src/Tools/jEdit/src/jedit/document_model.scala
author wenzelm
Mon, 11 Jan 2010 18:26:13 +0100
changeset 34867 fd6801e87944
parent 34861 ad486bd8abf3
child 34874 e596a0b71f3c
permissions -rw-r--r--
simplified Text_Edit;
     1 /*
     2  * Document model connected to jEdit buffer
     3  *
     4  * @author Fabian Immler, TU Munich
     5  * @author Makarius
     6  */
     7 
     8 package isabelle.jedit
     9 
    10 
    11 import isabelle.proofdocument.{Change, Command, Document, Session}
    12 
    13 import scala.actors.Actor, Actor._
    14 import scala.collection.mutable
    15 
    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}
    19 
    20 
    21 object Document_Model
    22 {
    23   /* document model of buffer */
    24 
    25   private val key = "isabelle.document_model"
    26 
    27   def init(session: Session, buffer: Buffer): Document_Model =
    28   {
    29     Swing_Thread.assert()
    30     val model = new Document_Model(session, buffer)
    31     buffer.setProperty(key, model)
    32     model.activate()
    33     model
    34   }
    35 
    36   def apply(buffer: Buffer): Option[Document_Model] =
    37   {
    38     Swing_Thread.assert()
    39     buffer.getProperty(key) match {
    40       case model: Document_Model => Some(model)
    41       case _ => None
    42     }
    43   }
    44 
    45   def exit(buffer: Buffer)
    46   {
    47     Swing_Thread.assert()
    48     apply(buffer) match {
    49       case None => error("No document model for buffer: " + buffer)
    50       case Some(model) =>
    51         model.deactivate()
    52         buffer.unsetProperty(key)
    53     }
    54   }
    55 }
    56 
    57 class Document_Model(val session: Session, val buffer: Buffer)
    58 {
    59   /* history */
    60 
    61   private val document_0 = session.begin_document(buffer.getName)
    62 
    63   @volatile private var history =  // owned by Swing thread
    64     new Change(document_0.id, None, Nil, Future.value(Nil, document_0))
    65 
    66   def current_change(): Change = history
    67   def recent_document(): Document = current_change().ancestors.find(_.is_assigned).get.join_document
    68 
    69 
    70   /* transforming offsets */
    71 
    72   private def changes_from(doc: Document): List[Text_Edit] =
    73   {
    74     Swing_Thread.assert()
    75     (edits_buffer.toList /:
    76       current_change.ancestors.takeWhile(_.id != doc.id))((edits, change) => change.edits ::: edits)
    77   }
    78 
    79   def from_current(doc: Document, offset: Int): Int =
    80     (offset /: changes_from(doc).reverse) ((i, change) => change before i)
    81 
    82   def to_current(doc: Document, offset: Int): Int =
    83     (offset /: changes_from(doc)) ((i, change) => change after i)
    84 
    85   def lines_of_command(doc: Document, cmd: Command): (Int, Int) =
    86   {
    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)))
    91   }
    92 
    93 
    94   /* text edits */
    95 
    96   private val edits_buffer = new mutable.ListBuffer[Text_Edit]   // owned by Swing thread
    97 
    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)
   101       edits_buffer.clear
   102       history = new_change
   103       new_change.result.map(_ => session.input(new_change))
   104     }
   105   }
   106 
   107 
   108   /* buffer listener */
   109 
   110   private val buffer_listener: BufferListener = new BufferAdapter
   111   {
   112     override def contentInserted(buffer: JEditBuffer,
   113       start_line: Int, offset: Int, num_lines: Int, length: Int)
   114     {
   115       edits_buffer += new Text_Edit(true, offset, buffer.getText(offset, length))
   116       edits_delay()
   117     }
   118 
   119     override def preContentRemoved(buffer: JEditBuffer,
   120       start_line: Int, start: Int, num_lines: Int, removed_length: Int)
   121     {
   122       edits_buffer += new Text_Edit(false, start, buffer.getText(start, removed_length))
   123       edits_delay()
   124     }
   125   }
   126 
   127 
   128   /* activation */
   129 
   130   def activate()
   131   {
   132     buffer.setTokenMarker(new Isabelle_Token_Marker(this))
   133     buffer.addBufferListener(buffer_listener)
   134     buffer.propertiesChanged()
   135 
   136     edits_buffer += new Text_Edit(true, 0, buffer.getText(0, buffer.getLength))
   137     edits_delay()
   138   }
   139 
   140   def deactivate()
   141   {
   142     buffer.setTokenMarker(buffer.getMode.getTokenMarker)
   143     buffer.removeBufferListener(buffer_listener)
   144   }
   145 }