author | wenzelm |
Sun, 06 Sep 2009 16:21:01 +0200 | |
changeset 34716 | b8f2b44529fd |
parent 34712 | 4f0ee5ab0380 |
child 34717 | 3f32e08bbb6c |
permissions | -rw-r--r-- |
34407 | 1 |
/* |
34408 | 2 |
* jEdit text area as document text source |
34407 | 3 |
* |
4 |
* @author Fabian Immler, TU Munich |
|
5 |
* @author Johannes Hölzl, TU Munich |
|
34447 | 6 |
* @author Makarius |
34407 | 7 |
*/ |
8 |
||
34318
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
9 |
package isabelle.jedit |
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
10 |
|
34703 | 11 |
import scala.actors.Actor, Actor._ |
34693 | 12 |
import scala.collection.mutable |
34446 | 13 |
|
34660 | 14 |
import isabelle.proofdocument.{ProofDocument, Change, Edit, Insert, Remove} |
34649 | 15 |
import isabelle.prover.{Prover, ProverEvents, Command} |
34318
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
16 |
|
34703 | 17 |
import java.awt.{Color, Graphics2D} |
34447 | 18 |
import javax.swing.event.{CaretListener, CaretEvent} |
34318
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
19 |
|
34446 | 20 |
import org.gjt.sp.jedit.buffer.{BufferListener, JEditBuffer} |
21 |
import org.gjt.sp.jedit.textarea.{JEditTextArea, TextAreaExtension, TextAreaPainter} |
|
34649 | 22 |
import org.gjt.sp.jedit.syntax.{ModeProvider, SyntaxStyle} |
34318
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
23 |
|
34446 | 24 |
|
34588 | 25 |
object TheoryView |
26 |
{ |
|
34716 | 27 |
def choose_color(command: Command, doc: ProofDocument): Color = |
28 |
{ |
|
29 |
command.status(doc) match { |
|
34653 | 30 |
case Command.Status.UNPROCESSED => new Color(255, 228, 225) |
31 |
case Command.Status.FINISHED => new Color(234, 248, 255) |
|
34716 | 32 |
case Command.Status.FAILED => new Color(255, 106, 106) |
34653 | 33 |
case _ => Color.red |
34 |
} |
|
34318
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
35 |
} |
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
36 |
} |
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
37 |
|
34446 | 38 |
|
34696 | 39 |
class TheoryView(text_area: JEditTextArea) |
40 |
extends TextAreaExtension with BufferListener |
|
34588 | 41 |
{ |
34541 | 42 |
|
34680 | 43 |
val buffer = text_area.getBuffer |
34672 | 44 |
|
45 |
// start prover |
|
34696 | 46 |
val prover: Prover = new Prover(Isabelle.system, Isabelle.default_logic(), change_receiver) |
34672 | 47 |
prover.start() // start actor |
34446 | 48 |
|
49 |
||
34680 | 50 |
/* activation */ |
34446 | 51 |
|
34566 | 52 |
private val phase_overview = new PhaseOverviewPanel(prover, text_area, to_current) |
34446 | 53 |
|
54 |
private val selected_state_controller = new CaretListener { |
|
55 |
override def caretUpdate(e: CaretEvent) = { |
|
34650 | 56 |
val doc = current_document() |
34712
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
57 |
doc.command_at(e.getDot) match { |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
58 |
case Some(cmd) |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
59 |
if (doc.token_start(cmd.tokens.first) <= e.getDot && |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
60 |
Isabelle.plugin.selected_state != cmd) => |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
61 |
Isabelle.plugin.selected_state = cmd |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
62 |
case _ => |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
63 |
} |
34318
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
64 |
} |
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
65 |
} |
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
66 |
|
34582 | 67 |
def activate() { |
34446 | 68 |
text_area.addCaretListener(selected_state_controller) |
69 |
text_area.addLeftOfScrollBar(phase_overview) |
|
70 |
text_area.getPainter.addExtension(TextAreaPainter.LINE_BACKGROUND_LAYER + 1, this) |
|
34538
20bfcca24658
Prover as actor managing ProofDocument-versions (removed EventBus structural_changes);
immler@in.tum.de
parents:
34532
diff
changeset
|
71 |
buffer.setTokenMarker(new DynamicTokenMarker(buffer, prover)) |
34649 | 72 |
buffer.addBufferListener(this) |
34671 | 73 |
|
74 |
val dockable = |
|
75 |
text_area.getView.getDockableWindowManager.getDockable("isabelle-output") |
|
76 |
if (dockable != null) { |
|
77 |
val output_dockable = dockable.asInstanceOf[OutputDockable] |
|
78 |
val output_text_view = prover.output_text_view |
|
79 |
output_dockable.set_text(output_text_view) |
|
80 |
} |
|
81 |
||
82 |
buffer.propertiesChanged() |
|
34446 | 83 |
} |
84 |
||
34582 | 85 |
def deactivate() { |
34649 | 86 |
buffer.setTokenMarker(buffer.getMode.getTokenMarker) |
87 |
buffer.removeBufferListener(this) |
|
34446 | 88 |
text_area.getPainter.removeExtension(this) |
89 |
text_area.removeLeftOfScrollBar(phase_overview) |
|
90 |
text_area.removeCaretListener(selected_state_controller) |
|
91 |
} |
|
92 |
||
93 |
||
34654 | 94 |
/* history of changes - TODO: seperate class?*/ |
95 |
||
34680 | 96 |
private val change_0 = new Change(prover.document_0.id, None, Nil) |
34694 | 97 |
private var _changes = List(change_0) // owned by Swing/AWT thread |
34680 | 98 |
def changes = _changes |
34654 | 99 |
private var current_change = change_0 |
34660 | 100 |
|
101 |
private def doc_or_pred(c: Change): ProofDocument = |
|
102 |
prover.document(c.id).getOrElse(doc_or_pred(c.parent.get)) |
|
34654 | 103 |
def current_document() = doc_or_pred(current_change) |
104 |
||
105 |
/* update to desired version */ |
|
106 |
||
34660 | 107 |
def set_version(goal: Change) { |
34654 | 108 |
// changes in buffer must be ignored |
109 |
buffer.removeBufferListener(this) |
|
110 |
||
34693 | 111 |
def apply(change: Change): Unit = change.edits.foreach { |
112 |
case Insert(start, text) => buffer.insert(start, text) |
|
113 |
case Remove(start, text) => buffer.remove(start, text.length) |
|
34660 | 114 |
} |
115 |
||
34693 | 116 |
def unapply(change: Change): Unit = change.edits.reverse.foreach { |
117 |
case Insert(start, text) => buffer.remove(start, text.length) |
|
118 |
case Remove(start, text) => buffer.insert(start, text) |
|
34660 | 119 |
} |
34318
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
120 |
|
34654 | 121 |
// undo/redo changes |
122 |
val ancs_current = current_change.ancestors |
|
123 |
val ancs_goal = goal.ancestors |
|
124 |
val paired = ancs_current.reverse zip ancs_goal.reverse |
|
125 |
def last_common[A](xs: List[(A, A)]): Option[A] = { |
|
126 |
xs match { |
|
127 |
case (x, y) :: xs => |
|
128 |
if (x == y) |
|
129 |
xs match { |
|
130 |
case (a, b) :: ys => |
|
131 |
if (a == b) last_common(xs) |
|
132 |
else Some(x) |
|
133 |
case _ => Some(x) |
|
134 |
} |
|
135 |
else None |
|
136 |
case _ => None |
|
137 |
} |
|
138 |
} |
|
139 |
val common_anc = last_common(paired).get |
|
140 |
||
141 |
ancs_current.takeWhile(_ != common_anc) map unapply |
|
142 |
ancs_goal.takeWhile(_ != common_anc).reverse map apply |
|
143 |
||
144 |
current_change = goal |
|
145 |
// invoke repaint |
|
34679 | 146 |
buffer.propertiesChanged() |
147 |
invalidate_all() |
|
148 |
phase_overview.repaint() |
|
34654 | 149 |
|
34703 | 150 |
// track changes in buffer |
34654 | 151 |
buffer.addBufferListener(this) |
152 |
} |
|
153 |
||
34693 | 154 |
|
34680 | 155 |
/* sending edits to prover */ |
156 |
||
34693 | 157 |
private val edits = new mutable.ListBuffer[Edit] // owned by Swing/AWT thread |
34680 | 158 |
|
34694 | 159 |
private val edits_delay = Swing_Thread.delay_last(300) { |
34660 | 160 |
if (!edits.isEmpty) { |
34693 | 161 |
val change = new Change(Isabelle.system.id(), Some(current_change), edits.toList) |
34680 | 162 |
_changes ::= change |
34672 | 163 |
prover ! change |
34660 | 164 |
current_change = change |
34693 | 165 |
edits.clear |
34545
b928628742ed
implemented to_current and from_current in dependancy of document-versions
immler@in.tum.de
parents:
34544
diff
changeset
|
166 |
} |
34318
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
167 |
} |
34446 | 168 |
|
34693 | 169 |
|
34680 | 170 |
/* BufferListener methods */ |
34446 | 171 |
|
172 |
override def preContentInserted(buffer: JEditBuffer, |
|
34588 | 173 |
start_line: Int, offset: Int, num_lines: Int, length: Int) |
34446 | 174 |
{ |
34693 | 175 |
edits += Insert(offset, buffer.getText(offset, length)) |
34694 | 176 |
edits_delay() |
34446 | 177 |
} |
178 |
||
179 |
override def preContentRemoved(buffer: JEditBuffer, |
|
34648 | 180 |
start_line: Int, start: Int, num_lines: Int, removed_length: Int) |
34446 | 181 |
{ |
34693 | 182 |
edits += Remove(start, buffer.getText(start, removed_length)) |
34694 | 183 |
edits_delay() |
34318
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
184 |
} |
c13e168a8ae6
original sources from Johannes Hölzl a48e0c6ab1aea77c52d596f7efc007a543d3d10c with minor modifications of directory layout;
wenzelm
parents:
diff
changeset
|
185 |
|
34695 | 186 |
override def contentInserted(buffer: JEditBuffer, |
187 |
start_line: Int, offset: Int, num_lines: Int, length: Int) { } |
|
188 |
||
189 |
override def contentRemoved(buffer: JEditBuffer, |
|
190 |
start_line: Int, offset: Int, num_lines: Int, length: Int) { } |
|
191 |
||
34446 | 192 |
override def bufferLoaded(buffer: JEditBuffer) { } |
193 |
override def foldHandlerChanged(buffer: JEditBuffer) { } |
|
194 |
override def foldLevelChanged(buffer: JEditBuffer, start_line: Int, end_line: Int) { } |
|
195 |
override def transactionComplete(buffer: JEditBuffer) { } |
|
34588 | 196 |
|
34680 | 197 |
|
198 |
/* transforming offsets */ |
|
199 |
||
34693 | 200 |
private def changes_to(doc: ProofDocument): List[Edit] = |
201 |
edits.toList ::: List.flatten(current_change.ancestors(_.id == doc.id).map(_.edits)) |
|
34680 | 202 |
|
34695 | 203 |
def from_current(doc: ProofDocument, offset: Int): Int = |
204 |
(offset /: changes_to(doc)) ((i, change) => change before i) |
|
34680 | 205 |
|
34695 | 206 |
def to_current(doc: ProofDocument, offset: Int): Int = |
207 |
(offset /: changes_to(doc).reverse) ((i, change) => change after i) |
|
34680 | 208 |
|
209 |
||
210 |
private def lines_of_command(cmd: Command) = |
|
211 |
{ |
|
212 |
val document = current_document() |
|
34681
74cc10b5ba51
fixed some issues with multiple active buffers
immler@in.tum.de
parents:
34680
diff
changeset
|
213 |
(buffer.getLineOfOffset(to_current(document, cmd.start(document))), |
74cc10b5ba51
fixed some issues with multiple active buffers
immler@in.tum.de
parents:
34680
diff
changeset
|
214 |
buffer.getLineOfOffset(to_current(document, cmd.stop(document)))) |
34680 | 215 |
} |
216 |
||
217 |
||
218 |
/* (re)painting */ |
|
219 |
||
34694 | 220 |
private val update_delay = Swing_Thread.delay_first(500) { buffer.propertiesChanged() } |
34680 | 221 |
|
222 |
private def update_syntax(cmd: Command) { |
|
223 |
val (line1, line2) = lines_of_command(cmd) |
|
224 |
if (line2 >= text_area.getFirstLine && |
|
225 |
line1 <= text_area.getFirstLine + text_area.getVisibleLines) |
|
226 |
update_delay() |
|
227 |
} |
|
228 |
||
229 |
private def invalidate_line(cmd: Command) = |
|
230 |
{ |
|
231 |
val (start, stop) = lines_of_command(cmd) |
|
232 |
text_area.invalidateLineRange(start, stop) |
|
233 |
||
234 |
if (Isabelle.plugin.selected_state == cmd) |
|
235 |
Isabelle.plugin.selected_state = cmd // update State view |
|
236 |
} |
|
237 |
||
238 |
private def invalidate_all() = |
|
239 |
text_area.invalidateLineRange(text_area.getFirstPhysicalLine, |
|
240 |
text_area.getLastPhysicalLine) |
|
241 |
||
242 |
private def encolor(gfx: Graphics2D, |
|
243 |
y: Int, height: Int, begin: Int, finish: Int, color: Color, fill: Boolean) |
|
244 |
{ |
|
245 |
val start = text_area.offsetToXY(begin) |
|
246 |
val stop = |
|
247 |
if (finish < buffer.getLength) text_area.offsetToXY(finish) |
|
248 |
else { |
|
249 |
val p = text_area.offsetToXY(finish - 1) |
|
250 |
val metrics = text_area.getPainter.getFontMetrics |
|
251 |
p.x = p.x + (metrics.charWidth(' ') max metrics.getMaxAdvance) |
|
252 |
p |
|
253 |
} |
|
254 |
||
255 |
if (start != null && stop != null) { |
|
256 |
gfx.setColor(color) |
|
257 |
if (fill) gfx.fillRect(start.x, y, stop.x - start.x, height) |
|
258 |
else gfx.drawRect(start.x, y, stop.x - start.x, height) |
|
259 |
} |
|
260 |
} |
|
261 |
||
34696 | 262 |
|
34680 | 263 |
/* TextAreaExtension methods */ |
264 |
||
265 |
override def paintValidLine(gfx: Graphics2D, |
|
266 |
screen_line: Int, physical_line: Int, start: Int, end: Int, y: Int) |
|
267 |
{ |
|
268 |
val document = current_document() |
|
269 |
def from_current(pos: Int) = this.from_current(document, pos) |
|
270 |
def to_current(pos: Int) = this.to_current(document, pos) |
|
271 |
val saved_color = gfx.getColor |
|
272 |
||
273 |
val metrics = text_area.getPainter.getFontMetrics |
|
274 |
||
275 |
// encolor phase |
|
34712
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
276 |
var cmd = document.command_at(from_current(start)) |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
277 |
while (cmd.isDefined && cmd.get.start(document) < end) { |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
278 |
val e = cmd.get |
34680 | 279 |
val begin = start max to_current(e.start(document)) |
34709 | 280 |
val finish = (end - 1) min to_current(e.stop(document)) |
34680 | 281 |
encolor(gfx, y, metrics.getHeight, begin, finish, |
282 |
TheoryView.choose_color(e, document), true) |
|
34712
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
283 |
cmd = document.commands.next(e) |
34680 | 284 |
} |
285 |
||
286 |
gfx.setColor(saved_color) |
|
287 |
} |
|
288 |
||
34696 | 289 |
override def getToolTipText(x: Int, y: Int): String = |
290 |
{ |
|
34680 | 291 |
val document = current_document() |
292 |
val offset = from_current(document, text_area.xyToOffset(x, y)) |
|
34712
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
293 |
document.command_at(offset) match { |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
294 |
case Some(cmd) => |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
295 |
document.token_start(cmd.tokens.first) |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
296 |
cmd.type_at(document, offset - cmd.start(document)) |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
297 |
case None => null |
4f0ee5ab0380
replaced find_command_at by command_at -- null-free, proper Option;
wenzelm
parents:
34709
diff
changeset
|
298 |
} |
34680 | 299 |
} |
300 |
||
301 |
||
302 |
/* receiving from prover */ |
|
303 |
||
304 |
lazy val change_receiver: Actor = actor { |
|
305 |
loop { |
|
306 |
react { |
|
34693 | 307 |
case ProverEvents.Activate => // FIXME !? |
308 |
Swing_Thread.now { |
|
309 |
edits.clear |
|
310 |
edits += Insert(0, buffer.getText(0, buffer.getLength)) |
|
34694 | 311 |
edits_delay() |
34693 | 312 |
} |
34680 | 313 |
case c: Command => |
34685
93f4978fe2a8
global event buses for changes concerning commands and document edits
immler@in.tum.de
parents:
34682
diff
changeset
|
314 |
actor{Isabelle.plugin.command_change.event(c)} |
34681
74cc10b5ba51
fixed some issues with multiple active buffers
immler@in.tum.de
parents:
34680
diff
changeset
|
315 |
if(current_document().commands.contains(c)) |
34680 | 316 |
Swing_Thread.later { |
34681
74cc10b5ba51
fixed some issues with multiple active buffers
immler@in.tum.de
parents:
34680
diff
changeset
|
317 |
// repaint if buffer is active |
74cc10b5ba51
fixed some issues with multiple active buffers
immler@in.tum.de
parents:
34680
diff
changeset
|
318 |
if(text_area.getBuffer == buffer) { |
74cc10b5ba51
fixed some issues with multiple active buffers
immler@in.tum.de
parents:
34680
diff
changeset
|
319 |
update_syntax(c) |
74cc10b5ba51
fixed some issues with multiple active buffers
immler@in.tum.de
parents:
34680
diff
changeset
|
320 |
invalidate_line(c) |
74cc10b5ba51
fixed some issues with multiple active buffers
immler@in.tum.de
parents:
34680
diff
changeset
|
321 |
phase_overview.repaint() |
74cc10b5ba51
fixed some issues with multiple active buffers
immler@in.tum.de
parents:
34680
diff
changeset
|
322 |
} |
34680 | 323 |
} |
34685
93f4978fe2a8
global event buses for changes concerning commands and document edits
immler@in.tum.de
parents:
34682
diff
changeset
|
324 |
case d: ProofDocument => |
93f4978fe2a8
global event buses for changes concerning commands and document edits
immler@in.tum.de
parents:
34682
diff
changeset
|
325 |
actor{Isabelle.plugin.document_change.event(d)} |
34680 | 326 |
case x => System.err.println("warning: change_receiver ignored " + x) |
327 |
} |
|
328 |
} |
|
329 |
} |
|
34447 | 330 |
} |