--- a/src/Tools/jEdit/src/jedit/BrowseVersionDockable.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Dockable window for navigating through the document-versions
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-import isabelle.proofdocument.Change
-
-import java.awt.Dimension
-import scala.swing.{ListView, FlowPanel}
-import scala.swing.event.ListSelectionChanged
-
-import org.gjt.sp.jedit.View
-import org.gjt.sp.jedit.gui.DockableWindowManager
-
-
-class BrowseVersionDockable(view: View, position: String) extends FlowPanel
-{
- if (position == DockableWindowManager.FLOATING)
- preferredSize = new Dimension(500, 250)
-
- def prover_setup(): Option[ProverSetup] = Isabelle.prover_setup(view.getBuffer)
- def get_versions() =
- prover_setup() match {
- case None => Nil
- case Some(setup) => setup.theory_view.changes
- }
-
- val list = new ListView[Change]
- list.fixedCellWidth = 500
- list.listData = get_versions()
- contents += list
-
- listenTo(list.selection)
- reactions += {
- case ListSelectionChanged(source, range, false) =>
- prover_setup().map(_.theory_view.set_version(list.listData(range.start)))
- }
-
- prover_setup.foreach(_.prover.document_change += (_ => list.listData = get_versions()))
-}
--- a/src/Tools/jEdit/src/jedit/Document_Overview.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Information on command status left of scrollbar (with panel)
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-import isabelle.prover.{Prover, Command}
-import isabelle.proofdocument.ProofDocument
-
-import javax.swing.{JPanel, ToolTipManager}
-import java.awt.event.{MouseAdapter, MouseEvent}
-import java.awt.{BorderLayout, Graphics, Dimension}
-
-import org.gjt.sp.jedit.gui.RolloverButton
-import org.gjt.sp.jedit.textarea.JEditTextArea
-import org.gjt.sp.jedit.buffer.JEditBuffer
-
-
-class Document_Overview(
- prover: Prover,
- text_area: JEditTextArea,
- to_current: (ProofDocument, Int) => Int)
- extends JPanel(new BorderLayout)
-{
- private val WIDTH = 10
- private val HEIGHT = 2
-
- setRequestFocusEnabled(false)
-
- addMouseListener(new MouseAdapter {
- override def mousePressed(event: MouseEvent) {
- val line = y_to_line(event.getY)
- if (line >= 0 && line < text_area.getLineCount)
- text_area.setCaretPosition(text_area.getLineStartOffset(line))
- }
- })
-
- override def addNotify() {
- super.addNotify()
- ToolTipManager.sharedInstance.registerComponent(this)
- }
-
- override def removeNotify() {
- super.removeNotify
- ToolTipManager.sharedInstance.unregisterComponent(this)
- }
-
- override def getToolTipText(event: MouseEvent): String =
- {
- val buffer = text_area.getBuffer
- val lineCount = buffer.getLineCount
- val line = y_to_line(event.getY())
- if (line >= 0 && line < text_area.getLineCount) "<html><b>TODO:</b><br>Tooltip</html>"
- else ""
- }
-
- override def paintComponent(gfx: Graphics) {
- super.paintComponent(gfx)
- val buffer = text_area.getBuffer
- val theory_view = Isabelle.prover_setup(buffer).get.theory_view
- val doc = theory_view.current_document()
-
- for (command <- doc.commands) {
- val line1 = buffer.getLineOfOffset(to_current(doc, command.start(doc)))
- val line2 = buffer.getLineOfOffset(to_current(doc, command.stop(doc))) + 1
- val y = line_to_y(line1)
- val height = HEIGHT * (line2 - line1)
- gfx.setColor(TheoryView.choose_color(command, doc))
- gfx.fillRect(0, y, getWidth - 1, height)
- }
- }
-
- override def getPreferredSize = new Dimension(WIDTH, 0)
-
- private def line_to_y(line: Int): Int =
- (line * getHeight) / (text_area.getBuffer.getLineCount max text_area.getVisibleLines)
-
- private def y_to_line(y: Int): Int =
- (y * (text_area.getBuffer.getLineCount max text_area.getVisibleLines)) / getHeight
-}
\ No newline at end of file
--- a/src/Tools/jEdit/src/jedit/DynamicTokenMarker.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/*
- * include isabelle's command- and keyword-declarations
- * live in jEdits syntax-highlighting
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-
-import isabelle.prover.Prover
-import isabelle.Markup
-
-import org.gjt.sp.jedit.buffer.JEditBuffer
-import org.gjt.sp.jedit.syntax.{Token => JToken,
- TokenMarker, TokenHandler, SyntaxStyle, ParserRuleSet}
-
-import java.awt.Color
-import java.awt.Font
-import javax.swing.text.Segment;
-
-
-object DynamicTokenMarker
-{
- /* line context */
-
- private val rule_set = new ParserRuleSet("isabelle", "MAIN")
- private class LineContext(val line: Int, prev: LineContext)
- extends TokenMarker.LineContext(rule_set, prev)
-
-
- /* mapping to jEdit token types */
- // TODO: as properties or CSS style sheet
-
- private val choose_byte: Map[String, Byte] =
- {
- import JToken._
- Map[String, Byte](
- // logical entities
- Markup.TCLASS -> LABEL,
- Markup.TYCON -> LABEL,
- Markup.FIXED_DECL -> LABEL,
- Markup.FIXED -> LABEL,
- Markup.CONST_DECL -> LABEL,
- Markup.CONST -> LABEL,
- Markup.FACT_DECL -> LABEL,
- Markup.FACT -> LABEL,
- Markup.DYNAMIC_FACT -> LABEL,
- Markup.LOCAL_FACT_DECL -> LABEL,
- Markup.LOCAL_FACT -> LABEL,
- // inner syntax
- Markup.TFREE -> LITERAL2,
- Markup.FREE -> LITERAL2,
- Markup.TVAR -> LITERAL3,
- Markup.SKOLEM -> LITERAL3,
- Markup.BOUND -> LITERAL3,
- Markup.VAR -> LITERAL3,
- Markup.NUM -> DIGIT,
- Markup.FLOAT -> DIGIT,
- Markup.XNUM -> DIGIT,
- Markup.XSTR -> LITERAL4,
- Markup.LITERAL -> LITERAL4,
- Markup.INNER_COMMENT -> COMMENT1,
- Markup.SORT -> FUNCTION,
- Markup.TYP -> FUNCTION,
- Markup.TERM -> FUNCTION,
- Markup.PROP -> FUNCTION,
- Markup.ATTRIBUTE -> FUNCTION,
- Markup.METHOD -> FUNCTION,
- // ML syntax
- Markup.ML_KEYWORD -> KEYWORD2,
- Markup.ML_IDENT -> NULL,
- Markup.ML_TVAR -> LITERAL3,
- Markup.ML_NUMERAL -> DIGIT,
- Markup.ML_CHAR -> LITERAL1,
- Markup.ML_STRING -> LITERAL1,
- Markup.ML_COMMENT -> COMMENT1,
- Markup.ML_MALFORMED -> INVALID,
- // embedded source text
- Markup.ML_SOURCE -> COMMENT4,
- Markup.DOC_SOURCE -> COMMENT4,
- Markup.ANTIQ -> COMMENT4,
- Markup.ML_ANTIQ -> COMMENT4,
- Markup.DOC_ANTIQ -> COMMENT4,
- // outer syntax
- Markup.IDENT -> NULL,
- Markup.COMMAND -> OPERATOR,
- Markup.KEYWORD -> KEYWORD4,
- Markup.VERBATIM -> COMMENT3,
- Markup.COMMENT -> COMMENT1,
- Markup.CONTROL -> COMMENT3,
- Markup.MALFORMED -> INVALID,
- Markup.STRING -> LITERAL3,
- Markup.ALTSTRING -> LITERAL1
- ).withDefaultValue(NULL)
- }
-
- def choose_color(kind: String, styles: Array[SyntaxStyle]): Color =
- styles(choose_byte(kind)).getForegroundColor
-}
-
-
-class DynamicTokenMarker(buffer: JEditBuffer, prover: Prover)
- extends TokenMarker
-{
- override def markTokens(prev: TokenMarker.LineContext,
- handler: TokenHandler, line_segment: Segment): TokenMarker.LineContext =
- {
- val previous = prev.asInstanceOf[DynamicTokenMarker.LineContext]
- val line = if (prev == null) 0 else previous.line + 1
- val context = new DynamicTokenMarker.LineContext(line, previous)
- val start = buffer.getLineStartOffset(line)
- val stop = start + line_segment.count
-
- val theory_view = Isabelle.prover_setup(buffer).get.theory_view
- val document = theory_view.current_document()
- def to: Int => Int = theory_view.to_current(document, _)
- def from: Int => Int = theory_view.from_current(document, _)
-
- var next_x = start
- var cmd = document.command_at(from(start))
- while (cmd.isDefined && cmd.get.start(document) < from(stop)) {
- val command = cmd.get
- for {
- markup <- command.highlight(document).flatten
- command_start = command.start(document)
- abs_start = to(command_start + markup.start)
- abs_stop = to(command_start + markup.stop)
- if (abs_stop > start)
- if (abs_start < stop)
- byte = DynamicTokenMarker.choose_byte(markup.info.toString)
- token_start = (abs_start - start) max 0
- token_length =
- (abs_stop - abs_start) -
- ((start - abs_start) max 0) -
- ((abs_stop - stop) max 0)
- } {
- if (start + token_start > next_x)
- handler.handleToken(line_segment, 1,
- next_x - start, start + token_start - next_x, context)
- handler.handleToken(line_segment, byte,
- token_start, token_length, context)
- next_x = start + token_start + token_length
- }
- cmd = document.commands.next(command)
- }
- if (next_x < stop)
- handler.handleToken(line_segment, 1, next_x - start, stop - next_x, context)
-
- handler.handleToken(line_segment, JToken.END, line_segment.count, 0, context)
- handler.setLineContext(context)
- return context
- }
-}
--- a/src/Tools/jEdit/src/jedit/IsabelleHyperlinkSource.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Hyperlink setup for Isabelle proof documents
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-import java.io.File
-
-import gatchan.jedit.hyperlinks.Hyperlink
-import gatchan.jedit.hyperlinks.HyperlinkSource
-import gatchan.jedit.hyperlinks.AbstractHyperlink
-
-import org.gjt.sp.jedit.View
-import org.gjt.sp.jedit.jEdit
-import org.gjt.sp.jedit.Buffer
-import org.gjt.sp.jedit.TextUtilities
-
-import isabelle.prover.Command
-
-
-class InternalHyperlink(start: Int, end: Int, line: Int, ref_offset: Int)
- extends AbstractHyperlink(start, end, line, "")
-{
- override def click(view: View) {
- view.getTextArea.moveCaretPosition(ref_offset)
- }
-}
-
-class ExternalHyperlink(start: Int, end: Int, line: Int, ref_file: String, ref_line: Int)
- extends AbstractHyperlink(start, end, line, "")
-{
- override def click(view: View) = {
- Isabelle.system.source_file(ref_file) match {
- case None => System.err.println("Could not find source file " + ref_file)
- case Some(file) =>
- jEdit.openFiles(view, file.getParent, Array(file.getName, "+line:" + ref_line))
- }
- }
-}
-
-class IsabelleHyperlinkSource extends HyperlinkSource
-{
- def getHyperlink(buffer: Buffer, original_offset: Int): Hyperlink = {
- val prover = Isabelle.prover_setup(buffer).map(_.prover)
- val theory_view_opt = Isabelle.prover_setup(buffer).map(_.theory_view)
- if (prover.isEmpty || theory_view_opt.isEmpty) null
- else if (prover.get == null || theory_view_opt.get == null) null
- else {
- val theory_view = theory_view_opt.get
- val document = theory_view.current_document()
- val offset = theory_view.from_current(document, original_offset)
- document.command_at(offset) match {
- case Some(command) =>
- command.ref_at(document, offset - command.start(document)) match {
- case Some(ref) =>
- val command_start = command.start(document)
- val begin = theory_view.to_current(document, command_start + ref.start)
- val line = buffer.getLineOfOffset(begin)
- val end = theory_view.to_current(document, command_start + ref.stop)
- ref.info match {
- case Command.RefInfo(Some(ref_file), Some(ref_line), _, _) =>
- new ExternalHyperlink(begin, end, line, ref_file, ref_line)
- case Command.RefInfo(_, _, Some(id), Some(offset)) =>
- prover.get.command(id) match {
- case Some(ref_cmd) =>
- new InternalHyperlink(begin, end, line,
- theory_view.to_current(document, ref_cmd.start(document) + offset - 1))
- case None => null
- }
- case _ => null
- }
- case None => null
- }
- case None => null
- }
- }
- }
-}
--- a/src/Tools/jEdit/src/jedit/IsabelleSideKickParser.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * SideKick parser for Isabelle proof documents
- *
- * @author Fabian Immler, TU Munich
- * @author Makarius
- */
-
-package isabelle.jedit
-
-import scala.collection.Set
-import scala.collection.immutable.TreeSet
-
-import javax.swing.tree.DefaultMutableTreeNode
-import javax.swing.text.Position
-import javax.swing.Icon
-
-import org.gjt.sp.jedit.{Buffer, EditPane, TextUtilities, View}
-import errorlist.DefaultErrorSource
-import sidekick.{SideKickParser, SideKickParsedData, SideKickCompletion, IAsset}
-
-import isabelle.prover.{Command, Markup_Node}
-import isabelle.proofdocument.ProofDocument
-
-
-class IsabelleSideKickParser extends SideKickParser("isabelle")
-{
- /* parsing */
-
- @volatile private var stopped = false
- override def stop() = { stopped = true }
-
- def parse(buffer: Buffer, error_source: DefaultErrorSource): SideKickParsedData =
- {
- implicit def int_to_pos(offset: Int): Position =
- new Position { def getOffset = offset; override def toString = offset.toString }
-
- stopped = false
-
- val data = new SideKickParsedData(buffer.getName)
- val root = data.root
- data.getAsset(root).setEnd(buffer.getLength)
-
- val prover_setup = Isabelle.prover_setup(buffer)
- if (prover_setup.isDefined) {
- val document = prover_setup.get.theory_view.current_document()
- for (command <- document.commands if !stopped) {
- root.add(command.markup_root(document).swing_tree((node: Markup_Node) =>
- {
- val content = command.content(node.start, node.stop)
- val command_start = command.start(document)
- val id = command.id
-
- new DefaultMutableTreeNode(new IAsset {
- override def getIcon: Icon = null
- override def getShortString: String = content
- override def getLongString: String = node.info.toString
- override def getName: String = id
- override def setName(name: String) = ()
- override def setStart(start: Position) = ()
- override def getStart: Position = command_start + node.start
- override def setEnd(end: Position) = ()
- override def getEnd: Position = command_start + node.stop
- override def toString = id + ": " + content + "[" + getStart + " - " + getEnd + "]"
- })
- }))
- }
- if (stopped) root.add(new DefaultMutableTreeNode("<parser stopped>"))
- }
- else root.add(new DefaultMutableTreeNode("<buffer inactive>"))
-
- data
- }
-
-
- /* completion */
-
- override def supportsCompletion = true
- override def canCompleteAnywhere = true
-
- override def complete(pane: EditPane, caret: Int): SideKickCompletion =
- {
- val buffer = pane.getBuffer
-
- val line = buffer.getLineOfOffset(caret)
- val start = buffer.getLineStartOffset(line)
- val text = buffer.getSegment(start, caret - start)
-
- val completion =
- Isabelle.prover_setup(buffer).map(_.prover.completion()).getOrElse(Isabelle.completion)
-
- completion.complete(text) match {
- case None => null
- case Some((word, cs)) =>
- val ds =
- if (Isabelle_Encoding.is_active(buffer))
- cs.map(Isabelle.system.symbols.decode(_)).sort(Completion.length_ord _)
- else cs
- new SideKickCompletion(pane.getView, word, ds.toArray.asInstanceOf[Array[Object]]) { }
- }
- }
-
-}
--- a/src/Tools/jEdit/src/jedit/Isabelle_Encoding.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Isabelle encoding -- based on utf-8
- *
- * @author Makarius
- */
-
-package isabelle.jedit
-
-import org.gjt.sp.jedit.io.Encoding
-import org.gjt.sp.jedit.buffer.JEditBuffer
-
-import java.nio.charset.{Charset, CharsetDecoder, CodingErrorAction}
-import java.io.{InputStream, OutputStream, Reader, Writer, InputStreamReader, OutputStreamWriter,
- CharArrayReader, ByteArrayOutputStream}
-
-import scala.io.{Source, BufferedSource}
-
-
-object Isabelle_Encoding
-{
- val NAME = "UTF-8-Isabelle"
-
- def is_active(buffer: JEditBuffer): Boolean =
- buffer.getProperty(JEditBuffer.ENCODING).asInstanceOf[String] == NAME
-}
-
-class Isabelle_Encoding extends Encoding
-{
- private val charset = Charset.forName(Isabelle_System.charset)
- private val BUFSIZE = 32768
-
- private def text_reader(in: InputStream, decoder: CharsetDecoder): Reader =
- {
- def source(): Source =
- BufferedSource.fromInputStream(in, decoder, BUFSIZE, { () => source() })
- new CharArrayReader(Isabelle.symbols.decode(source.mkString).toArray)
- }
-
- override def getTextReader(in: InputStream): Reader =
- text_reader(in, charset.newDecoder())
-
- override def getPermissiveTextReader(in: InputStream): Reader =
- {
- val decoder = charset.newDecoder()
- decoder.onMalformedInput(CodingErrorAction.REPLACE)
- decoder.onUnmappableCharacter(CodingErrorAction.REPLACE)
- text_reader(in, decoder)
- }
-
- override def getTextWriter(out: OutputStream): Writer =
- {
- val buffer = new ByteArrayOutputStream(BUFSIZE) {
- override def flush()
- {
- val text = Isabelle.symbols.encode(toString(Isabelle_System.charset))
- out.write(text.getBytes(Isabelle_System.charset))
- out.flush()
- }
- override def close() { out.close() }
- }
- new OutputStreamWriter(buffer, charset.newEncoder())
- }
-}
--- a/src/Tools/jEdit/src/jedit/OptionPane.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Editor pane for plugin options
- *
- * @author Johannes Hölzl, TU Munich
- */
-
-package isabelle.jedit
-
-import javax.swing.{JComboBox, JSpinner}
-
-import org.gjt.sp.jedit.AbstractOptionPane
-
-
-class OptionPane extends AbstractOptionPane("isabelle")
-{
- private val logic_name = new JComboBox()
- private val font_size = new JSpinner()
-
- override def _init()
- {
- addComponent(Isabelle.Property("logic.title"), {
- for (name <- Isabelle.system.find_logics()) {
- logic_name.addItem(name)
- if (name == Isabelle.Property("logic"))
- logic_name.setSelectedItem(name)
- }
- logic_name
- })
- addComponent(Isabelle.Property("font-size.title"), {
- font_size.setValue(Isabelle.Int_Property("font-size"))
- font_size
- })
- }
-
- override def _save()
- {
- val logic = logic_name.getSelectedItem.asInstanceOf[String]
- Isabelle.Property("logic") = logic
-
- val size = font_size.getValue().asInstanceOf[Int]
- Isabelle.Int_Property("font-size") = size
- }
-}
--- a/src/Tools/jEdit/src/jedit/OutputDockable.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*
- * Dockable window for raw process output
- *
- * @author Fabian Immler, TU Munich
- * @author Johannes Hölzl, TU Munich
- */
-
-package isabelle.jedit
-
-
-import java.awt.{Dimension, Graphics, GridLayout}
-import javax.swing.{JPanel, JTextArea, JScrollPane}
-
-import org.gjt.sp.jedit.View
-import org.gjt.sp.jedit.gui.DockableWindowManager
-
-
-class OutputDockable(view : View, position : String) extends JPanel {
-
- if (position == DockableWindowManager.FLOATING)
- setPreferredSize(new Dimension(500, 250))
-
- setLayout(new GridLayout(1, 1))
- add(new JScrollPane(new JTextArea))
-
- def set_text(output_text_view: JTextArea) {
- removeAll()
- add(new JScrollPane(output_text_view))
- revalidate()
- }
-}
--- a/src/Tools/jEdit/src/jedit/Plugin.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
- * Main Isabelle/jEdit plugin setup
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-
-import java.io.{FileInputStream, IOException}
-import java.awt.Font
-import javax.swing.JScrollPane
-
-import scala.collection.mutable
-
-import isabelle.prover.{Prover, Command}
-import isabelle.proofdocument.ProofDocument
-import isabelle.Isabelle_System
-
-import org.gjt.sp.jedit.{jEdit, EBMessage, EBPlugin, Buffer, EditPane, ServiceManager, View}
-import org.gjt.sp.jedit.buffer.JEditBuffer
-import org.gjt.sp.jedit.textarea.JEditTextArea
-import org.gjt.sp.jedit.msg.{EditPaneUpdate, PropertiesChanged}
-
-
-object Isabelle
-{
- /* name */
-
- val NAME = "Isabelle"
-
-
- /* properties */
-
- val OPTION_PREFIX = "options.isabelle."
-
- object Property
- {
- def apply(name: String): String = jEdit.getProperty(OPTION_PREFIX + name)
- def update(name: String, value: String) = jEdit.setProperty(OPTION_PREFIX + name, value)
- }
-
- object Boolean_Property
- {
- def apply(name: String): Boolean = jEdit.getBooleanProperty(OPTION_PREFIX + name)
- def update(name: String, value: Boolean) = jEdit.setBooleanProperty(OPTION_PREFIX + name, value)
- }
-
- object Int_Property
- {
- def apply(name: String): Int = jEdit.getIntegerProperty(OPTION_PREFIX + name)
- def update(name: String, value: Int) = jEdit.setIntegerProperty(OPTION_PREFIX + name, value)
- }
-
-
- /* Isabelle system instance */
-
- var system: Isabelle_System = null
- def symbols = system.symbols
- lazy val completion = new Completion + symbols
-
-
- /* settings */
-
- def default_logic(): String =
- {
- val logic = Isabelle.Property("logic")
- if (logic != null) logic
- else system.getenv_strict("ISABELLE_LOGIC")
- }
-
-
- /* plugin instance */
-
- var plugin: Plugin = null
-
-
- /* running provers */
-
- def prover_setup(buffer: JEditBuffer) = plugin.prover_setup(buffer)
-}
-
-
-class Plugin extends EBPlugin
-{
- /* event buses */
-
- val state_update = new Event_Bus[Command]
-
-
- /* selected state */
-
- private var _selected_state: Command = null
- def selected_state = _selected_state
- def selected_state_=(state: Command) { _selected_state = state; state_update.event(state) }
-
-
- /* mapping buffer <-> prover */
-
- private val mapping = new mutable.HashMap[JEditBuffer, ProverSetup]
-
- private def install(view: View)
- {
- val buffer = view.getBuffer
- val prover_setup = new ProverSetup(buffer)
- mapping.update(buffer, prover_setup)
- prover_setup.activate(view)
- }
-
- private def uninstall(view: View) =
- mapping.removeKey(view.getBuffer).get.deactivate
-
- def switch_active (view: View) =
- if (mapping.isDefinedAt(view.getBuffer)) uninstall(view)
- else install(view)
-
- def prover_setup(buffer: JEditBuffer): Option[ProverSetup] = mapping.get(buffer)
- def is_active (buffer: JEditBuffer) = mapping.isDefinedAt(buffer)
-
-
- /* main plugin plumbing */
-
- override def handleMessage(msg: EBMessage)
- {
- msg match {
- case epu: EditPaneUpdate =>
- val buffer = epu.getEditPane.getBuffer
- epu.getWhat match {
- case EditPaneUpdate.BUFFER_CHANGED =>
- (mapping get buffer) map (_.theory_view.activate)
- case EditPaneUpdate.BUFFER_CHANGING =>
- if (buffer != null)
- (mapping get buffer) map (_.theory_view.deactivate)
- case _ =>
- }
- case _ =>
- }
- }
-
- override def start()
- {
- Isabelle.plugin = this
- Isabelle.system = new Isabelle_System
- if (!Isabelle.system.register_fonts())
- System.err.println("Failed to register Isabelle fonts")
- }
-
- override def stop()
- {
- // TODO: proper cleanup
- Isabelle.system = null
- Isabelle.plugin = null
- }
-}
--- a/src/Tools/jEdit/src/jedit/ProverSetup.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Independent prover sessions for each buffer
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.jedit
-
-
-import org.gjt.sp.jedit.{Buffer, View}
-
-import isabelle.prover.Prover
-
-
-class ProverSetup(buffer: Buffer)
-{
- var prover: Prover = null
- var theory_view: TheoryView = null
-
- def activate(view: View)
- {
- // TheoryView starts prover
- theory_view = new TheoryView(view.getTextArea)
- prover = theory_view.prover
-
- theory_view.activate()
- prover.begin_document(buffer.getName)
- }
-
- def deactivate()
- {
- theory_view.deactivate
- prover.stop
- }
-}
--- a/src/Tools/jEdit/src/jedit/StateViewDockable.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/*
- * Dockable window with rendered state output
- *
- * @author Fabian Immler, TU Munich
- * @author Johannes Hölzl, TU Munich
- */
-
-package isabelle.jedit
-
-import isabelle.XML
-
-import java.io.StringReader
-import java.awt.{BorderLayout, Dimension}
-
-import javax.swing.{JButton, JPanel, JScrollPane}
-
-import java.util.logging.{Logger, Level}
-
-import org.lobobrowser.html.parser._
-import org.lobobrowser.html.test._
-import org.lobobrowser.html.gui._
-import org.lobobrowser.html._
-import org.lobobrowser.html.style.CSSUtilities
-import org.lobobrowser.html.domimpl.{HTMLDocumentImpl, HTMLStyleElementImpl, NodeImpl}
-
-import org.gjt.sp.jedit.jEdit
-import org.gjt.sp.jedit.View
-import org.gjt.sp.jedit.gui.DockableWindowManager
-import org.gjt.sp.jedit.textarea.AntiAlias
-
-import scala.io.Source
-
-
-class StateViewDockable(view : View, position : String) extends JPanel {
-
- // outer panel
- if (position == DockableWindowManager.FLOATING)
- setPreferredSize(new Dimension(500, 250))
- setLayout(new BorderLayout)
-
-
- // global logging
-
- Logger.getLogger("org.lobobrowser").setLevel(Level.WARNING)
-
-
- // document template with styles
-
- private def try_file(name: String): String =
- {
- val file = Isabelle.system.platform_file(name)
- if (file.exists) Source.fromFile(file).mkString else ""
- }
-
-
- // HTML panel
-
- val panel = new HtmlPanel
- val ucontext = new SimpleUserAgentContext
- val rcontext = new SimpleHtmlRendererContext(panel, ucontext)
- val doc = {
- val builder = new DocumentBuilderImpl(ucontext, rcontext)
- builder.parse(new InputSourceImpl(new StringReader(
- """<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<style media="all" type="text/css">
-""" +
- try_file("$ISABELLE_HOME/lib/html/isabelle.css") + "\n" +
-"""
-body {
- font-family: IsabelleText;
- font-size: 14pt;
-}
-""" +
- try_file("$ISABELLE_HOME_USER/etc/isabelle.css") + "\n" +
-"""
-</style>
-</head>
-</html>
-""")))
- }
-
- val empty_body = XML.document_node(doc, XML.elem(HTML.BODY))
- doc.appendChild(empty_body)
-
- panel.setDocument(doc, rcontext)
- add(panel, BorderLayout.CENTER)
-
-
- // register for state-view
- Isabelle.plugin.state_update += (cmd => {
- val theory_view = Isabelle.prover_setup(view.getBuffer).get.theory_view
-
- Swing_Thread.later {
- val node =
- if (cmd == null) empty_body
- else {
- val xml = XML.elem(HTML.BODY,
- cmd.results(theory_view.current_document).
- map((t: XML.Tree) => XML.elem(HTML.PRE, HTML.spans(t))))
- XML.document_node(doc, xml)
- }
- doc.removeChild(doc.getLastChild())
- doc.appendChild(node)
- panel.delayedRelayout(node.asInstanceOf[NodeImpl])
- }
- })
-}
--- a/src/Tools/jEdit/src/jedit/TheoryView.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,327 +0,0 @@
-/*
- * jEdit text area as document text source
- *
- * @author Fabian Immler, TU Munich
- * @author Johannes Hölzl, TU Munich
- * @author Makarius
- */
-
-package isabelle.jedit
-
-import scala.actors.Actor, Actor._
-import scala.collection.mutable
-
-import isabelle.proofdocument.{ProofDocument, Change, Edit, Insert, Remove}
-import isabelle.prover.{Prover, Command}
-
-import java.awt.{Color, Graphics2D}
-import javax.swing.event.{CaretListener, CaretEvent}
-
-import org.gjt.sp.jedit.buffer.{BufferListener, JEditBuffer}
-import org.gjt.sp.jedit.textarea.{JEditTextArea, TextAreaExtension, TextAreaPainter}
-import org.gjt.sp.jedit.syntax.{ModeProvider, SyntaxStyle}
-
-
-object TheoryView
-{
- def choose_color(command: Command, doc: ProofDocument): Color =
- {
- command.status(doc) match {
- case Command.Status.UNPROCESSED => new Color(255, 228, 225)
- case Command.Status.FINISHED => new Color(234, 248, 255)
- case Command.Status.FAILED => new Color(255, 106, 106)
- case _ => Color.red
- }
- }
-}
-
-
-class TheoryView(text_area: JEditTextArea)
-{
- private val buffer = text_area.getBuffer
-
-
- /* prover setup */
-
- val prover: Prover = new Prover(Isabelle.system, Isabelle.default_logic())
-
- prover.command_change += ((command: Command) =>
- if (current_document().commands.contains(command))
- Swing_Thread.later {
- // FIXME proper handling of buffer vs. text areas
- // repaint if buffer is active
- if (text_area.getBuffer == buffer) {
- update_syntax(command)
- invalidate_line(command)
- overview.repaint()
- }
- })
-
-
- /* changes vs. edits */
-
- private val change_0 = new Change(prover.document_0.id, None, Nil)
- private var _changes = List(change_0) // owned by Swing/AWT thread
- def changes = _changes
- private var current_change = change_0
-
- private val edits = new mutable.ListBuffer[Edit] // owned by Swing thread
-
- private val edits_delay = Swing_Thread.delay_last(300) {
- if (!edits.isEmpty) {
- val change = new Change(Isabelle.system.id(), Some(current_change), edits.toList)
- _changes ::= change
- prover.input(change)
- current_change = change
- edits.clear
- }
- }
-
-
- /* buffer_listener */
-
- private val buffer_listener = new BufferListener {
- override def preContentInserted(buffer: JEditBuffer,
- start_line: Int, offset: Int, num_lines: Int, length: Int)
- {
- edits += Insert(offset, buffer.getText(offset, length))
- edits_delay()
- }
-
- override def preContentRemoved(buffer: JEditBuffer,
- start_line: Int, start: Int, num_lines: Int, removed_length: Int)
- {
- edits += Remove(start, buffer.getText(start, removed_length))
- edits_delay()
- }
-
- override def contentInserted(buffer: JEditBuffer,
- start_line: Int, offset: Int, num_lines: Int, length: Int) { }
-
- override def contentRemoved(buffer: JEditBuffer,
- start_line: Int, offset: Int, num_lines: Int, length: Int) { }
-
- override def bufferLoaded(buffer: JEditBuffer) { }
- override def foldHandlerChanged(buffer: JEditBuffer) { }
- override def foldLevelChanged(buffer: JEditBuffer, start_line: Int, end_line: Int) { }
- override def transactionComplete(buffer: JEditBuffer) { }
- }
-
-
- /* text_area_extension */
-
- private val text_area_extension = new TextAreaExtension {
- override def paintValidLine(gfx: Graphics2D,
- screen_line: Int, physical_line: Int, start: Int, end: Int, y: Int)
- {
- val document = current_document()
- def from_current(pos: Int) = TheoryView.this.from_current(document, pos)
- def to_current(pos: Int) = TheoryView.this.to_current(document, pos)
- val saved_color = gfx.getColor
-
- val metrics = text_area.getPainter.getFontMetrics
-
- // encolor phase
- var cmd = document.command_at(from_current(start))
- while (cmd.isDefined && cmd.get.start(document) < end) {
- val e = cmd.get
- val begin = start max to_current(e.start(document))
- val finish = (end - 1) min to_current(e.stop(document))
- encolor(gfx, y, metrics.getHeight, begin, finish,
- TheoryView.choose_color(e, document), true)
- cmd = document.commands.next(e)
- }
-
- gfx.setColor(saved_color)
- }
-
- override def getToolTipText(x: Int, y: Int): String =
- {
- val document = current_document()
- val offset = from_current(document, text_area.xyToOffset(x, y))
- document.command_at(offset) match {
- case Some(cmd) =>
- document.token_start(cmd.tokens.first)
- cmd.type_at(document, offset - cmd.start(document)).getOrElse(null)
- case None => null
- }
- }
- }
-
-
- /* activation */
-
- private val overview = new Document_Overview(prover, text_area, to_current)
-
- private val selected_state_controller = new CaretListener {
- override def caretUpdate(e: CaretEvent) {
- val doc = current_document()
- doc.command_at(e.getDot) match {
- case Some(cmd)
- if (doc.token_start(cmd.tokens.first) <= e.getDot &&
- Isabelle.plugin.selected_state != cmd) =>
- Isabelle.plugin.selected_state = cmd
- case _ =>
- }
- }
- }
-
- def activate() {
- text_area.addCaretListener(selected_state_controller)
- text_area.addLeftOfScrollBar(overview)
- text_area.getPainter.
- addExtension(TextAreaPainter.LINE_BACKGROUND_LAYER + 1, text_area_extension)
- buffer.setTokenMarker(new DynamicTokenMarker(buffer, prover))
- buffer.addBufferListener(buffer_listener)
-
- val dockable =
- text_area.getView.getDockableWindowManager.getDockable("isabelle-output")
- if (dockable != null) {
- val output_dockable = dockable.asInstanceOf[OutputDockable]
- val output_text_view = prover.output_text_view
- output_dockable.set_text(output_text_view)
- }
-
- buffer.propertiesChanged()
- }
-
- def deactivate() {
- buffer.setTokenMarker(buffer.getMode.getTokenMarker)
- buffer.removeBufferListener(buffer_listener)
- text_area.getPainter.removeExtension(text_area_extension)
- text_area.removeLeftOfScrollBar(overview)
- text_area.removeCaretListener(selected_state_controller)
- }
-
-
- /* history of changes */
-
- private def doc_or_pred(c: Change): ProofDocument =
- prover.document(c.id).getOrElse(doc_or_pred(c.parent.get))
-
- def current_document() = doc_or_pred(current_change)
-
-
- /* update to desired version */
-
- def set_version(goal: Change) {
- // changes in buffer must be ignored
- buffer.removeBufferListener(buffer_listener)
-
- def apply(change: Change): Unit = change.edits.foreach {
- case Insert(start, text) => buffer.insert(start, text)
- case Remove(start, text) => buffer.remove(start, text.length)
- }
-
- def unapply(change: Change): Unit = change.edits.reverse.foreach {
- case Insert(start, text) => buffer.remove(start, text.length)
- case Remove(start, text) => buffer.insert(start, text)
- }
-
- // undo/redo changes
- val ancs_current = current_change.ancestors
- val ancs_goal = goal.ancestors
- val paired = ancs_current.reverse zip ancs_goal.reverse
- def last_common[A](xs: List[(A, A)]): Option[A] = {
- xs match {
- case (x, y) :: xs =>
- if (x == y)
- xs match {
- case (a, b) :: ys =>
- if (a == b) last_common(xs)
- else Some(x)
- case _ => Some(x)
- }
- else None
- case _ => None
- }
- }
- val common_anc = last_common(paired).get
-
- ancs_current.takeWhile(_ != common_anc) map unapply
- ancs_goal.takeWhile(_ != common_anc).reverse map apply
-
- current_change = goal
- // invoke repaint
- buffer.propertiesChanged()
- invalidate_all()
- overview.repaint()
-
- // track changes in buffer
- buffer.addBufferListener(buffer_listener)
- }
-
-
- /* transforming offsets */
-
- private def changes_from(doc: ProofDocument): List[Edit] =
- List.flatten(current_change.ancestors(_.id == doc.id).reverse.map(_.edits)) :::
- edits.toList
-
- def from_current(doc: ProofDocument, offset: Int): Int =
- (offset /: changes_from(doc).reverse) ((i, change) => change before i)
-
- def to_current(doc: ProofDocument, offset: Int): Int =
- (offset /: changes_from(doc)) ((i, change) => change after i)
-
-
- private def lines_of_command(cmd: Command) =
- {
- val document = current_document()
- (buffer.getLineOfOffset(to_current(document, cmd.start(document))),
- buffer.getLineOfOffset(to_current(document, cmd.stop(document))))
- }
-
-
- /* (re)painting */
-
- private val update_delay = Swing_Thread.delay_first(500) { buffer.propertiesChanged() }
-
- private def update_syntax(cmd: Command) {
- val (line1, line2) = lines_of_command(cmd)
- if (line2 >= text_area.getFirstLine &&
- line1 <= text_area.getFirstLine + text_area.getVisibleLines)
- update_delay()
- }
-
- private def invalidate_line(cmd: Command) =
- {
- val (start, stop) = lines_of_command(cmd)
- text_area.invalidateLineRange(start, stop)
-
- if (Isabelle.plugin.selected_state == cmd)
- Isabelle.plugin.selected_state = cmd // update State view
- }
-
- private def invalidate_all() =
- text_area.invalidateLineRange(text_area.getFirstPhysicalLine,
- text_area.getLastPhysicalLine)
-
- private def encolor(gfx: Graphics2D,
- y: Int, height: Int, begin: Int, finish: Int, color: Color, fill: Boolean)
- {
- val start = text_area.offsetToXY(begin)
- val stop =
- if (finish < buffer.getLength) text_area.offsetToXY(finish)
- else {
- val p = text_area.offsetToXY(finish - 1)
- val metrics = text_area.getPainter.getFontMetrics
- p.x = p.x + (metrics.charWidth(' ') max metrics.getMaxAdvance)
- p
- }
-
- if (start != null && stop != null) {
- gfx.setColor(color)
- if (fill) gfx.fillRect(start.x, y, stop.x - start.x, height)
- else gfx.drawRect(start.x, y, stop.x - start.x, height)
- }
- }
-
-
- /* init */
-
- prover.start()
-
- edits += Insert(0, buffer.getText(0, buffer.getLength))
- edits_delay()
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/browse_version_dockable.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,43 @@
+/*
+ * Dockable window for navigating through the document-versions
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+import isabelle.proofdocument.Change
+
+import java.awt.Dimension
+import scala.swing.{ListView, FlowPanel}
+import scala.swing.event.ListSelectionChanged
+
+import org.gjt.sp.jedit.View
+import org.gjt.sp.jedit.gui.DockableWindowManager
+
+
+class BrowseVersionDockable(view: View, position: String) extends FlowPanel
+{
+ if (position == DockableWindowManager.FLOATING)
+ preferredSize = new Dimension(500, 250)
+
+ def prover_setup(): Option[ProverSetup] = Isabelle.prover_setup(view.getBuffer)
+ def get_versions() =
+ prover_setup() match {
+ case None => Nil
+ case Some(setup) => setup.theory_view.changes
+ }
+
+ val list = new ListView[Change]
+ list.fixedCellWidth = 500
+ list.listData = get_versions()
+ contents += list
+
+ listenTo(list.selection)
+ reactions += {
+ case ListSelectionChanged(source, range, false) =>
+ prover_setup().map(_.theory_view.set_version(list.listData(range.start)))
+ }
+
+ prover_setup.foreach(_.prover.document_change += (_ => list.listData = get_versions()))
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/document_overview.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,82 @@
+/*
+ * Information on command status left of scrollbar (with panel)
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+import isabelle.prover.{Prover, Command}
+import isabelle.proofdocument.ProofDocument
+
+import javax.swing.{JPanel, ToolTipManager}
+import java.awt.event.{MouseAdapter, MouseEvent}
+import java.awt.{BorderLayout, Graphics, Dimension}
+
+import org.gjt.sp.jedit.gui.RolloverButton
+import org.gjt.sp.jedit.textarea.JEditTextArea
+import org.gjt.sp.jedit.buffer.JEditBuffer
+
+
+class Document_Overview(
+ prover: Prover,
+ text_area: JEditTextArea,
+ to_current: (ProofDocument, Int) => Int)
+ extends JPanel(new BorderLayout)
+{
+ private val WIDTH = 10
+ private val HEIGHT = 2
+
+ setRequestFocusEnabled(false)
+
+ addMouseListener(new MouseAdapter {
+ override def mousePressed(event: MouseEvent) {
+ val line = y_to_line(event.getY)
+ if (line >= 0 && line < text_area.getLineCount)
+ text_area.setCaretPosition(text_area.getLineStartOffset(line))
+ }
+ })
+
+ override def addNotify() {
+ super.addNotify()
+ ToolTipManager.sharedInstance.registerComponent(this)
+ }
+
+ override def removeNotify() {
+ super.removeNotify
+ ToolTipManager.sharedInstance.unregisterComponent(this)
+ }
+
+ override def getToolTipText(event: MouseEvent): String =
+ {
+ val buffer = text_area.getBuffer
+ val lineCount = buffer.getLineCount
+ val line = y_to_line(event.getY())
+ if (line >= 0 && line < text_area.getLineCount) "<html><b>TODO:</b><br>Tooltip</html>"
+ else ""
+ }
+
+ override def paintComponent(gfx: Graphics) {
+ super.paintComponent(gfx)
+ val buffer = text_area.getBuffer
+ val theory_view = Isabelle.prover_setup(buffer).get.theory_view
+ val doc = theory_view.current_document()
+
+ for (command <- doc.commands) {
+ val line1 = buffer.getLineOfOffset(to_current(doc, command.start(doc)))
+ val line2 = buffer.getLineOfOffset(to_current(doc, command.stop(doc))) + 1
+ val y = line_to_y(line1)
+ val height = HEIGHT * (line2 - line1)
+ gfx.setColor(TheoryView.choose_color(command, doc))
+ gfx.fillRect(0, y, getWidth - 1, height)
+ }
+ }
+
+ override def getPreferredSize = new Dimension(WIDTH, 0)
+
+ private def line_to_y(line: Int): Int =
+ (line * getHeight) / (text_area.getBuffer.getLineCount max text_area.getVisibleLines)
+
+ private def y_to_line(y: Int): Int =
+ (y * (text_area.getBuffer.getLineCount max text_area.getVisibleLines)) / getHeight
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/isabelle_encoding.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,63 @@
+/*
+ * Isabelle encoding -- based on utf-8
+ *
+ * @author Makarius
+ */
+
+package isabelle.jedit
+
+import org.gjt.sp.jedit.io.Encoding
+import org.gjt.sp.jedit.buffer.JEditBuffer
+
+import java.nio.charset.{Charset, CharsetDecoder, CodingErrorAction}
+import java.io.{InputStream, OutputStream, Reader, Writer, InputStreamReader, OutputStreamWriter,
+ CharArrayReader, ByteArrayOutputStream}
+
+import scala.io.{Source, BufferedSource}
+
+
+object Isabelle_Encoding
+{
+ val NAME = "UTF-8-Isabelle"
+
+ def is_active(buffer: JEditBuffer): Boolean =
+ buffer.getProperty(JEditBuffer.ENCODING).asInstanceOf[String] == NAME
+}
+
+class Isabelle_Encoding extends Encoding
+{
+ private val charset = Charset.forName(Isabelle_System.charset)
+ private val BUFSIZE = 32768
+
+ private def text_reader(in: InputStream, decoder: CharsetDecoder): Reader =
+ {
+ def source(): Source =
+ BufferedSource.fromInputStream(in, decoder, BUFSIZE, { () => source() })
+ new CharArrayReader(Isabelle.symbols.decode(source.mkString).toArray)
+ }
+
+ override def getTextReader(in: InputStream): Reader =
+ text_reader(in, charset.newDecoder())
+
+ override def getPermissiveTextReader(in: InputStream): Reader =
+ {
+ val decoder = charset.newDecoder()
+ decoder.onMalformedInput(CodingErrorAction.REPLACE)
+ decoder.onUnmappableCharacter(CodingErrorAction.REPLACE)
+ text_reader(in, decoder)
+ }
+
+ override def getTextWriter(out: OutputStream): Writer =
+ {
+ val buffer = new ByteArrayOutputStream(BUFSIZE) {
+ override def flush()
+ {
+ val text = Isabelle.symbols.encode(toString(Isabelle_System.charset))
+ out.write(text.getBytes(Isabelle_System.charset))
+ out.flush()
+ }
+ override def close() { out.close() }
+ }
+ new OutputStreamWriter(buffer, charset.newEncoder())
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/isabelle_hyperlinks.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,80 @@
+/*
+ * Hyperlink setup for Isabelle proof documents
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+import java.io.File
+
+import gatchan.jedit.hyperlinks.Hyperlink
+import gatchan.jedit.hyperlinks.HyperlinkSource
+import gatchan.jedit.hyperlinks.AbstractHyperlink
+
+import org.gjt.sp.jedit.View
+import org.gjt.sp.jedit.jEdit
+import org.gjt.sp.jedit.Buffer
+import org.gjt.sp.jedit.TextUtilities
+
+import isabelle.prover.Command
+
+
+class InternalHyperlink(start: Int, end: Int, line: Int, ref_offset: Int)
+ extends AbstractHyperlink(start, end, line, "")
+{
+ override def click(view: View) {
+ view.getTextArea.moveCaretPosition(ref_offset)
+ }
+}
+
+class ExternalHyperlink(start: Int, end: Int, line: Int, ref_file: String, ref_line: Int)
+ extends AbstractHyperlink(start, end, line, "")
+{
+ override def click(view: View) = {
+ Isabelle.system.source_file(ref_file) match {
+ case None => System.err.println("Could not find source file " + ref_file)
+ case Some(file) =>
+ jEdit.openFiles(view, file.getParent, Array(file.getName, "+line:" + ref_line))
+ }
+ }
+}
+
+class IsabelleHyperlinkSource extends HyperlinkSource
+{
+ def getHyperlink(buffer: Buffer, original_offset: Int): Hyperlink = {
+ val prover = Isabelle.prover_setup(buffer).map(_.prover)
+ val theory_view_opt = Isabelle.prover_setup(buffer).map(_.theory_view)
+ if (prover.isEmpty || theory_view_opt.isEmpty) null
+ else if (prover.get == null || theory_view_opt.get == null) null
+ else {
+ val theory_view = theory_view_opt.get
+ val document = theory_view.current_document()
+ val offset = theory_view.from_current(document, original_offset)
+ document.command_at(offset) match {
+ case Some(command) =>
+ command.ref_at(document, offset - command.start(document)) match {
+ case Some(ref) =>
+ val command_start = command.start(document)
+ val begin = theory_view.to_current(document, command_start + ref.start)
+ val line = buffer.getLineOfOffset(begin)
+ val end = theory_view.to_current(document, command_start + ref.stop)
+ ref.info match {
+ case Command.RefInfo(Some(ref_file), Some(ref_line), _, _) =>
+ new ExternalHyperlink(begin, end, line, ref_file, ref_line)
+ case Command.RefInfo(_, _, Some(id), Some(offset)) =>
+ prover.get.command(id) match {
+ case Some(ref_cmd) =>
+ new InternalHyperlink(begin, end, line,
+ theory_view.to_current(document, ref_cmd.start(document) + offset - 1))
+ case None => null
+ }
+ case _ => null
+ }
+ case None => null
+ }
+ case None => null
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/isabelle_sidekick.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,102 @@
+/*
+ * SideKick parser for Isabelle proof documents
+ *
+ * @author Fabian Immler, TU Munich
+ * @author Makarius
+ */
+
+package isabelle.jedit
+
+import scala.collection.Set
+import scala.collection.immutable.TreeSet
+
+import javax.swing.tree.DefaultMutableTreeNode
+import javax.swing.text.Position
+import javax.swing.Icon
+
+import org.gjt.sp.jedit.{Buffer, EditPane, TextUtilities, View}
+import errorlist.DefaultErrorSource
+import sidekick.{SideKickParser, SideKickParsedData, SideKickCompletion, IAsset}
+
+import isabelle.prover.{Command, Markup_Node}
+import isabelle.proofdocument.ProofDocument
+
+
+class IsabelleSideKickParser extends SideKickParser("isabelle")
+{
+ /* parsing */
+
+ @volatile private var stopped = false
+ override def stop() = { stopped = true }
+
+ def parse(buffer: Buffer, error_source: DefaultErrorSource): SideKickParsedData =
+ {
+ implicit def int_to_pos(offset: Int): Position =
+ new Position { def getOffset = offset; override def toString = offset.toString }
+
+ stopped = false
+
+ val data = new SideKickParsedData(buffer.getName)
+ val root = data.root
+ data.getAsset(root).setEnd(buffer.getLength)
+
+ val prover_setup = Isabelle.prover_setup(buffer)
+ if (prover_setup.isDefined) {
+ val document = prover_setup.get.theory_view.current_document()
+ for (command <- document.commands if !stopped) {
+ root.add(command.markup_root(document).swing_tree((node: Markup_Node) =>
+ {
+ val content = command.content(node.start, node.stop)
+ val command_start = command.start(document)
+ val id = command.id
+
+ new DefaultMutableTreeNode(new IAsset {
+ override def getIcon: Icon = null
+ override def getShortString: String = content
+ override def getLongString: String = node.info.toString
+ override def getName: String = id
+ override def setName(name: String) = ()
+ override def setStart(start: Position) = ()
+ override def getStart: Position = command_start + node.start
+ override def setEnd(end: Position) = ()
+ override def getEnd: Position = command_start + node.stop
+ override def toString = id + ": " + content + "[" + getStart + " - " + getEnd + "]"
+ })
+ }))
+ }
+ if (stopped) root.add(new DefaultMutableTreeNode("<parser stopped>"))
+ }
+ else root.add(new DefaultMutableTreeNode("<buffer inactive>"))
+
+ data
+ }
+
+
+ /* completion */
+
+ override def supportsCompletion = true
+ override def canCompleteAnywhere = true
+
+ override def complete(pane: EditPane, caret: Int): SideKickCompletion =
+ {
+ val buffer = pane.getBuffer
+
+ val line = buffer.getLineOfOffset(caret)
+ val start = buffer.getLineStartOffset(line)
+ val text = buffer.getSegment(start, caret - start)
+
+ val completion =
+ Isabelle.prover_setup(buffer).map(_.prover.completion()).getOrElse(Isabelle.completion)
+
+ completion.complete(text) match {
+ case None => null
+ case Some((word, cs)) =>
+ val ds =
+ if (Isabelle_Encoding.is_active(buffer))
+ cs.map(Isabelle.system.symbols.decode(_)).sort(Completion.length_ord _)
+ else cs
+ new SideKickCompletion(pane.getView, word, ds.toArray.asInstanceOf[Array[Object]]) { }
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/option_pane.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,43 @@
+/*
+ * Editor pane for plugin options
+ *
+ * @author Johannes Hölzl, TU Munich
+ */
+
+package isabelle.jedit
+
+import javax.swing.{JComboBox, JSpinner}
+
+import org.gjt.sp.jedit.AbstractOptionPane
+
+
+class OptionPane extends AbstractOptionPane("isabelle")
+{
+ private val logic_name = new JComboBox()
+ private val font_size = new JSpinner()
+
+ override def _init()
+ {
+ addComponent(Isabelle.Property("logic.title"), {
+ for (name <- Isabelle.system.find_logics()) {
+ logic_name.addItem(name)
+ if (name == Isabelle.Property("logic"))
+ logic_name.setSelectedItem(name)
+ }
+ logic_name
+ })
+ addComponent(Isabelle.Property("font-size.title"), {
+ font_size.setValue(Isabelle.Int_Property("font-size"))
+ font_size
+ })
+ }
+
+ override def _save()
+ {
+ val logic = logic_name.getSelectedItem.asInstanceOf[String]
+ Isabelle.Property("logic") = logic
+
+ val size = font_size.getValue().asInstanceOf[Int]
+ Isabelle.Int_Property("font-size") = size
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/plugin.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,155 @@
+/*
+ * Main Isabelle/jEdit plugin setup
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+
+import java.io.{FileInputStream, IOException}
+import java.awt.Font
+import javax.swing.JScrollPane
+
+import scala.collection.mutable
+
+import isabelle.prover.{Prover, Command}
+import isabelle.proofdocument.ProofDocument
+import isabelle.Isabelle_System
+
+import org.gjt.sp.jedit.{jEdit, EBMessage, EBPlugin, Buffer, EditPane, ServiceManager, View}
+import org.gjt.sp.jedit.buffer.JEditBuffer
+import org.gjt.sp.jedit.textarea.JEditTextArea
+import org.gjt.sp.jedit.msg.{EditPaneUpdate, PropertiesChanged}
+
+
+object Isabelle
+{
+ /* name */
+
+ val NAME = "Isabelle"
+
+
+ /* properties */
+
+ val OPTION_PREFIX = "options.isabelle."
+
+ object Property
+ {
+ def apply(name: String): String = jEdit.getProperty(OPTION_PREFIX + name)
+ def update(name: String, value: String) = jEdit.setProperty(OPTION_PREFIX + name, value)
+ }
+
+ object Boolean_Property
+ {
+ def apply(name: String): Boolean = jEdit.getBooleanProperty(OPTION_PREFIX + name)
+ def update(name: String, value: Boolean) = jEdit.setBooleanProperty(OPTION_PREFIX + name, value)
+ }
+
+ object Int_Property
+ {
+ def apply(name: String): Int = jEdit.getIntegerProperty(OPTION_PREFIX + name)
+ def update(name: String, value: Int) = jEdit.setIntegerProperty(OPTION_PREFIX + name, value)
+ }
+
+
+ /* Isabelle system instance */
+
+ var system: Isabelle_System = null
+ def symbols = system.symbols
+ lazy val completion = new Completion + symbols
+
+
+ /* settings */
+
+ def default_logic(): String =
+ {
+ val logic = Isabelle.Property("logic")
+ if (logic != null) logic
+ else system.getenv_strict("ISABELLE_LOGIC")
+ }
+
+
+ /* plugin instance */
+
+ var plugin: Plugin = null
+
+
+ /* running provers */
+
+ def prover_setup(buffer: JEditBuffer) = plugin.prover_setup(buffer)
+}
+
+
+class Plugin extends EBPlugin
+{
+ /* event buses */
+
+ val state_update = new Event_Bus[Command]
+
+
+ /* selected state */
+
+ private var _selected_state: Command = null
+ def selected_state = _selected_state
+ def selected_state_=(state: Command) { _selected_state = state; state_update.event(state) }
+
+
+ /* mapping buffer <-> prover */
+
+ private val mapping = new mutable.HashMap[JEditBuffer, ProverSetup]
+
+ private def install(view: View)
+ {
+ val buffer = view.getBuffer
+ val prover_setup = new ProverSetup(buffer)
+ mapping.update(buffer, prover_setup)
+ prover_setup.activate(view)
+ }
+
+ private def uninstall(view: View) =
+ mapping.removeKey(view.getBuffer).get.deactivate
+
+ def switch_active (view: View) =
+ if (mapping.isDefinedAt(view.getBuffer)) uninstall(view)
+ else install(view)
+
+ def prover_setup(buffer: JEditBuffer): Option[ProverSetup] = mapping.get(buffer)
+ def is_active (buffer: JEditBuffer) = mapping.isDefinedAt(buffer)
+
+
+ /* main plugin plumbing */
+
+ override def handleMessage(msg: EBMessage)
+ {
+ msg match {
+ case epu: EditPaneUpdate =>
+ val buffer = epu.getEditPane.getBuffer
+ epu.getWhat match {
+ case EditPaneUpdate.BUFFER_CHANGED =>
+ (mapping get buffer) map (_.theory_view.activate)
+ case EditPaneUpdate.BUFFER_CHANGING =>
+ if (buffer != null)
+ (mapping get buffer) map (_.theory_view.deactivate)
+ case _ =>
+ }
+ case _ =>
+ }
+ }
+
+ override def start()
+ {
+ Isabelle.plugin = this
+ Isabelle.system = new Isabelle_System
+ if (!Isabelle.system.register_fonts())
+ System.err.println("Failed to register Isabelle fonts")
+ }
+
+ override def stop()
+ {
+ // TODO: proper cleanup
+ Isabelle.system = null
+ Isabelle.plugin = null
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/prover_setup.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,35 @@
+/*
+ * Independent prover sessions for each buffer
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+
+import org.gjt.sp.jedit.{Buffer, View}
+
+import isabelle.prover.Prover
+
+
+class ProverSetup(buffer: Buffer)
+{
+ var prover: Prover = null
+ var theory_view: TheoryView = null
+
+ def activate(view: View)
+ {
+ // TheoryView starts prover
+ theory_view = new TheoryView(view.getTextArea)
+ prover = theory_view.prover
+
+ theory_view.activate()
+ prover.begin_document(buffer.getName)
+ }
+
+ def deactivate()
+ {
+ theory_view.deactivate
+ prover.stop
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/raw_output_dockable.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,31 @@
+/*
+ * Dockable window for raw process output
+ *
+ * @author Fabian Immler, TU Munich
+ * @author Johannes Hölzl, TU Munich
+ */
+
+package isabelle.jedit
+
+
+import java.awt.{Dimension, Graphics, GridLayout}
+import javax.swing.{JPanel, JTextArea, JScrollPane}
+
+import org.gjt.sp.jedit.View
+import org.gjt.sp.jedit.gui.DockableWindowManager
+
+
+class OutputDockable(view : View, position : String) extends JPanel {
+
+ if (position == DockableWindowManager.FLOATING)
+ setPreferredSize(new Dimension(500, 250))
+
+ setLayout(new GridLayout(1, 1))
+ add(new JScrollPane(new JTextArea))
+
+ def set_text(output_text_view: JTextArea) {
+ removeAll()
+ add(new JScrollPane(output_text_view))
+ revalidate()
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/results_dockable.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,111 @@
+/*
+ * Dockable window with rendered state output
+ *
+ * @author Fabian Immler, TU Munich
+ * @author Johannes Hölzl, TU Munich
+ */
+
+package isabelle.jedit
+
+import isabelle.XML
+
+import java.io.StringReader
+import java.awt.{BorderLayout, Dimension}
+
+import javax.swing.{JButton, JPanel, JScrollPane}
+
+import java.util.logging.{Logger, Level}
+
+import org.lobobrowser.html.parser._
+import org.lobobrowser.html.test._
+import org.lobobrowser.html.gui._
+import org.lobobrowser.html._
+import org.lobobrowser.html.style.CSSUtilities
+import org.lobobrowser.html.domimpl.{HTMLDocumentImpl, HTMLStyleElementImpl, NodeImpl}
+
+import org.gjt.sp.jedit.jEdit
+import org.gjt.sp.jedit.View
+import org.gjt.sp.jedit.gui.DockableWindowManager
+import org.gjt.sp.jedit.textarea.AntiAlias
+
+import scala.io.Source
+
+
+class StateViewDockable(view : View, position : String) extends JPanel {
+
+ // outer panel
+ if (position == DockableWindowManager.FLOATING)
+ setPreferredSize(new Dimension(500, 250))
+ setLayout(new BorderLayout)
+
+
+ // global logging
+
+ Logger.getLogger("org.lobobrowser").setLevel(Level.WARNING)
+
+
+ // document template with styles
+
+ private def try_file(name: String): String =
+ {
+ val file = Isabelle.system.platform_file(name)
+ if (file.exists) Source.fromFile(file).mkString else ""
+ }
+
+
+ // HTML panel
+
+ val panel = new HtmlPanel
+ val ucontext = new SimpleUserAgentContext
+ val rcontext = new SimpleHtmlRendererContext(panel, ucontext)
+ val doc = {
+ val builder = new DocumentBuilderImpl(ucontext, rcontext)
+ builder.parse(new InputSourceImpl(new StringReader(
+ """<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<style media="all" type="text/css">
+""" +
+ try_file("$ISABELLE_HOME/lib/html/isabelle.css") + "\n" +
+"""
+body {
+ font-family: IsabelleText;
+ font-size: 14pt;
+}
+""" +
+ try_file("$ISABELLE_HOME_USER/etc/isabelle.css") + "\n" +
+"""
+</style>
+</head>
+</html>
+""")))
+ }
+
+ val empty_body = XML.document_node(doc, XML.elem(HTML.BODY))
+ doc.appendChild(empty_body)
+
+ panel.setDocument(doc, rcontext)
+ add(panel, BorderLayout.CENTER)
+
+
+ // register for state-view
+ Isabelle.plugin.state_update += (cmd => {
+ val theory_view = Isabelle.prover_setup(view.getBuffer).get.theory_view
+
+ Swing_Thread.later {
+ val node =
+ if (cmd == null) empty_body
+ else {
+ val xml = XML.elem(HTML.BODY,
+ cmd.results(theory_view.current_document).
+ map((t: XML.Tree) => XML.elem(HTML.PRE, HTML.spans(t))))
+ XML.document_node(doc, xml)
+ }
+ doc.removeChild(doc.getLastChild())
+ doc.appendChild(node)
+ panel.delayedRelayout(node.asInstanceOf[NodeImpl])
+ }
+ })
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/jedit/token_marker.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,154 @@
+/*
+ * include isabelle's command- and keyword-declarations
+ * live in jEdits syntax-highlighting
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.jedit
+
+
+import isabelle.prover.Prover
+import isabelle.Markup
+
+import org.gjt.sp.jedit.buffer.JEditBuffer
+import org.gjt.sp.jedit.syntax.{Token => JToken,
+ TokenMarker, TokenHandler, SyntaxStyle, ParserRuleSet}
+
+import java.awt.Color
+import java.awt.Font
+import javax.swing.text.Segment;
+
+
+object DynamicTokenMarker
+{
+ /* line context */
+
+ private val rule_set = new ParserRuleSet("isabelle", "MAIN")
+ private class LineContext(val line: Int, prev: LineContext)
+ extends TokenMarker.LineContext(rule_set, prev)
+
+
+ /* mapping to jEdit token types */
+ // TODO: as properties or CSS style sheet
+
+ private val choose_byte: Map[String, Byte] =
+ {
+ import JToken._
+ Map[String, Byte](
+ // logical entities
+ Markup.TCLASS -> LABEL,
+ Markup.TYCON -> LABEL,
+ Markup.FIXED_DECL -> LABEL,
+ Markup.FIXED -> LABEL,
+ Markup.CONST_DECL -> LABEL,
+ Markup.CONST -> LABEL,
+ Markup.FACT_DECL -> LABEL,
+ Markup.FACT -> LABEL,
+ Markup.DYNAMIC_FACT -> LABEL,
+ Markup.LOCAL_FACT_DECL -> LABEL,
+ Markup.LOCAL_FACT -> LABEL,
+ // inner syntax
+ Markup.TFREE -> LITERAL2,
+ Markup.FREE -> LITERAL2,
+ Markup.TVAR -> LITERAL3,
+ Markup.SKOLEM -> LITERAL3,
+ Markup.BOUND -> LITERAL3,
+ Markup.VAR -> LITERAL3,
+ Markup.NUM -> DIGIT,
+ Markup.FLOAT -> DIGIT,
+ Markup.XNUM -> DIGIT,
+ Markup.XSTR -> LITERAL4,
+ Markup.LITERAL -> LITERAL4,
+ Markup.INNER_COMMENT -> COMMENT1,
+ Markup.SORT -> FUNCTION,
+ Markup.TYP -> FUNCTION,
+ Markup.TERM -> FUNCTION,
+ Markup.PROP -> FUNCTION,
+ Markup.ATTRIBUTE -> FUNCTION,
+ Markup.METHOD -> FUNCTION,
+ // ML syntax
+ Markup.ML_KEYWORD -> KEYWORD2,
+ Markup.ML_IDENT -> NULL,
+ Markup.ML_TVAR -> LITERAL3,
+ Markup.ML_NUMERAL -> DIGIT,
+ Markup.ML_CHAR -> LITERAL1,
+ Markup.ML_STRING -> LITERAL1,
+ Markup.ML_COMMENT -> COMMENT1,
+ Markup.ML_MALFORMED -> INVALID,
+ // embedded source text
+ Markup.ML_SOURCE -> COMMENT4,
+ Markup.DOC_SOURCE -> COMMENT4,
+ Markup.ANTIQ -> COMMENT4,
+ Markup.ML_ANTIQ -> COMMENT4,
+ Markup.DOC_ANTIQ -> COMMENT4,
+ // outer syntax
+ Markup.IDENT -> NULL,
+ Markup.COMMAND -> OPERATOR,
+ Markup.KEYWORD -> KEYWORD4,
+ Markup.VERBATIM -> COMMENT3,
+ Markup.COMMENT -> COMMENT1,
+ Markup.CONTROL -> COMMENT3,
+ Markup.MALFORMED -> INVALID,
+ Markup.STRING -> LITERAL3,
+ Markup.ALTSTRING -> LITERAL1
+ ).withDefaultValue(NULL)
+ }
+
+ def choose_color(kind: String, styles: Array[SyntaxStyle]): Color =
+ styles(choose_byte(kind)).getForegroundColor
+}
+
+
+class DynamicTokenMarker(buffer: JEditBuffer, prover: Prover)
+ extends TokenMarker
+{
+ override def markTokens(prev: TokenMarker.LineContext,
+ handler: TokenHandler, line_segment: Segment): TokenMarker.LineContext =
+ {
+ val previous = prev.asInstanceOf[DynamicTokenMarker.LineContext]
+ val line = if (prev == null) 0 else previous.line + 1
+ val context = new DynamicTokenMarker.LineContext(line, previous)
+ val start = buffer.getLineStartOffset(line)
+ val stop = start + line_segment.count
+
+ val theory_view = Isabelle.prover_setup(buffer).get.theory_view
+ val document = theory_view.current_document()
+ def to: Int => Int = theory_view.to_current(document, _)
+ def from: Int => Int = theory_view.from_current(document, _)
+
+ var next_x = start
+ var cmd = document.command_at(from(start))
+ while (cmd.isDefined && cmd.get.start(document) < from(stop)) {
+ val command = cmd.get
+ for {
+ markup <- command.highlight(document).flatten
+ command_start = command.start(document)
+ abs_start = to(command_start + markup.start)
+ abs_stop = to(command_start + markup.stop)
+ if (abs_stop > start)
+ if (abs_start < stop)
+ byte = DynamicTokenMarker.choose_byte(markup.info.toString)
+ token_start = (abs_start - start) max 0
+ token_length =
+ (abs_stop - abs_start) -
+ ((start - abs_start) max 0) -
+ ((abs_stop - stop) max 0)
+ } {
+ if (start + token_start > next_x)
+ handler.handleToken(line_segment, 1,
+ next_x - start, start + token_start - next_x, context)
+ handler.handleToken(line_segment, byte,
+ token_start, token_length, context)
+ next_x = start + token_start + token_length
+ }
+ cmd = document.commands.next(command)
+ }
+ if (next_x < stop)
+ handler.handleToken(line_segment, 1, next_x - start, stop - next_x, context)
+
+ handler.handleToken(line_segment, JToken.END, line_segment.count, 0, context)
+ handler.setLineContext(context)
+ return context
+ }
+}
--- a/src/Tools/jEdit/src/proofdocument/Change.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Changes of plain text
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.proofdocument
-
-
-sealed abstract class Edit
-{
- val start: Int
- def before(offset: Int): Int
- def after(offset: Int): Int
-}
-
-
-case class Insert(start: Int, text: String) extends Edit
-{
- def before(offset: Int): Int =
- if (start > offset) offset
- else (offset - text.length) max start
-
- def after(offset: Int): Int =
- if (start <= offset) offset + text.length else offset
-}
-
-
-case class Remove(start: Int, text: String) extends Edit
-{
- def before(offset: Int): Int =
- if (start <= offset) offset + text.length else offset
-
- def after(offset: Int): Int =
- if (start > offset) offset
- else (offset - text.length) max start
-}
-// TODO: merge multiple inserts?
-
-
-class Change(
- val id: String,
- val parent: Option[Change],
- val edits: List[Edit])
-{
- def ancestors(done: Change => Boolean): List[Change] =
- if (done(this)) Nil
- else this :: parent.map(_.ancestors(done)).getOrElse(Nil)
- def ancestors: List[Change] = ancestors(_ => false)
-
- override def toString =
- "Change(" + id + " <- " + parent.map(_.id) + ", " + edits + ")"
-}
\ No newline at end of file
--- a/src/Tools/jEdit/src/proofdocument/ProofDocument.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,277 +0,0 @@
-/*
- * Document as list of commands, consisting of lists of tokens
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- * @author Makarius
- */
-
-package isabelle.proofdocument
-
-import scala.actors.Actor, Actor._
-
-import java.util.regex.Pattern
-
-import isabelle.prover.{Prover, Command, Command_State}
-
-
-object ProofDocument
-{
- // Be careful when changing this regex. Not only must it handle the
- // spurious end of a token but also:
- // Bug ID: 5050507 Pattern.matches throws StackOverflow Error
- // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507
-
- val token_pattern =
- Pattern.compile(
- "\\{\\*([^*]|\\*[^}]|\\*\\z)*(\\z|\\*\\})|" +
- "\\(\\*([^*]|\\*[^)]|\\*\\z)*(\\z|\\*\\))|" +
- "(\\?'?|')[A-Za-z_0-9.]*|" +
- "[A-Za-z_0-9.]+|" +
- "[!#$%&*+-/<=>?@^_|~]+|" +
- "\"([^\\\\\"]?(\\\\(.|\\z))?)*+(\"|\\z)|" +
- "`([^\\\\`]?(\\\\(.|\\z))?)*+(`|\\z)|" +
- "[()\\[\\]{}:;]", Pattern.MULTILINE)
-
- val empty =
- new ProofDocument(isabelle.jedit.Isabelle.system.id(),
- Linear_Set(), Map(), Linear_Set(), Map(), _ => false)
-
- type StructureChange = List[(Option[Command], Option[Command])]
-
-}
-
-class ProofDocument(
- val id: String,
- val tokens: Linear_Set[Token],
- val token_start: Map[Token, Int],
- val commands: Linear_Set[Command],
- var states: Map[Command, Command_State], // FIXME immutable
- is_command_keyword: String => Boolean)
-{
- import ProofDocument.StructureChange
-
- def set_command_keyword(f: String => Boolean): ProofDocument =
- new ProofDocument(id, tokens, token_start, commands, states, f)
-
- def content = Token.string_from_tokens(Nil ++ tokens, token_start)
-
-
-
- /** token view **/
-
- def text_changed(change: Change): (ProofDocument, StructureChange) =
- {
- def edit_doc(doc_chgs: (ProofDocument, StructureChange), edit: Edit) = {
- val (doc, chgs) = doc_chgs
- val (new_doc, chg) = doc.text_edit(edit, change.id)
- (new_doc, chgs ++ chg)
- }
- ((this, Nil: StructureChange) /: change.edits)(edit_doc)
- }
-
- def text_edit(e: Edit, id: String): (ProofDocument, StructureChange) =
- {
- case class TextChange(start: Int, added: String, removed: String)
- val change = e match {
- case Insert(s, a) => TextChange(s, a, "")
- case Remove(s, r) => TextChange(s, "", r)
- }
- //indices of tokens
- var start: Map[Token, Int] = token_start
- def stop(t: Token) = start(t) + t.length
- // split old token lists
- val tokens = Nil ++ this.tokens
- val (begin, remaining) = tokens.span(stop(_) < change.start)
- val (removed, end) = remaining.span(token_start(_) <= change.start + change.removed.length)
- // update indices
- start = end.foldLeft(start)((s, t) =>
- s + (t -> (s(t) + change.added.length - change.removed.length)))
-
- val split_begin = removed.takeWhile(start(_) < change.start).
- map (t => {
- val split_tok = new Token(t.content.substring(0, change.start - start(t)), t.kind)
- start += (split_tok -> start(t))
- split_tok
- })
-
- val split_end = removed.dropWhile(stop(_) < change.start + change.removed.length).
- map (t => {
- val split_tok =
- new Token(t.content.substring(change.start + change.removed.length - start(t)), t.kind)
- start += (split_tok -> start(t))
- split_tok
- })
- // update indices
- start = removed.foldLeft (start) ((s, t) => s - t)
- start = split_end.foldLeft (start) ((s, t) =>
- s + (t -> (change.start + change.added.length)))
-
- val ins = new Token(change.added, Token.Kind.OTHER)
- start += (ins -> change.start)
-
- var invalid_tokens = split_begin ::: ins :: split_end ::: end
- var new_tokens: List[Token] = Nil
- var old_suffix: List[Token] = Nil
-
- val match_start = invalid_tokens.firstOption.map(start(_)).getOrElse(0)
- val matcher =
- ProofDocument.token_pattern.matcher(Token.string_from_tokens(invalid_tokens, start))
-
- while (matcher.find() && invalid_tokens != Nil) {
- val kind =
- if (is_command_keyword(matcher.group))
- Token.Kind.COMMAND_START
- else if (matcher.end - matcher.start > 2 && matcher.group.substring(0, 2) == "(*")
- Token.Kind.COMMENT
- else
- Token.Kind.OTHER
- val new_token = new Token(matcher.group, kind)
- start += (new_token -> (match_start + matcher.start))
- new_tokens ::= new_token
-
- invalid_tokens = invalid_tokens dropWhile (stop(_) < stop(new_token))
- invalid_tokens match {
- case t :: ts =>
- if (start(t) == start(new_token) &&
- start(t) > change.start + change.added.length) {
- old_suffix = t :: ts
- new_tokens = new_tokens.tail
- invalid_tokens = Nil
- }
- case _ =>
- }
- }
- val insert = new_tokens.reverse
- val new_token_list = begin ::: insert ::: old_suffix
- token_changed(id, begin.lastOption, insert,
- old_suffix.firstOption, new_token_list, start)
- }
-
-
- /** command view **/
-
- private def token_changed(
- new_id: String,
- before_change: Option[Token],
- inserted_tokens: List[Token],
- after_change: Option[Token],
- new_tokens: List[Token],
- new_token_start: Map[Token, Int]):
- (ProofDocument, StructureChange) =
- {
- val new_tokenset = Linear_Set[Token]() ++ new_tokens
- val cmd_before_change = before_change match {
- case None => None
- case Some(bc) =>
- val cmd_with_bc = commands.find(_.contains(bc)).get
- if (cmd_with_bc.tokens.last == bc) {
- if (new_tokenset.next(bc).map(_.is_start).getOrElse(true))
- Some(cmd_with_bc)
- else commands.prev(cmd_with_bc)
- }
- else commands.prev(cmd_with_bc)
- }
-
- val cmd_after_change = after_change match {
- case None => None
- case Some(ac) =>
- val cmd_with_ac = commands.find(_.contains(ac)).get
- if (ac.is_start)
- Some(cmd_with_ac)
- else
- commands.next(cmd_with_ac)
- }
-
- val removed_commands = commands.dropWhile(Some(_) != cmd_before_change).drop(1).
- takeWhile(Some(_) != cmd_after_change)
-
- // calculate inserted commands
- def tokens_to_commands(tokens: List[Token]): List[Command]= {
- tokens match {
- case Nil => Nil
- case t :: ts =>
- val (cmd, rest) =
- ts.span(t => t.kind != Token.Kind.COMMAND_START && t.kind != Token.Kind.COMMENT)
- new Command(t :: cmd, new_token_start) :: tokens_to_commands(rest)
- }
- }
-
- val split_begin =
- if (before_change.isDefined) {
- val changed =
- if (cmd_before_change.isDefined)
- new_tokens.dropWhile(_ != cmd_before_change.get.tokens.last).drop(1)
- else new_tokenset
- if (changed.exists(_ == before_change.get))
- changed.takeWhile(_ != before_change.get).toList :::
- List(before_change.get)
- else Nil
- } else Nil
-
- val split_end =
- if (after_change.isDefined) {
- val unchanged = new_tokens.dropWhile(_ != after_change.get)
- if(cmd_after_change.isDefined) {
- if (unchanged.exists(_ == cmd_after_change.get.tokens.first))
- unchanged.takeWhile(_ != cmd_after_change.get.tokens.first).toList
- else Nil
- } else {
- unchanged
- }
- } else Nil
-
- val rescan_begin =
- split_begin :::
- before_change.map(bc => new_tokens.dropWhile(_ != bc).drop(1)).getOrElse(new_tokens)
- val rescanning_tokens =
- after_change.map(ac => rescan_begin.takeWhile(_ != ac)).getOrElse(rescan_begin) :::
- split_end
- val inserted_commands = tokens_to_commands(rescanning_tokens.toList)
-
- // build new document
- val new_commandset = commands.
- delete_between(cmd_before_change, cmd_after_change).
- append_after(cmd_before_change, inserted_commands)
-
-
- val doc =
- new ProofDocument(new_id, new_tokenset, new_token_start, new_commandset,
- states -- removed_commands, is_command_keyword)
-
- val removes =
- for (cmd <- removed_commands) yield (cmd_before_change -> None)
- val inserts =
- for (cmd <- inserted_commands) yield (doc.commands.prev(cmd) -> Some(cmd))
-
- return (doc, removes.toList ++ inserts)
- }
-
- val commands_offsets = {
- var last_stop = 0
- (for (c <- commands) yield {
- val r = c -> (last_stop,c.stop(this))
- last_stop = c.stop(this)
- r
- }).toArray
- }
-
- def command_at(pos: Int): Option[Command] =
- find_command(pos, 0, commands_offsets.length)
-
- // use a binary search to find commands for a given offset
- private def find_command(pos: Int, array_start: Int, array_stop: Int): Option[Command] =
- {
- val middle_index = (array_start + array_stop) / 2
- if (middle_index >= commands_offsets.length) return None
- val (middle, (start, stop)) = commands_offsets(middle_index)
- // does middle contain pos?
- if (start <= pos && pos < stop)
- Some(middle)
- else if (start > pos)
- find_command(pos, array_start, middle_index)
- else if (stop <= pos)
- find_command(pos, middle_index + 1, array_stop)
- else error("impossible")
- }
-}
--- a/src/Tools/jEdit/src/proofdocument/Token.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Document tokens as text ranges
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.proofdocument
-
-
-import isabelle.prover.Command
-
-
-object Token {
- object Kind extends Enumeration
- {
- val COMMAND_START = Value("COMMAND_START")
- val COMMENT = Value("COMMENT")
- val OTHER = Value("OTHER")
- }
-
- def string_from_tokens(tokens: List[Token], starts: Token => Int): String = {
- def stop(t: Token) = starts(t) + t.length
- tokens match {
- case Nil => ""
- case tok :: toks =>
- val (res, _) = toks.foldLeft(tok.content, stop(tok))((a, token) =>
- (a._1 + " " * (starts(token) - a._2) + token.content, stop(token)))
- res
- }
- }
-
-}
-
-class Token(
- val content: String,
- val kind: Token.Kind.Value)
-{
- override def toString = content
- val length = content.length
- val is_start = kind == Token.Kind.COMMAND_START || kind == Token.Kind.COMMENT
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/change.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,54 @@
+/*
+ * Changes of plain text
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.proofdocument
+
+
+sealed abstract class Edit
+{
+ val start: Int
+ def before(offset: Int): Int
+ def after(offset: Int): Int
+}
+
+
+case class Insert(start: Int, text: String) extends Edit
+{
+ def before(offset: Int): Int =
+ if (start > offset) offset
+ else (offset - text.length) max start
+
+ def after(offset: Int): Int =
+ if (start <= offset) offset + text.length else offset
+}
+
+
+case class Remove(start: Int, text: String) extends Edit
+{
+ def before(offset: Int): Int =
+ if (start <= offset) offset + text.length else offset
+
+ def after(offset: Int): Int =
+ if (start > offset) offset
+ else (offset - text.length) max start
+}
+// TODO: merge multiple inserts?
+
+
+class Change(
+ val id: String,
+ val parent: Option[Change],
+ val edits: List[Edit])
+{
+ def ancestors(done: Change => Boolean): List[Change] =
+ if (done(this)) Nil
+ else this :: parent.map(_.ancestors(done)).getOrElse(Nil)
+ def ancestors: List[Change] = ancestors(_ => false)
+
+ override def toString =
+ "Change(" + id + " <- " + parent.map(_.id) + ", " + edits + ")"
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/command.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,124 @@
+/*
+ * Prover commands with semantic state
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.prover
+
+
+import scala.actors.Actor, Actor._
+
+import scala.collection.mutable
+
+import isabelle.proofdocument.{Token, ProofDocument}
+import isabelle.jedit.{Isabelle, Plugin}
+import isabelle.XML
+
+
+trait Accumulator extends Actor
+{
+ start() // start actor
+
+ protected var _state: State
+ def state = _state
+
+ override def act() {
+ loop {
+ react {
+ case (prover: Prover, message: XML.Tree) => _state = _state.+(prover, message)
+ case bad => System.err.println("prover: ignoring bad message " + bad)
+ }
+ }
+ }
+}
+
+
+object Command
+{
+ object Status extends Enumeration
+ {
+ val UNPROCESSED = Value("UNPROCESSED")
+ val FINISHED = Value("FINISHED")
+ val FAILED = Value("FAILED")
+ }
+
+ case class HighlightInfo(highlight: String) { override def toString = highlight }
+ case class TypeInfo(ty: String)
+ case class RefInfo(file: Option[String], line: Option[Int],
+ command_id: Option[String], offset: Option[Int])
+}
+
+
+class Command(
+ val tokens: List[Token],
+ val starts: Map[Token, Int]) extends Accumulator
+{
+ require(!tokens.isEmpty)
+
+ val id = Isabelle.system.id()
+ override def hashCode = id.hashCode
+
+
+ /* content */
+
+ override def toString = name
+
+ val name = tokens.head.content
+ val content: String = Token.string_from_tokens(tokens, starts)
+ def content(i: Int, j: Int): String = content.substring(i, j)
+ val symbol_index = new Symbol.Index(content)
+
+ def start(doc: ProofDocument) = doc.token_start(tokens.first)
+ def stop(doc: ProofDocument) = doc.token_start(tokens.last) + tokens.last.length
+
+ def contains(p: Token) = tokens.contains(p)
+
+ protected override var _state = new State(this)
+
+
+ /* markup */
+
+ lazy val empty_markup = new Markup_Text(Nil, content)
+
+ def markup_node(begin: Int, end: Int, info: Any): Markup_Tree =
+ {
+ val start = symbol_index.decode(begin)
+ val stop = symbol_index.decode(end)
+ new Markup_Tree(new Markup_Node(start, stop, info), Nil)
+ }
+
+
+ /* results, markup, ... */
+
+ private val empty_cmd_state = new Command_State(this)
+ private def cmd_state(doc: ProofDocument) =
+ doc.states.getOrElse(this, empty_cmd_state)
+
+ def status(doc: ProofDocument) = cmd_state(doc).state.status
+ def results(doc: ProofDocument) = cmd_state(doc).results
+ def markup_root(doc: ProofDocument) = cmd_state(doc).markup_root
+ def highlight(doc: ProofDocument) = cmd_state(doc).highlight
+ def type_at(doc: ProofDocument, offset: Int) = cmd_state(doc).type_at(offset)
+ def ref_at(doc: ProofDocument, offset: Int) = cmd_state(doc).ref_at(offset)
+}
+
+
+class Command_State(val command: Command) extends Accumulator
+{
+ protected override var _state = new State(command)
+
+ def results: List[XML.Tree] =
+ command.state.results ::: state.results
+
+ def markup_root: Markup_Text =
+ (command.state.markup_root /: state.markup_root.markup)(_ + _)
+
+ def type_at(pos: Int): Option[String] = state.type_at(pos)
+
+ def ref_at(pos: Int): Option[Markup_Node] = state.ref_at(pos)
+
+ def highlight: Markup_Text =
+ (command.state.highlight /: state.highlight.markup)(_ + _)
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/markup_node.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,111 @@
+/*
+ * Document markup nodes, with connection to Swing tree model
+ *
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.prover
+
+
+import javax.swing.tree.DefaultMutableTreeNode
+
+import isabelle.proofdocument.ProofDocument
+
+
+class Markup_Node(val start: Int, val stop: Int, val info: Any)
+{
+ def fits_into(that: Markup_Node): Boolean =
+ that.start <= this.start && this.stop <= that.stop
+}
+
+
+class Markup_Tree(val node: Markup_Node, val branches: List[Markup_Tree])
+{
+ def set_branches(bs: List[Markup_Tree]): Markup_Tree = new Markup_Tree(node, bs)
+
+ private def add(branch: Markup_Tree) = // FIXME avoid sort
+ set_branches((branch :: branches) sort ((a, b) => a.node.start < b.node.start))
+
+ private def remove(bs: List[Markup_Tree]) = set_branches(branches -- bs)
+
+ def + (new_tree: Markup_Tree): Markup_Tree =
+ {
+ val new_node = new_tree.node
+ if (new_node fits_into node) {
+ var inserted = false
+ val new_branches =
+ branches.map(branch =>
+ if ((new_node fits_into branch.node) && !inserted) {
+ inserted = true
+ branch + new_tree
+ }
+ else branch)
+ if (!inserted) {
+ // new_tree did not fit into children of this
+ // -> insert between this and its branches
+ val fitting = branches filter(_.node fits_into new_node)
+ (this remove fitting) add ((new_tree /: fitting)(_ + _))
+ }
+ else set_branches(new_branches)
+ }
+ else {
+ System.err.println("ignored nonfitting markup: " + new_node)
+ this
+ }
+ }
+
+ def flatten: List[Markup_Node] =
+ {
+ var next_x = node.start
+ if (branches.isEmpty) List(this.node)
+ else {
+ val filled_gaps =
+ for {
+ child <- branches
+ markups =
+ if (next_x < child.node.start)
+ new Markup_Node(next_x, child.node.start, node.info) :: child.flatten
+ else child.flatten
+ update = (next_x = child.node.stop)
+ markup <- markups
+ } yield markup
+ if (next_x < node.stop)
+ filled_gaps + new Markup_Node(next_x, node.stop, node.info)
+ else filled_gaps
+ }
+ }
+}
+
+
+class Markup_Text(val markup: List[Markup_Tree], val content: String)
+{
+ private lazy val root =
+ new Markup_Tree(new Markup_Node(0, content.length, None), markup)
+
+ def + (new_tree: Markup_Tree): Markup_Text =
+ new Markup_Text((root + new_tree).branches, content)
+
+ def filter(pred: Markup_Node => Boolean): Markup_Text =
+ {
+ def filt(tree: Markup_Tree): List[Markup_Tree] =
+ {
+ val branches = tree.branches.flatMap(filt(_))
+ if (pred(tree.node)) List(tree.set_branches(branches))
+ else branches
+ }
+ new Markup_Text(markup.flatMap(filt(_)), content)
+ }
+
+ def flatten: List[Markup_Node] = markup.flatten(_.flatten)
+
+ def swing_tree(swing_node: Markup_Node => DefaultMutableTreeNode): DefaultMutableTreeNode =
+ {
+ def swing(tree: Markup_Tree): DefaultMutableTreeNode =
+ {
+ val node = swing_node(tree.node)
+ tree.branches foreach ((branch: Markup_Tree) => node.add(swing(branch)))
+ node
+ }
+ swing(root)
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/proof_document.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,277 @@
+/*
+ * Document as list of commands, consisting of lists of tokens
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ * @author Makarius
+ */
+
+package isabelle.proofdocument
+
+import scala.actors.Actor, Actor._
+
+import java.util.regex.Pattern
+
+import isabelle.prover.{Prover, Command, Command_State}
+
+
+object ProofDocument
+{
+ // Be careful when changing this regex. Not only must it handle the
+ // spurious end of a token but also:
+ // Bug ID: 5050507 Pattern.matches throws StackOverflow Error
+ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507
+
+ val token_pattern =
+ Pattern.compile(
+ "\\{\\*([^*]|\\*[^}]|\\*\\z)*(\\z|\\*\\})|" +
+ "\\(\\*([^*]|\\*[^)]|\\*\\z)*(\\z|\\*\\))|" +
+ "(\\?'?|')[A-Za-z_0-9.]*|" +
+ "[A-Za-z_0-9.]+|" +
+ "[!#$%&*+-/<=>?@^_|~]+|" +
+ "\"([^\\\\\"]?(\\\\(.|\\z))?)*+(\"|\\z)|" +
+ "`([^\\\\`]?(\\\\(.|\\z))?)*+(`|\\z)|" +
+ "[()\\[\\]{}:;]", Pattern.MULTILINE)
+
+ val empty =
+ new ProofDocument(isabelle.jedit.Isabelle.system.id(),
+ Linear_Set(), Map(), Linear_Set(), Map(), _ => false)
+
+ type StructureChange = List[(Option[Command], Option[Command])]
+
+}
+
+class ProofDocument(
+ val id: String,
+ val tokens: Linear_Set[Token],
+ val token_start: Map[Token, Int],
+ val commands: Linear_Set[Command],
+ var states: Map[Command, Command_State], // FIXME immutable
+ is_command_keyword: String => Boolean)
+{
+ import ProofDocument.StructureChange
+
+ def set_command_keyword(f: String => Boolean): ProofDocument =
+ new ProofDocument(id, tokens, token_start, commands, states, f)
+
+ def content = Token.string_from_tokens(Nil ++ tokens, token_start)
+
+
+
+ /** token view **/
+
+ def text_changed(change: Change): (ProofDocument, StructureChange) =
+ {
+ def edit_doc(doc_chgs: (ProofDocument, StructureChange), edit: Edit) = {
+ val (doc, chgs) = doc_chgs
+ val (new_doc, chg) = doc.text_edit(edit, change.id)
+ (new_doc, chgs ++ chg)
+ }
+ ((this, Nil: StructureChange) /: change.edits)(edit_doc)
+ }
+
+ def text_edit(e: Edit, id: String): (ProofDocument, StructureChange) =
+ {
+ case class TextChange(start: Int, added: String, removed: String)
+ val change = e match {
+ case Insert(s, a) => TextChange(s, a, "")
+ case Remove(s, r) => TextChange(s, "", r)
+ }
+ //indices of tokens
+ var start: Map[Token, Int] = token_start
+ def stop(t: Token) = start(t) + t.length
+ // split old token lists
+ val tokens = Nil ++ this.tokens
+ val (begin, remaining) = tokens.span(stop(_) < change.start)
+ val (removed, end) = remaining.span(token_start(_) <= change.start + change.removed.length)
+ // update indices
+ start = end.foldLeft(start)((s, t) =>
+ s + (t -> (s(t) + change.added.length - change.removed.length)))
+
+ val split_begin = removed.takeWhile(start(_) < change.start).
+ map (t => {
+ val split_tok = new Token(t.content.substring(0, change.start - start(t)), t.kind)
+ start += (split_tok -> start(t))
+ split_tok
+ })
+
+ val split_end = removed.dropWhile(stop(_) < change.start + change.removed.length).
+ map (t => {
+ val split_tok =
+ new Token(t.content.substring(change.start + change.removed.length - start(t)), t.kind)
+ start += (split_tok -> start(t))
+ split_tok
+ })
+ // update indices
+ start = removed.foldLeft (start) ((s, t) => s - t)
+ start = split_end.foldLeft (start) ((s, t) =>
+ s + (t -> (change.start + change.added.length)))
+
+ val ins = new Token(change.added, Token.Kind.OTHER)
+ start += (ins -> change.start)
+
+ var invalid_tokens = split_begin ::: ins :: split_end ::: end
+ var new_tokens: List[Token] = Nil
+ var old_suffix: List[Token] = Nil
+
+ val match_start = invalid_tokens.firstOption.map(start(_)).getOrElse(0)
+ val matcher =
+ ProofDocument.token_pattern.matcher(Token.string_from_tokens(invalid_tokens, start))
+
+ while (matcher.find() && invalid_tokens != Nil) {
+ val kind =
+ if (is_command_keyword(matcher.group))
+ Token.Kind.COMMAND_START
+ else if (matcher.end - matcher.start > 2 && matcher.group.substring(0, 2) == "(*")
+ Token.Kind.COMMENT
+ else
+ Token.Kind.OTHER
+ val new_token = new Token(matcher.group, kind)
+ start += (new_token -> (match_start + matcher.start))
+ new_tokens ::= new_token
+
+ invalid_tokens = invalid_tokens dropWhile (stop(_) < stop(new_token))
+ invalid_tokens match {
+ case t :: ts =>
+ if (start(t) == start(new_token) &&
+ start(t) > change.start + change.added.length) {
+ old_suffix = t :: ts
+ new_tokens = new_tokens.tail
+ invalid_tokens = Nil
+ }
+ case _ =>
+ }
+ }
+ val insert = new_tokens.reverse
+ val new_token_list = begin ::: insert ::: old_suffix
+ token_changed(id, begin.lastOption, insert,
+ old_suffix.firstOption, new_token_list, start)
+ }
+
+
+ /** command view **/
+
+ private def token_changed(
+ new_id: String,
+ before_change: Option[Token],
+ inserted_tokens: List[Token],
+ after_change: Option[Token],
+ new_tokens: List[Token],
+ new_token_start: Map[Token, Int]):
+ (ProofDocument, StructureChange) =
+ {
+ val new_tokenset = Linear_Set[Token]() ++ new_tokens
+ val cmd_before_change = before_change match {
+ case None => None
+ case Some(bc) =>
+ val cmd_with_bc = commands.find(_.contains(bc)).get
+ if (cmd_with_bc.tokens.last == bc) {
+ if (new_tokenset.next(bc).map(_.is_start).getOrElse(true))
+ Some(cmd_with_bc)
+ else commands.prev(cmd_with_bc)
+ }
+ else commands.prev(cmd_with_bc)
+ }
+
+ val cmd_after_change = after_change match {
+ case None => None
+ case Some(ac) =>
+ val cmd_with_ac = commands.find(_.contains(ac)).get
+ if (ac.is_start)
+ Some(cmd_with_ac)
+ else
+ commands.next(cmd_with_ac)
+ }
+
+ val removed_commands = commands.dropWhile(Some(_) != cmd_before_change).drop(1).
+ takeWhile(Some(_) != cmd_after_change)
+
+ // calculate inserted commands
+ def tokens_to_commands(tokens: List[Token]): List[Command]= {
+ tokens match {
+ case Nil => Nil
+ case t :: ts =>
+ val (cmd, rest) =
+ ts.span(t => t.kind != Token.Kind.COMMAND_START && t.kind != Token.Kind.COMMENT)
+ new Command(t :: cmd, new_token_start) :: tokens_to_commands(rest)
+ }
+ }
+
+ val split_begin =
+ if (before_change.isDefined) {
+ val changed =
+ if (cmd_before_change.isDefined)
+ new_tokens.dropWhile(_ != cmd_before_change.get.tokens.last).drop(1)
+ else new_tokenset
+ if (changed.exists(_ == before_change.get))
+ changed.takeWhile(_ != before_change.get).toList :::
+ List(before_change.get)
+ else Nil
+ } else Nil
+
+ val split_end =
+ if (after_change.isDefined) {
+ val unchanged = new_tokens.dropWhile(_ != after_change.get)
+ if(cmd_after_change.isDefined) {
+ if (unchanged.exists(_ == cmd_after_change.get.tokens.first))
+ unchanged.takeWhile(_ != cmd_after_change.get.tokens.first).toList
+ else Nil
+ } else {
+ unchanged
+ }
+ } else Nil
+
+ val rescan_begin =
+ split_begin :::
+ before_change.map(bc => new_tokens.dropWhile(_ != bc).drop(1)).getOrElse(new_tokens)
+ val rescanning_tokens =
+ after_change.map(ac => rescan_begin.takeWhile(_ != ac)).getOrElse(rescan_begin) :::
+ split_end
+ val inserted_commands = tokens_to_commands(rescanning_tokens.toList)
+
+ // build new document
+ val new_commandset = commands.
+ delete_between(cmd_before_change, cmd_after_change).
+ append_after(cmd_before_change, inserted_commands)
+
+
+ val doc =
+ new ProofDocument(new_id, new_tokenset, new_token_start, new_commandset,
+ states -- removed_commands, is_command_keyword)
+
+ val removes =
+ for (cmd <- removed_commands) yield (cmd_before_change -> None)
+ val inserts =
+ for (cmd <- inserted_commands) yield (doc.commands.prev(cmd) -> Some(cmd))
+
+ return (doc, removes.toList ++ inserts)
+ }
+
+ val commands_offsets = {
+ var last_stop = 0
+ (for (c <- commands) yield {
+ val r = c -> (last_stop,c.stop(this))
+ last_stop = c.stop(this)
+ r
+ }).toArray
+ }
+
+ def command_at(pos: Int): Option[Command] =
+ find_command(pos, 0, commands_offsets.length)
+
+ // use a binary search to find commands for a given offset
+ private def find_command(pos: Int, array_start: Int, array_stop: Int): Option[Command] =
+ {
+ val middle_index = (array_start + array_stop) / 2
+ if (middle_index >= commands_offsets.length) return None
+ val (middle, (start, stop)) = commands_offsets(middle_index)
+ // does middle contain pos?
+ if (start <= pos && pos < stop)
+ Some(middle)
+ else if (start > pos)
+ find_command(pos, array_start, middle_index)
+ else if (stop <= pos)
+ find_command(pos, middle_index + 1, array_stop)
+ else error("impossible")
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/prover.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,175 @@
+/*
+ * Higher-level prover communication: interactive document model
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ * @author Makarius
+ */
+
+package isabelle.prover
+
+
+import scala.actors.Actor, Actor._
+
+import javax.swing.JTextArea
+
+import isabelle.jedit.Isabelle
+import isabelle.proofdocument.{ProofDocument, Change, Token}
+
+
+class Prover(system: Isabelle_System, logic: String)
+{
+ /* incoming messages */
+
+ private var prover_ready = false
+
+ private val receiver = new Actor {
+ def act() {
+ loop {
+ react {
+ case result: Isabelle_Process.Result => handle_result(result)
+ case change: Change if prover_ready => handle_change(change)
+ case bad if prover_ready => System.err.println("prover: ignoring bad message " + bad)
+ }
+ }
+ }
+ }
+
+ def input(change: Change) { receiver ! change }
+
+
+ /* outgoing messages */
+
+ val command_change = new Event_Bus[Command]
+ val document_change = new Event_Bus[ProofDocument]
+
+
+ /* prover process */
+
+ private val process =
+ new Isabelle_Process(system, receiver, "-m", "xsymbols", logic) with Isar_Document
+
+
+ /* outer syntax keywords and completion */
+
+ @volatile private var _command_decls = Map[String, String]()
+ def command_decls() = _command_decls
+
+ @volatile private var _keyword_decls = Set[String]()
+ def keyword_decls() = _keyword_decls
+
+ @volatile private var _completion = Isabelle.completion
+ def completion() = _completion
+
+
+ /* document state information */
+
+ @volatile private var states = Map[Isar_Document.State_ID, Command_State]()
+ @volatile private var commands = Map[Isar_Document.Command_ID, Command]()
+ val document_0 =
+ ProofDocument.empty.
+ set_command_keyword((s: String) => command_decls().contains(s))
+ @volatile private var document_versions = List(document_0)
+
+ def command(id: Isar_Document.Command_ID): Option[Command] = commands.get(id)
+ def document(id: Isar_Document.Document_ID): Option[ProofDocument] =
+ document_versions.find(_.id == id)
+
+
+ /* prover results */
+
+ val output_text_view = new JTextArea // FIXME separate jEdit component
+
+ private def handle_result(result: Isabelle_Process.Result)
+ {
+ // FIXME separate jEdit component
+ Swing_Thread.later { output_text_view.append(result.toString + "\n") }
+
+ val message = Isabelle_Process.parse_message(system, result)
+
+ val state =
+ Position.id_of(result.props) match {
+ case None => None
+ case Some(id) => commands.get(id) orElse states.get(id) orElse None
+ }
+ if (state.isDefined) state.get ! (this, message)
+ else if (result.kind == Isabelle_Process.Kind.STATUS) {
+ //{{{ global status message
+ message match {
+ case XML.Elem(Markup.MESSAGE, _, elems) =>
+ for (elem <- elems) {
+ elem match {
+ // document edits
+ case XML.Elem(Markup.EDITS, (Markup.ID, doc_id) :: _, edits) =>
+ document_versions.find(_.id == doc_id) match {
+ case Some(doc) =>
+ for {
+ XML.Elem(Markup.EDIT, (Markup.ID, cmd_id) :: (Markup.STATE, state_id) :: _, _)
+ <- edits }
+ {
+ commands.get(cmd_id) match {
+ case Some(cmd) =>
+ val state = new Command_State(cmd)
+ states += (state_id -> state)
+ doc.states += (cmd -> state)
+ command_change.event(cmd) // FIXME really!?
+ case None =>
+ }
+ }
+ case None =>
+ }
+
+ // command and keyword declarations
+ case XML.Elem(Markup.COMMAND_DECL, (Markup.NAME, name) :: (Markup.KIND, kind) :: _, _) =>
+ _command_decls += (name -> kind)
+ _completion += name
+ case XML.Elem(Markup.KEYWORD_DECL, (Markup.NAME, name) :: _, _) =>
+ _keyword_decls += name
+ _completion += name
+
+ // process ready (after initialization)
+ case XML.Elem(Markup.READY, _, _) => prover_ready = true
+
+ case _ =>
+ }
+ }
+ case _ =>
+ }
+ //}}}
+ }
+ }
+
+
+ /* document changes */
+
+ def begin_document(path: String) {
+ process.begin_document(document_0.id, path)
+ }
+
+ def handle_change(change: Change) {
+ val old = document(change.parent.get.id).get
+ val (doc, changes) = old.text_changed(change)
+ document_versions ::= doc
+
+ val id_changes = changes map { case (c1, c2) =>
+ (c1.map(_.id).getOrElse(document_0.id),
+ c2 match {
+ case None => None
+ case Some(command) =>
+ commands += (command.id -> command)
+ process.define_command(command.id, system.symbols.encode(command.content))
+ Some(command.id)
+ })
+ }
+ process.edit_document(old.id, doc.id, id_changes)
+
+ document_change.event(doc)
+ }
+
+
+ /* main controls */
+
+ def start() { receiver.start() }
+
+ def stop() { process.kill() }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/state.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,117 @@
+/*
+ * Accumulating results from prover
+ *
+ * @author Fabian Immler, TU Munich
+ * @author Makarius
+ */
+
+package isabelle.prover
+
+
+class State(
+ val command: Command,
+ val status: Command.Status.Value,
+ rev_results: List[XML.Tree],
+ val markup_root: Markup_Text)
+{
+ def this(command: Command) =
+ this(command, Command.Status.UNPROCESSED, Nil, command.empty_markup)
+
+
+ /* content */
+
+ private def set_status(st: Command.Status.Value): State =
+ new State(command, st, rev_results, markup_root)
+
+ private def add_result(res: XML.Tree): State =
+ new State(command, status, res :: rev_results, markup_root)
+
+ private def add_markup(node: Markup_Tree): State =
+ new State(command, status, rev_results, markup_root + node)
+
+ lazy val results = rev_results.reverse
+
+
+ /* markup */
+
+ lazy val highlight: Markup_Text =
+ {
+ markup_root.filter(_.info match {
+ case Command.HighlightInfo(_) => true
+ case _ => false
+ })
+ }
+
+ private lazy val types: List[Markup_Node] =
+ markup_root.filter(_.info match {
+ case Command.TypeInfo(_) => true
+ case _ => false }).flatten
+
+ def type_at(pos: Int): Option[String] =
+ {
+ types.find(t => t.start <= pos && pos < t.stop) match {
+ case Some(t) =>
+ t.info match {
+ case Command.TypeInfo(ty) => Some(command.content(t.start, t.stop) + ": " + ty)
+ case _ => None
+ }
+ case None => None
+ }
+ }
+
+ private lazy val refs: List[Markup_Node] =
+ markup_root.filter(_.info match {
+ case Command.RefInfo(_, _, _, _) => true
+ case _ => false }).flatten
+
+ def ref_at(pos: Int): Option[Markup_Node] =
+ refs.find(t => t.start <= pos && pos < t.stop)
+
+
+ /* message dispatch */
+
+ def + (prover: Prover, message: XML.Tree): State =
+ {
+ val changed: State =
+ message match {
+ case XML.Elem(Markup.MESSAGE, (Markup.CLASS, Markup.STATUS) :: _, elems) =>
+ (this /: elems)((state, elem) =>
+ elem match {
+ case XML.Elem(Markup.UNPROCESSED, _, _) => state.set_status(Command.Status.UNPROCESSED)
+ case XML.Elem(Markup.FINISHED, _, _) => state.set_status(Command.Status.FINISHED)
+ case XML.Elem(Markup.FAILED, _, _) => state.set_status(Command.Status.FAILED)
+ case XML.Elem(kind, atts, body) =>
+ val (begin, end) = Position.offsets_of(atts)
+ if (begin.isEmpty || end.isEmpty) state
+ else if (kind == Markup.ML_TYPING) {
+ val info = body.first.asInstanceOf[XML.Text].content // FIXME proper match!?
+ state.add_markup(
+ command.markup_node(begin.get - 1, end.get - 1, Command.TypeInfo(info)))
+ }
+ else if (kind == Markup.ML_REF) {
+ body match {
+ case List(XML.Elem(Markup.ML_DEF, atts, _)) =>
+ state.add_markup(command.markup_node(
+ begin.get - 1, end.get - 1,
+ Command.RefInfo(
+ Position.file_of(atts),
+ Position.line_of(atts),
+ Position.id_of(atts),
+ Position.offset_of(atts))))
+ case _ => state
+ }
+ }
+ else {
+ state.add_markup(
+ command.markup_node(begin.get - 1, end.get - 1, Command.HighlightInfo(kind)))
+ }
+ case _ =>
+ System.err.println("ignored status report: " + elem)
+ state
+ })
+ case _ => add_result(message)
+ }
+ if (!(this eq changed)) prover.command_change.event(command)
+ changed
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/theory_view.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,327 @@
+/*
+ * jEdit text area as document text source
+ *
+ * @author Fabian Immler, TU Munich
+ * @author Johannes Hölzl, TU Munich
+ * @author Makarius
+ */
+
+package isabelle.jedit
+
+import scala.actors.Actor, Actor._
+import scala.collection.mutable
+
+import isabelle.proofdocument.{ProofDocument, Change, Edit, Insert, Remove}
+import isabelle.prover.{Prover, Command}
+
+import java.awt.{Color, Graphics2D}
+import javax.swing.event.{CaretListener, CaretEvent}
+
+import org.gjt.sp.jedit.buffer.{BufferListener, JEditBuffer}
+import org.gjt.sp.jedit.textarea.{JEditTextArea, TextAreaExtension, TextAreaPainter}
+import org.gjt.sp.jedit.syntax.{ModeProvider, SyntaxStyle}
+
+
+object TheoryView
+{
+ def choose_color(command: Command, doc: ProofDocument): Color =
+ {
+ command.status(doc) match {
+ case Command.Status.UNPROCESSED => new Color(255, 228, 225)
+ case Command.Status.FINISHED => new Color(234, 248, 255)
+ case Command.Status.FAILED => new Color(255, 106, 106)
+ case _ => Color.red
+ }
+ }
+}
+
+
+class TheoryView(text_area: JEditTextArea)
+{
+ private val buffer = text_area.getBuffer
+
+
+ /* prover setup */
+
+ val prover: Prover = new Prover(Isabelle.system, Isabelle.default_logic())
+
+ prover.command_change += ((command: Command) =>
+ if (current_document().commands.contains(command))
+ Swing_Thread.later {
+ // FIXME proper handling of buffer vs. text areas
+ // repaint if buffer is active
+ if (text_area.getBuffer == buffer) {
+ update_syntax(command)
+ invalidate_line(command)
+ overview.repaint()
+ }
+ })
+
+
+ /* changes vs. edits */
+
+ private val change_0 = new Change(prover.document_0.id, None, Nil)
+ private var _changes = List(change_0) // owned by Swing/AWT thread
+ def changes = _changes
+ private var current_change = change_0
+
+ private val edits = new mutable.ListBuffer[Edit] // owned by Swing thread
+
+ private val edits_delay = Swing_Thread.delay_last(300) {
+ if (!edits.isEmpty) {
+ val change = new Change(Isabelle.system.id(), Some(current_change), edits.toList)
+ _changes ::= change
+ prover.input(change)
+ current_change = change
+ edits.clear
+ }
+ }
+
+
+ /* buffer_listener */
+
+ private val buffer_listener = new BufferListener {
+ override def preContentInserted(buffer: JEditBuffer,
+ start_line: Int, offset: Int, num_lines: Int, length: Int)
+ {
+ edits += Insert(offset, buffer.getText(offset, length))
+ edits_delay()
+ }
+
+ override def preContentRemoved(buffer: JEditBuffer,
+ start_line: Int, start: Int, num_lines: Int, removed_length: Int)
+ {
+ edits += Remove(start, buffer.getText(start, removed_length))
+ edits_delay()
+ }
+
+ override def contentInserted(buffer: JEditBuffer,
+ start_line: Int, offset: Int, num_lines: Int, length: Int) { }
+
+ override def contentRemoved(buffer: JEditBuffer,
+ start_line: Int, offset: Int, num_lines: Int, length: Int) { }
+
+ override def bufferLoaded(buffer: JEditBuffer) { }
+ override def foldHandlerChanged(buffer: JEditBuffer) { }
+ override def foldLevelChanged(buffer: JEditBuffer, start_line: Int, end_line: Int) { }
+ override def transactionComplete(buffer: JEditBuffer) { }
+ }
+
+
+ /* text_area_extension */
+
+ private val text_area_extension = new TextAreaExtension {
+ override def paintValidLine(gfx: Graphics2D,
+ screen_line: Int, physical_line: Int, start: Int, end: Int, y: Int)
+ {
+ val document = current_document()
+ def from_current(pos: Int) = TheoryView.this.from_current(document, pos)
+ def to_current(pos: Int) = TheoryView.this.to_current(document, pos)
+ val saved_color = gfx.getColor
+
+ val metrics = text_area.getPainter.getFontMetrics
+
+ // encolor phase
+ var cmd = document.command_at(from_current(start))
+ while (cmd.isDefined && cmd.get.start(document) < end) {
+ val e = cmd.get
+ val begin = start max to_current(e.start(document))
+ val finish = (end - 1) min to_current(e.stop(document))
+ encolor(gfx, y, metrics.getHeight, begin, finish,
+ TheoryView.choose_color(e, document), true)
+ cmd = document.commands.next(e)
+ }
+
+ gfx.setColor(saved_color)
+ }
+
+ override def getToolTipText(x: Int, y: Int): String =
+ {
+ val document = current_document()
+ val offset = from_current(document, text_area.xyToOffset(x, y))
+ document.command_at(offset) match {
+ case Some(cmd) =>
+ document.token_start(cmd.tokens.first)
+ cmd.type_at(document, offset - cmd.start(document)).getOrElse(null)
+ case None => null
+ }
+ }
+ }
+
+
+ /* activation */
+
+ private val overview = new Document_Overview(prover, text_area, to_current)
+
+ private val selected_state_controller = new CaretListener {
+ override def caretUpdate(e: CaretEvent) {
+ val doc = current_document()
+ doc.command_at(e.getDot) match {
+ case Some(cmd)
+ if (doc.token_start(cmd.tokens.first) <= e.getDot &&
+ Isabelle.plugin.selected_state != cmd) =>
+ Isabelle.plugin.selected_state = cmd
+ case _ =>
+ }
+ }
+ }
+
+ def activate() {
+ text_area.addCaretListener(selected_state_controller)
+ text_area.addLeftOfScrollBar(overview)
+ text_area.getPainter.
+ addExtension(TextAreaPainter.LINE_BACKGROUND_LAYER + 1, text_area_extension)
+ buffer.setTokenMarker(new DynamicTokenMarker(buffer, prover))
+ buffer.addBufferListener(buffer_listener)
+
+ val dockable =
+ text_area.getView.getDockableWindowManager.getDockable("isabelle-output")
+ if (dockable != null) {
+ val output_dockable = dockable.asInstanceOf[OutputDockable]
+ val output_text_view = prover.output_text_view
+ output_dockable.set_text(output_text_view)
+ }
+
+ buffer.propertiesChanged()
+ }
+
+ def deactivate() {
+ buffer.setTokenMarker(buffer.getMode.getTokenMarker)
+ buffer.removeBufferListener(buffer_listener)
+ text_area.getPainter.removeExtension(text_area_extension)
+ text_area.removeLeftOfScrollBar(overview)
+ text_area.removeCaretListener(selected_state_controller)
+ }
+
+
+ /* history of changes */
+
+ private def doc_or_pred(c: Change): ProofDocument =
+ prover.document(c.id).getOrElse(doc_or_pred(c.parent.get))
+
+ def current_document() = doc_or_pred(current_change)
+
+
+ /* update to desired version */
+
+ def set_version(goal: Change) {
+ // changes in buffer must be ignored
+ buffer.removeBufferListener(buffer_listener)
+
+ def apply(change: Change): Unit = change.edits.foreach {
+ case Insert(start, text) => buffer.insert(start, text)
+ case Remove(start, text) => buffer.remove(start, text.length)
+ }
+
+ def unapply(change: Change): Unit = change.edits.reverse.foreach {
+ case Insert(start, text) => buffer.remove(start, text.length)
+ case Remove(start, text) => buffer.insert(start, text)
+ }
+
+ // undo/redo changes
+ val ancs_current = current_change.ancestors
+ val ancs_goal = goal.ancestors
+ val paired = ancs_current.reverse zip ancs_goal.reverse
+ def last_common[A](xs: List[(A, A)]): Option[A] = {
+ xs match {
+ case (x, y) :: xs =>
+ if (x == y)
+ xs match {
+ case (a, b) :: ys =>
+ if (a == b) last_common(xs)
+ else Some(x)
+ case _ => Some(x)
+ }
+ else None
+ case _ => None
+ }
+ }
+ val common_anc = last_common(paired).get
+
+ ancs_current.takeWhile(_ != common_anc) map unapply
+ ancs_goal.takeWhile(_ != common_anc).reverse map apply
+
+ current_change = goal
+ // invoke repaint
+ buffer.propertiesChanged()
+ invalidate_all()
+ overview.repaint()
+
+ // track changes in buffer
+ buffer.addBufferListener(buffer_listener)
+ }
+
+
+ /* transforming offsets */
+
+ private def changes_from(doc: ProofDocument): List[Edit] =
+ List.flatten(current_change.ancestors(_.id == doc.id).reverse.map(_.edits)) :::
+ edits.toList
+
+ def from_current(doc: ProofDocument, offset: Int): Int =
+ (offset /: changes_from(doc).reverse) ((i, change) => change before i)
+
+ def to_current(doc: ProofDocument, offset: Int): Int =
+ (offset /: changes_from(doc)) ((i, change) => change after i)
+
+
+ private def lines_of_command(cmd: Command) =
+ {
+ val document = current_document()
+ (buffer.getLineOfOffset(to_current(document, cmd.start(document))),
+ buffer.getLineOfOffset(to_current(document, cmd.stop(document))))
+ }
+
+
+ /* (re)painting */
+
+ private val update_delay = Swing_Thread.delay_first(500) { buffer.propertiesChanged() }
+
+ private def update_syntax(cmd: Command) {
+ val (line1, line2) = lines_of_command(cmd)
+ if (line2 >= text_area.getFirstLine &&
+ line1 <= text_area.getFirstLine + text_area.getVisibleLines)
+ update_delay()
+ }
+
+ private def invalidate_line(cmd: Command) =
+ {
+ val (start, stop) = lines_of_command(cmd)
+ text_area.invalidateLineRange(start, stop)
+
+ if (Isabelle.plugin.selected_state == cmd)
+ Isabelle.plugin.selected_state = cmd // update State view
+ }
+
+ private def invalidate_all() =
+ text_area.invalidateLineRange(text_area.getFirstPhysicalLine,
+ text_area.getLastPhysicalLine)
+
+ private def encolor(gfx: Graphics2D,
+ y: Int, height: Int, begin: Int, finish: Int, color: Color, fill: Boolean)
+ {
+ val start = text_area.offsetToXY(begin)
+ val stop =
+ if (finish < buffer.getLength) text_area.offsetToXY(finish)
+ else {
+ val p = text_area.offsetToXY(finish - 1)
+ val metrics = text_area.getPainter.getFontMetrics
+ p.x = p.x + (metrics.charWidth(' ') max metrics.getMaxAdvance)
+ p
+ }
+
+ if (start != null && stop != null) {
+ gfx.setColor(color)
+ if (fill) gfx.fillRect(start.x, y, stop.x - start.x, height)
+ else gfx.drawRect(start.x, y, stop.x - start.x, height)
+ }
+ }
+
+
+ /* init */
+
+ prover.start()
+
+ edits += Insert(0, buffer.getText(0, buffer.getLength))
+ edits_delay()
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/proofdocument/token.scala Tue Dec 08 14:49:01 2009 +0100
@@ -0,0 +1,42 @@
+/*
+ * Document tokens as text ranges
+ *
+ * @author Johannes Hölzl, TU Munich
+ * @author Fabian Immler, TU Munich
+ */
+
+package isabelle.proofdocument
+
+
+import isabelle.prover.Command
+
+
+object Token {
+ object Kind extends Enumeration
+ {
+ val COMMAND_START = Value("COMMAND_START")
+ val COMMENT = Value("COMMENT")
+ val OTHER = Value("OTHER")
+ }
+
+ def string_from_tokens(tokens: List[Token], starts: Token => Int): String = {
+ def stop(t: Token) = starts(t) + t.length
+ tokens match {
+ case Nil => ""
+ case tok :: toks =>
+ val (res, _) = toks.foldLeft(tok.content, stop(tok))((a, token) =>
+ (a._1 + " " * (starts(token) - a._2) + token.content, stop(token)))
+ res
+ }
+ }
+
+}
+
+class Token(
+ val content: String,
+ val kind: Token.Kind.Value)
+{
+ override def toString = content
+ val length = content.length
+ val is_start = kind == Token.Kind.COMMAND_START || kind == Token.Kind.COMMENT
+}
--- a/src/Tools/jEdit/src/prover/Command.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * Prover commands with semantic state
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.prover
-
-
-import scala.actors.Actor, Actor._
-
-import scala.collection.mutable
-
-import isabelle.proofdocument.{Token, ProofDocument}
-import isabelle.jedit.{Isabelle, Plugin}
-import isabelle.XML
-
-
-trait Accumulator extends Actor
-{
- start() // start actor
-
- protected var _state: State
- def state = _state
-
- override def act() {
- loop {
- react {
- case (prover: Prover, message: XML.Tree) => _state = _state.+(prover, message)
- case bad => System.err.println("prover: ignoring bad message " + bad)
- }
- }
- }
-}
-
-
-object Command
-{
- object Status extends Enumeration
- {
- val UNPROCESSED = Value("UNPROCESSED")
- val FINISHED = Value("FINISHED")
- val FAILED = Value("FAILED")
- }
-
- case class HighlightInfo(highlight: String) { override def toString = highlight }
- case class TypeInfo(ty: String)
- case class RefInfo(file: Option[String], line: Option[Int],
- command_id: Option[String], offset: Option[Int])
-}
-
-
-class Command(
- val tokens: List[Token],
- val starts: Map[Token, Int]) extends Accumulator
-{
- require(!tokens.isEmpty)
-
- val id = Isabelle.system.id()
- override def hashCode = id.hashCode
-
-
- /* content */
-
- override def toString = name
-
- val name = tokens.head.content
- val content: String = Token.string_from_tokens(tokens, starts)
- def content(i: Int, j: Int): String = content.substring(i, j)
- val symbol_index = new Symbol.Index(content)
-
- def start(doc: ProofDocument) = doc.token_start(tokens.first)
- def stop(doc: ProofDocument) = doc.token_start(tokens.last) + tokens.last.length
-
- def contains(p: Token) = tokens.contains(p)
-
- protected override var _state = new State(this)
-
-
- /* markup */
-
- lazy val empty_markup = new Markup_Text(Nil, content)
-
- def markup_node(begin: Int, end: Int, info: Any): Markup_Tree =
- {
- val start = symbol_index.decode(begin)
- val stop = symbol_index.decode(end)
- new Markup_Tree(new Markup_Node(start, stop, info), Nil)
- }
-
-
- /* results, markup, ... */
-
- private val empty_cmd_state = new Command_State(this)
- private def cmd_state(doc: ProofDocument) =
- doc.states.getOrElse(this, empty_cmd_state)
-
- def status(doc: ProofDocument) = cmd_state(doc).state.status
- def results(doc: ProofDocument) = cmd_state(doc).results
- def markup_root(doc: ProofDocument) = cmd_state(doc).markup_root
- def highlight(doc: ProofDocument) = cmd_state(doc).highlight
- def type_at(doc: ProofDocument, offset: Int) = cmd_state(doc).type_at(offset)
- def ref_at(doc: ProofDocument, offset: Int) = cmd_state(doc).ref_at(offset)
-}
-
-
-class Command_State(val command: Command) extends Accumulator
-{
- protected override var _state = new State(command)
-
- def results: List[XML.Tree] =
- command.state.results ::: state.results
-
- def markup_root: Markup_Text =
- (command.state.markup_root /: state.markup_root.markup)(_ + _)
-
- def type_at(pos: Int): Option[String] = state.type_at(pos)
-
- def ref_at(pos: Int): Option[Markup_Node] = state.ref_at(pos)
-
- def highlight: Markup_Text =
- (command.state.highlight /: state.highlight.markup)(_ + _)
-}
\ No newline at end of file
--- a/src/Tools/jEdit/src/prover/MarkupNode.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/*
- * Document markup nodes, with connection to Swing tree model
- *
- * @author Fabian Immler, TU Munich
- */
-
-package isabelle.prover
-
-
-import javax.swing.tree.DefaultMutableTreeNode
-
-import isabelle.proofdocument.ProofDocument
-
-
-class Markup_Node(val start: Int, val stop: Int, val info: Any)
-{
- def fits_into(that: Markup_Node): Boolean =
- that.start <= this.start && this.stop <= that.stop
-}
-
-
-class Markup_Tree(val node: Markup_Node, val branches: List[Markup_Tree])
-{
- def set_branches(bs: List[Markup_Tree]): Markup_Tree = new Markup_Tree(node, bs)
-
- private def add(branch: Markup_Tree) = // FIXME avoid sort
- set_branches((branch :: branches) sort ((a, b) => a.node.start < b.node.start))
-
- private def remove(bs: List[Markup_Tree]) = set_branches(branches -- bs)
-
- def + (new_tree: Markup_Tree): Markup_Tree =
- {
- val new_node = new_tree.node
- if (new_node fits_into node) {
- var inserted = false
- val new_branches =
- branches.map(branch =>
- if ((new_node fits_into branch.node) && !inserted) {
- inserted = true
- branch + new_tree
- }
- else branch)
- if (!inserted) {
- // new_tree did not fit into children of this
- // -> insert between this and its branches
- val fitting = branches filter(_.node fits_into new_node)
- (this remove fitting) add ((new_tree /: fitting)(_ + _))
- }
- else set_branches(new_branches)
- }
- else {
- System.err.println("ignored nonfitting markup: " + new_node)
- this
- }
- }
-
- def flatten: List[Markup_Node] =
- {
- var next_x = node.start
- if (branches.isEmpty) List(this.node)
- else {
- val filled_gaps =
- for {
- child <- branches
- markups =
- if (next_x < child.node.start)
- new Markup_Node(next_x, child.node.start, node.info) :: child.flatten
- else child.flatten
- update = (next_x = child.node.stop)
- markup <- markups
- } yield markup
- if (next_x < node.stop)
- filled_gaps + new Markup_Node(next_x, node.stop, node.info)
- else filled_gaps
- }
- }
-}
-
-
-class Markup_Text(val markup: List[Markup_Tree], val content: String)
-{
- private lazy val root =
- new Markup_Tree(new Markup_Node(0, content.length, None), markup)
-
- def + (new_tree: Markup_Tree): Markup_Text =
- new Markup_Text((root + new_tree).branches, content)
-
- def filter(pred: Markup_Node => Boolean): Markup_Text =
- {
- def filt(tree: Markup_Tree): List[Markup_Tree] =
- {
- val branches = tree.branches.flatMap(filt(_))
- if (pred(tree.node)) List(tree.set_branches(branches))
- else branches
- }
- new Markup_Text(markup.flatMap(filt(_)), content)
- }
-
- def flatten: List[Markup_Node] = markup.flatten(_.flatten)
-
- def swing_tree(swing_node: Markup_Node => DefaultMutableTreeNode): DefaultMutableTreeNode =
- {
- def swing(tree: Markup_Tree): DefaultMutableTreeNode =
- {
- val node = swing_node(tree.node)
- tree.branches foreach ((branch: Markup_Tree) => node.add(swing(branch)))
- node
- }
- swing(root)
- }
-}
--- a/src/Tools/jEdit/src/prover/Prover.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-/*
- * Higher-level prover communication: interactive document model
- *
- * @author Johannes Hölzl, TU Munich
- * @author Fabian Immler, TU Munich
- * @author Makarius
- */
-
-package isabelle.prover
-
-
-import scala.actors.Actor, Actor._
-
-import javax.swing.JTextArea
-
-import isabelle.jedit.Isabelle
-import isabelle.proofdocument.{ProofDocument, Change, Token}
-
-
-class Prover(system: Isabelle_System, logic: String)
-{
- /* incoming messages */
-
- private var prover_ready = false
-
- private val receiver = new Actor {
- def act() {
- loop {
- react {
- case result: Isabelle_Process.Result => handle_result(result)
- case change: Change if prover_ready => handle_change(change)
- case bad if prover_ready => System.err.println("prover: ignoring bad message " + bad)
- }
- }
- }
- }
-
- def input(change: Change) { receiver ! change }
-
-
- /* outgoing messages */
-
- val command_change = new Event_Bus[Command]
- val document_change = new Event_Bus[ProofDocument]
-
-
- /* prover process */
-
- private val process =
- new Isabelle_Process(system, receiver, "-m", "xsymbols", logic) with Isar_Document
-
-
- /* outer syntax keywords and completion */
-
- @volatile private var _command_decls = Map[String, String]()
- def command_decls() = _command_decls
-
- @volatile private var _keyword_decls = Set[String]()
- def keyword_decls() = _keyword_decls
-
- @volatile private var _completion = Isabelle.completion
- def completion() = _completion
-
-
- /* document state information */
-
- @volatile private var states = Map[Isar_Document.State_ID, Command_State]()
- @volatile private var commands = Map[Isar_Document.Command_ID, Command]()
- val document_0 =
- ProofDocument.empty.
- set_command_keyword((s: String) => command_decls().contains(s))
- @volatile private var document_versions = List(document_0)
-
- def command(id: Isar_Document.Command_ID): Option[Command] = commands.get(id)
- def document(id: Isar_Document.Document_ID): Option[ProofDocument] =
- document_versions.find(_.id == id)
-
-
- /* prover results */
-
- val output_text_view = new JTextArea // FIXME separate jEdit component
-
- private def handle_result(result: Isabelle_Process.Result)
- {
- // FIXME separate jEdit component
- Swing_Thread.later { output_text_view.append(result.toString + "\n") }
-
- val message = Isabelle_Process.parse_message(system, result)
-
- val state =
- Position.id_of(result.props) match {
- case None => None
- case Some(id) => commands.get(id) orElse states.get(id) orElse None
- }
- if (state.isDefined) state.get ! (this, message)
- else if (result.kind == Isabelle_Process.Kind.STATUS) {
- //{{{ global status message
- message match {
- case XML.Elem(Markup.MESSAGE, _, elems) =>
- for (elem <- elems) {
- elem match {
- // document edits
- case XML.Elem(Markup.EDITS, (Markup.ID, doc_id) :: _, edits) =>
- document_versions.find(_.id == doc_id) match {
- case Some(doc) =>
- for {
- XML.Elem(Markup.EDIT, (Markup.ID, cmd_id) :: (Markup.STATE, state_id) :: _, _)
- <- edits }
- {
- commands.get(cmd_id) match {
- case Some(cmd) =>
- val state = new Command_State(cmd)
- states += (state_id -> state)
- doc.states += (cmd -> state)
- command_change.event(cmd) // FIXME really!?
- case None =>
- }
- }
- case None =>
- }
-
- // command and keyword declarations
- case XML.Elem(Markup.COMMAND_DECL, (Markup.NAME, name) :: (Markup.KIND, kind) :: _, _) =>
- _command_decls += (name -> kind)
- _completion += name
- case XML.Elem(Markup.KEYWORD_DECL, (Markup.NAME, name) :: _, _) =>
- _keyword_decls += name
- _completion += name
-
- // process ready (after initialization)
- case XML.Elem(Markup.READY, _, _) => prover_ready = true
-
- case _ =>
- }
- }
- case _ =>
- }
- //}}}
- }
- }
-
-
- /* document changes */
-
- def begin_document(path: String) {
- process.begin_document(document_0.id, path)
- }
-
- def handle_change(change: Change) {
- val old = document(change.parent.get.id).get
- val (doc, changes) = old.text_changed(change)
- document_versions ::= doc
-
- val id_changes = changes map { case (c1, c2) =>
- (c1.map(_.id).getOrElse(document_0.id),
- c2 match {
- case None => None
- case Some(command) =>
- commands += (command.id -> command)
- process.define_command(command.id, system.symbols.encode(command.content))
- Some(command.id)
- })
- }
- process.edit_document(old.id, doc.id, id_changes)
-
- document_change.event(doc)
- }
-
-
- /* main controls */
-
- def start() { receiver.start() }
-
- def stop() { process.kill() }
-}
--- a/src/Tools/jEdit/src/prover/State.scala Tue Dec 08 14:29:29 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Accumulating results from prover
- *
- * @author Fabian Immler, TU Munich
- * @author Makarius
- */
-
-package isabelle.prover
-
-
-class State(
- val command: Command,
- val status: Command.Status.Value,
- rev_results: List[XML.Tree],
- val markup_root: Markup_Text)
-{
- def this(command: Command) =
- this(command, Command.Status.UNPROCESSED, Nil, command.empty_markup)
-
-
- /* content */
-
- private def set_status(st: Command.Status.Value): State =
- new State(command, st, rev_results, markup_root)
-
- private def add_result(res: XML.Tree): State =
- new State(command, status, res :: rev_results, markup_root)
-
- private def add_markup(node: Markup_Tree): State =
- new State(command, status, rev_results, markup_root + node)
-
- lazy val results = rev_results.reverse
-
-
- /* markup */
-
- lazy val highlight: Markup_Text =
- {
- markup_root.filter(_.info match {
- case Command.HighlightInfo(_) => true
- case _ => false
- })
- }
-
- private lazy val types: List[Markup_Node] =
- markup_root.filter(_.info match {
- case Command.TypeInfo(_) => true
- case _ => false }).flatten
-
- def type_at(pos: Int): Option[String] =
- {
- types.find(t => t.start <= pos && pos < t.stop) match {
- case Some(t) =>
- t.info match {
- case Command.TypeInfo(ty) => Some(command.content(t.start, t.stop) + ": " + ty)
- case _ => None
- }
- case None => None
- }
- }
-
- private lazy val refs: List[Markup_Node] =
- markup_root.filter(_.info match {
- case Command.RefInfo(_, _, _, _) => true
- case _ => false }).flatten
-
- def ref_at(pos: Int): Option[Markup_Node] =
- refs.find(t => t.start <= pos && pos < t.stop)
-
-
- /* message dispatch */
-
- def + (prover: Prover, message: XML.Tree): State =
- {
- val changed: State =
- message match {
- case XML.Elem(Markup.MESSAGE, (Markup.CLASS, Markup.STATUS) :: _, elems) =>
- (this /: elems)((state, elem) =>
- elem match {
- case XML.Elem(Markup.UNPROCESSED, _, _) => state.set_status(Command.Status.UNPROCESSED)
- case XML.Elem(Markup.FINISHED, _, _) => state.set_status(Command.Status.FINISHED)
- case XML.Elem(Markup.FAILED, _, _) => state.set_status(Command.Status.FAILED)
- case XML.Elem(kind, atts, body) =>
- val (begin, end) = Position.offsets_of(atts)
- if (begin.isEmpty || end.isEmpty) state
- else if (kind == Markup.ML_TYPING) {
- val info = body.first.asInstanceOf[XML.Text].content // FIXME proper match!?
- state.add_markup(
- command.markup_node(begin.get - 1, end.get - 1, Command.TypeInfo(info)))
- }
- else if (kind == Markup.ML_REF) {
- body match {
- case List(XML.Elem(Markup.ML_DEF, atts, _)) =>
- state.add_markup(command.markup_node(
- begin.get - 1, end.get - 1,
- Command.RefInfo(
- Position.file_of(atts),
- Position.line_of(atts),
- Position.id_of(atts),
- Position.offset_of(atts))))
- case _ => state
- }
- }
- else {
- state.add_markup(
- command.markup_node(begin.get - 1, end.get - 1, Command.HighlightInfo(kind)))
- }
- case _ =>
- System.err.println("ignored status report: " + elem)
- state
- })
- case _ => add_result(message)
- }
- if (!(this eq changed)) prover.command_change.event(command)
- changed
- }
-}