2 * Document model connected to jEdit buffer
4 * @author Fabian Immler, TU Munich
11 import isabelle.proofdocument.{Change, Command, Document, Session}
13 import scala.actors.Actor, Actor._
14 import scala.collection.mutable
16 import org.gjt.sp.jedit.Buffer
17 import org.gjt.sp.jedit.buffer.{BufferAdapter, BufferListener, JEditBuffer}
18 import org.gjt.sp.jedit.syntax.{ModeProvider, SyntaxStyle}
23 /* document model of buffer */
25 private val key = "isabelle.document_model"
27 def init(session: Session, buffer: Buffer): Document_Model =
30 val model = new Document_Model(session, buffer)
31 buffer.setProperty(key, model)
36 def apply(buffer: Buffer): Option[Document_Model] =
39 buffer.getProperty(key) match {
40 case model: Document_Model => Some(model)
45 def exit(buffer: Buffer)
49 case None => error("No document model for buffer: " + buffer)
52 buffer.unsetProperty(key)
57 class Document_Model(val session: Session, val buffer: Buffer)
61 private val document_0 = session.begin_document(buffer.getName)
63 @volatile private var history = // owned by Swing thread
64 new Change(document_0.id, None, Nil, Future.value(Nil, document_0))
66 def current_change(): Change = history
67 def recent_document(): Document = current_change().ancestors.find(_.is_assigned).get.join_document
70 /* transforming offsets */
72 private def changes_from(doc: Document): List[Text_Edit] =
75 (edits_buffer.toList /:
76 current_change.ancestors.takeWhile(_.id != doc.id))((edits, change) => change.edits ::: edits)
79 def from_current(doc: Document, offset: Int): Int =
80 (offset /: changes_from(doc).reverse) ((i, change) => change before i)
82 def to_current(doc: Document, offset: Int): Int =
83 (offset /: changes_from(doc)) ((i, change) => change after i)
85 def lines_of_command(doc: Document, cmd: Command): (Int, Int) =
87 val start = doc.command_start(cmd).get // FIXME total?
88 val stop = start + cmd.length
89 (buffer.getLineOfOffset(to_current(doc, start)),
90 buffer.getLineOfOffset(to_current(doc, stop)))
96 private val edits_buffer = new mutable.ListBuffer[Text_Edit] // owned by Swing thread
98 private val edits_delay = Swing_Thread.delay_last(300) {
99 if (!edits_buffer.isEmpty) {
100 val new_change = current_change().edit(session, edits_buffer.toList)
103 new_change.result.map(_ => session.input(new_change))
108 /* buffer listener */
110 private val buffer_listener: BufferListener = new BufferAdapter
112 override def contentInserted(buffer: JEditBuffer,
113 start_line: Int, offset: Int, num_lines: Int, length: Int)
115 edits_buffer += new Text_Edit(true, offset, buffer.getText(offset, length))
119 override def preContentRemoved(buffer: JEditBuffer,
120 start_line: Int, start: Int, num_lines: Int, removed_length: Int)
122 edits_buffer += new Text_Edit(false, start, buffer.getText(start, removed_length))
132 buffer.setTokenMarker(new Isabelle_Token_Marker(this))
133 buffer.addBufferListener(buffer_listener)
134 buffer.propertiesChanged()
136 edits_buffer += new Text_Edit(true, 0, buffer.getText(0, buffer.getLength))
142 buffer.setTokenMarker(buffer.getMode.getTokenMarker)
143 buffer.removeBufferListener(buffer_listener)