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( |
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) { |
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 || |