src/Tools/jEdit/src/jedit_lib.scala
changeset 75393 87ebf5a50283
parent 73987 fc363a3b690a
child 75696 c79df6dc2803
equal deleted inserted replaced
75388:b3ca4a6ed74b 75393:87ebf5a50283
    22 import org.gjt.sp.jedit.gui.{KeyEventWorkaround, KeyEventTranslator}
    22 import org.gjt.sp.jedit.gui.{KeyEventWorkaround, KeyEventTranslator}
    23 import org.gjt.sp.jedit.buffer.{JEditBuffer, LineManager}
    23 import org.gjt.sp.jedit.buffer.{JEditBuffer, LineManager}
    24 import org.gjt.sp.jedit.textarea.{JEditTextArea, TextArea, TextAreaPainter}
    24 import org.gjt.sp.jedit.textarea.{JEditTextArea, TextArea, TextAreaPainter}
    25 
    25 
    26 
    26 
    27 object JEdit_Lib
    27 object JEdit_Lib {
    28 {
       
    29   /* jEdit directories */
    28   /* jEdit directories */
    30 
    29 
    31   def directories: List[JFile] =
    30   def directories: List[JFile] =
    32     (Option(jEdit.getSettingsDirectory).toList ::: List(jEdit.getJEditHome)).map(new JFile(_))
    31     (Option(jEdit.getSettingsDirectory).toList ::: List(jEdit.getJEditHome)).map(new JFile(_))
    33 
    32 
    34 
    33 
    35   /* window geometry measurement */
    34   /* window geometry measurement */
    36 
    35 
    37   private lazy val dummy_window = new JWindow
    36   private lazy val dummy_window = new JWindow
    38 
    37 
    39   final case class Window_Geometry(width: Int, height: Int, inner_width: Int, inner_height: Int)
    38   final case class Window_Geometry(width: Int, height: Int, inner_width: Int, inner_height: Int) {
    40   {
       
    41     def deco_width: Int = width - inner_width
    39     def deco_width: Int = width - inner_width
    42     def deco_height: Int = height - inner_height
    40     def deco_height: Int = height - inner_height
    43   }
    41   }
    44 
    42 
    45   def window_geometry(outer: Container, inner: Component): Window_Geometry =
    43   def window_geometry(outer: Container, inner: Component): Window_Geometry = {
    46   {
       
    47     GUI_Thread.require {}
    44     GUI_Thread.require {}
    48 
    45 
    49     val old_content = dummy_window.getContentPane
    46     val old_content = dummy_window.getContentPane
    50 
    47 
    51     dummy_window.setContentPane(outer)
    48     dummy_window.setContentPane(outer)
    77     buffer_lock(buffer) { buffer.getText(0, buffer.getLength) }
    74     buffer_lock(buffer) { buffer.getText(0, buffer.getLength) }
    78 
    75 
    79   def buffer_reader(buffer: JEditBuffer): CharSequenceReader =
    76   def buffer_reader(buffer: JEditBuffer): CharSequenceReader =
    80     Scan.char_reader(buffer.getSegment(0, buffer.getLength))
    77     Scan.char_reader(buffer.getSegment(0, buffer.getLength))
    81 
    78 
    82   def buffer_mode(buffer: JEditBuffer): String =
    79   def buffer_mode(buffer: JEditBuffer): String = {
    83   {
       
    84     val mode = buffer.getMode
    80     val mode = buffer.getMode
    85     if (mode == null) ""
    81     if (mode == null) ""
    86     else {
    82     else {
    87       val name = mode.getName
    83       val name = mode.getName
    88       if (name == null) "" else name
    84       if (name == null) "" else name
    94 
    90 
    95   def buffer_name(buffer: Buffer): String = buffer.getSymlinkPath
    91   def buffer_name(buffer: Buffer): String = buffer.getSymlinkPath
    96 
    92 
    97   def buffer_file(buffer: Buffer): Option[JFile] = check_file(buffer_name(buffer))
    93   def buffer_file(buffer: Buffer): Option[JFile] = check_file(buffer_name(buffer))
    98 
    94 
    99   def buffer_undo_in_progress[A](buffer: JEditBuffer, body: => A): A =
    95   def buffer_undo_in_progress[A](buffer: JEditBuffer, body: => A): A = {
   100   {
       
   101     val undo_in_progress = buffer.isUndoInProgress
    96     val undo_in_progress = buffer.isUndoInProgress
   102     def set(b: Boolean): Unit = Untyped.set[Boolean](buffer, "undoInProgress", b)
    97     def set(b: Boolean): Unit = Untyped.set[Boolean](buffer, "undoInProgress", b)
   103     try { set(true); body } finally { set(undo_in_progress) }
    98     try { set(true); body } finally { set(undo_in_progress) }
   104   }
    99   }
   105 
   100 
   133     jedit_views().flatMap(jedit_text_areas)
   128     jedit_views().flatMap(jedit_text_areas)
   134 
   129 
   135   def jedit_text_areas(buffer: JEditBuffer): Iterator[JEditTextArea] =
   130   def jedit_text_areas(buffer: JEditBuffer): Iterator[JEditTextArea] =
   136     jedit_text_areas().filter(_.getBuffer == buffer)
   131     jedit_text_areas().filter(_.getBuffer == buffer)
   137 
   132 
   138   def buffer_lock[A](buffer: JEditBuffer)(body: => A): A =
   133   def buffer_lock[A](buffer: JEditBuffer)(body: => A): A = {
   139   {
       
   140     try { buffer.readLock(); body }
   134     try { buffer.readLock(); body }
   141     finally { buffer.readUnlock() }
   135     finally { buffer.readUnlock() }
   142   }
   136   }
   143 
   137 
   144   def buffer_edit[A](buffer: JEditBuffer)(body: => A): A =
   138   def buffer_edit[A](buffer: JEditBuffer)(body: => A): A = {
   145   {
       
   146     try { buffer.beginCompoundEdit(); body }
   139     try { buffer.beginCompoundEdit(); body }
   147     finally { buffer.endCompoundEdit() }
   140     finally { buffer.endCompoundEdit() }
   148   }
   141   }
   149 
   142 
   150 
   143 
   184     Text.Range(buffer.getLineStartOffset(line), buffer.getLineEndOffset(line) min buffer.getLength)
   177     Text.Range(buffer.getLineStartOffset(line), buffer.getLineEndOffset(line) min buffer.getLength)
   185 
   178 
   186   def caret_range(text_area: TextArea): Text.Range =
   179   def caret_range(text_area: TextArea): Text.Range =
   187     point_range(text_area.getBuffer, text_area.getCaretPosition)
   180     point_range(text_area.getBuffer, text_area.getCaretPosition)
   188 
   181 
   189   def visible_range(text_area: TextArea): Option[Text.Range] =
   182   def visible_range(text_area: TextArea): Option[Text.Range] = {
   190   {
       
   191     val buffer = text_area.getBuffer
   183     val buffer = text_area.getBuffer
   192     val n = text_area.getVisibleLines
   184     val n = text_area.getVisibleLines
   193     if (n > 0) {
   185     if (n > 0) {
   194       val start = text_area.getScreenLineStartOffset(0)
   186       val start = text_area.getScreenLineStartOffset(0)
   195       val raw_end = text_area.getScreenLineEndOffset(n - 1)
   187       val raw_end = text_area.getScreenLineEndOffset(n - 1)
   197       Some(Text.Range(start, end))
   189       Some(Text.Range(start, end))
   198     }
   190     }
   199     else None
   191     else None
   200   }
   192   }
   201 
   193 
   202   def invalidate_range(text_area: TextArea, range: Text.Range): Unit =
   194   def invalidate_range(text_area: TextArea, range: Text.Range): Unit = {
   203   {
       
   204     val buffer = text_area.getBuffer
   195     val buffer = text_area.getBuffer
   205     buffer_range(buffer).try_restrict(range) match {
   196     buffer_range(buffer).try_restrict(range) match {
   206       case Some(range1) if !range1.is_singularity =>
   197       case Some(range1) if !range1.is_singularity =>
   207         try {
   198         try {
   208           text_area.invalidateLineRange(
   199           text_area.invalidateLineRange(
   212         catch { case _: ArrayIndexOutOfBoundsException => }
   203         catch { case _: ArrayIndexOutOfBoundsException => }
   213       case _ =>
   204       case _ =>
   214     }
   205     }
   215   }
   206   }
   216 
   207 
   217   def invalidate(text_area: TextArea): Unit =
   208   def invalidate(text_area: TextArea): Unit = {
   218   {
       
   219     val visible_lines = text_area.getVisibleLines
   209     val visible_lines = text_area.getVisibleLines
   220     if (visible_lines > 0) text_area.invalidateScreenLineRange(0, visible_lines)
   210     if (visible_lines > 0) text_area.invalidateScreenLineRange(0, visible_lines)
   221   }
   211   }
   222 
   212 
   223 
   213 
   225 
   215 
   226   case class Gfx_Range(x: Int, y: Int, length: Int)
   216   case class Gfx_Range(x: Int, y: Int, length: Int)
   227 
   217 
   228   // NB: jEdit always normalizes \r\n and \r to \n
   218   // NB: jEdit always normalizes \r\n and \r to \n
   229   // NB: last line lacks \n
   219   // NB: last line lacks \n
   230   def gfx_range(text_area: TextArea, range: Text.Range): Option[Gfx_Range] =
   220   def gfx_range(text_area: TextArea, range: Text.Range): Option[Gfx_Range] = {
   231   {
       
   232     val metric = pretty_metric(text_area.getPainter)
   221     val metric = pretty_metric(text_area.getPainter)
   233     val char_width = (metric.unit * metric.average).round.toInt
   222     val char_width = (metric.unit * metric.average).round.toInt
   234 
   223 
   235     val buffer = text_area.getBuffer
   224     val buffer = text_area.getBuffer
   236 
   225 
   256   }
   245   }
   257 
   246 
   258 
   247 
   259   /* pixel range */
   248   /* pixel range */
   260 
   249 
   261   def pixel_range(text_area: TextArea, x: Int, y: Int): Option[Text.Range] =
   250   def pixel_range(text_area: TextArea, x: Int, y: Int): Option[Text.Range] = {
   262   {
       
   263     // coordinates wrt. inner painter component
   251     // coordinates wrt. inner painter component
   264     val painter = text_area.getPainter
   252     val painter = text_area.getPainter
   265     if (0 <= x && x < painter.getWidth && 0 <= y && y < painter.getHeight) {
   253     if (0 <= x && x < painter.getWidth && 0 <= y && y < painter.getHeight) {
   266       val offset = text_area.xyToOffset(x, y, false)
   254       val offset = text_area.xyToOffset(x, y, false)
   267       if (offset >= 0) {
   255       if (offset >= 0) {
   277   }
   265   }
   278 
   266 
   279 
   267 
   280   /* pretty text metric */
   268   /* pretty text metric */
   281 
   269 
   282   abstract class Pretty_Metric extends Pretty.Metric
   270   abstract class Pretty_Metric extends Pretty.Metric {
   283   {
       
   284     def average: Double
   271     def average: Double
   285   }
   272   }
   286 
   273 
   287   def pretty_metric(painter: TextAreaPainter): Pretty_Metric =
   274   def pretty_metric(painter: TextAreaPainter): Pretty_Metric =
   288     new Pretty_Metric {
   275     new Pretty_Metric {
   295     }
   282     }
   296 
   283 
   297 
   284 
   298   /* icons */
   285   /* icons */
   299 
   286 
   300   def load_icon(name: String): Icon =
   287   def load_icon(name: String): Icon = {
   301   {
       
   302     val name1 =
   288     val name1 =
   303       if (name.startsWith("idea-icons/")) {
   289       if (name.startsWith("idea-icons/")) {
   304         val file = Path.explode("$ISABELLE_IDEA_ICONS").file.toURI.toASCIIString
   290         val file = Path.explode("$ISABELLE_IDEA_ICONS").file.toURI.toASCIIString
   305         "jar:" + file + "!/" + name
   291         "jar:" + file + "!/" + name
   306       }
   292       }
   317     }
   303     }
   318 
   304 
   319 
   305 
   320   /* key event handling */
   306   /* key event handling */
   321 
   307 
   322   def request_focus_view(alt_view: View = null): Unit =
   308   def request_focus_view(alt_view: View = null): Unit = {
   323   {
       
   324     val view = if (alt_view != null) alt_view else jEdit.getActiveView()
   309     val view = if (alt_view != null) alt_view else jEdit.getActiveView()
   325     if (view != null) {
   310     if (view != null) {
   326       val text_area = view.getTextArea
   311       val text_area = view.getTextArea
   327       if (text_area != null) text_area.requestFocus()
   312       if (text_area != null) text_area.requestFocus()
   328     }
   313     }
   329   }
   314   }
   330 
   315 
   331   def propagate_key(view: View, evt: KeyEvent): Unit =
   316   def propagate_key(view: View, evt: KeyEvent): Unit = {
   332   {
       
   333     if (view != null && !evt.isConsumed)
   317     if (view != null && !evt.isConsumed)
   334       view.getInputHandler().processKeyEvent(evt, View.ACTION_BAR, false)
   318       view.getInputHandler().processKeyEvent(evt, View.ACTION_BAR, false)
   335   }
   319   }
   336 
   320 
   337   def key_listener(
   321   def key_listener(
   338     key_typed: KeyEvent => Unit = _ => (),
   322     key_typed: KeyEvent => Unit = _ => (),
   339     key_pressed: KeyEvent => Unit = _ => (),
   323     key_pressed: KeyEvent => Unit = _ => (),
   340     key_released: KeyEvent => Unit = _ => ()): KeyListener =
   324     key_released: KeyEvent => Unit = _ => ()
   341   {
   325   ): KeyListener = {
   342     def process_key_event(evt0: KeyEvent, handle: KeyEvent => Unit): Unit =
   326     def process_key_event(evt0: KeyEvent, handle: KeyEvent => Unit): Unit = {
   343     {
       
   344       val evt = KeyEventWorkaround.processKeyEvent(evt0)
   327       val evt = KeyEventWorkaround.processKeyEvent(evt0)
   345       if (evt != null) handle(evt)
   328       if (evt != null) handle(evt)
   346     }
   329     }
   347 
   330 
   348     new KeyListener
   331     new KeyListener {
   349     {
       
   350       def keyTyped(evt: KeyEvent): Unit = process_key_event(evt, key_typed)
   332       def keyTyped(evt: KeyEvent): Unit = process_key_event(evt, key_typed)
   351       def keyPressed(evt: KeyEvent): Unit = process_key_event(evt, key_pressed)
   333       def keyPressed(evt: KeyEvent): Unit = process_key_event(evt, key_pressed)
   352       def keyReleased(evt: KeyEvent): Unit = process_key_event(evt, key_released)
   334       def keyReleased(evt: KeyEvent): Unit = process_key_event(evt, key_released)
   353     }
   335     }
   354   }
   336   }
   355 
   337 
   356   def special_key(evt: KeyEvent): Boolean =
   338   def special_key(evt: KeyEvent): Boolean = {
   357   {
       
   358     // cf. 5.2.0/jEdit/org/gjt/sp/jedit/gui/KeyEventWorkaround.java
   339     // cf. 5.2.0/jEdit/org/gjt/sp/jedit/gui/KeyEventWorkaround.java
   359     val mod = evt.getModifiersEx
   340     val mod = evt.getModifiersEx
   360     (mod & InputEvent.CTRL_DOWN_MASK) != 0 && (mod & InputEvent.ALT_DOWN_MASK) == 0 ||
   341     (mod & InputEvent.CTRL_DOWN_MASK) != 0 && (mod & InputEvent.ALT_DOWN_MASK) == 0 ||
   361     (mod & InputEvent.CTRL_DOWN_MASK) == 0 && (mod & InputEvent.ALT_DOWN_MASK) != 0 &&
   342     (mod & InputEvent.CTRL_DOWN_MASK) == 0 && (mod & InputEvent.ALT_DOWN_MASK) != 0 &&
   362       !Debug.ALT_KEY_PRESSED_DISABLED ||
   343       !Debug.ALT_KEY_PRESSED_DISABLED ||