slightly more general support for one-shot query operations via asynchronous print functions and temporary document overlay;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/PIDE/query_operation.ML Mon Aug 05 17:14:02 2013 +0200
@@ -0,0 +1,30 @@
+(* Title: Pure/PIDE/query_operation.ML
+ Author: Makarius
+
+One-shot query operations via asynchronous print functions and temporary
+document overlay.
+*)
+
+signature QUERY_OPERATION =
+sig
+ val register: string -> (Toplevel.state -> string list -> string) -> unit
+end;
+
+structure Query_Operation: QUERY_OPERATION =
+struct
+
+fun register name f =
+ Command.print_function name
+ (fn {args = instance :: args, ...} =>
+ SOME {delay = NONE, pri = 0, persistent = false,
+ print_fn = fn _ => fn state =>
+ let
+ val msg = XML.Elem ((Markup.writelnN, []), [XML.Text (f state args)])
+ handle exn =>
+ if Exn.is_interrupt exn then reraise exn
+ else XML.Elem ((Markup.errorN, []), [XML.Text (ML_Compiler.exn_message exn)]);
+ in Output.result [(Markup.instanceN, instance)] (YXML.string_of msg) end}
+ | _ => NONE);
+
+end;
+
--- a/src/Pure/ROOT Mon Aug 05 16:12:03 2013 +0200
+++ b/src/Pure/ROOT Mon Aug 05 17:14:02 2013 +0200
@@ -158,6 +158,7 @@
"PIDE/execution.ML"
"PIDE/markup.ML"
"PIDE/protocol.ML"
+ "PIDE/query_operation.ML"
"PIDE/xml.ML"
"PIDE/yxml.ML"
"Proof/extraction.ML"
--- a/src/Pure/ROOT.ML Mon Aug 05 16:12:03 2013 +0200
+++ b/src/Pure/ROOT.ML Mon Aug 05 17:14:02 2013 +0200
@@ -269,6 +269,7 @@
use "Thy/present.ML";
use "PIDE/execution.ML";
use "PIDE/command.ML";
+use "PIDE/query_operation.ML";
use "Thy/thy_load.ML";
use "Thy/thy_info.ML";
use "PIDE/document.ML";
--- a/src/Pure/Tools/find_theorems.ML Mon Aug 05 16:12:03 2013 +0200
+++ b/src/Pure/Tools/find_theorems.ML Mon Aug 05 17:14:02 2013 +0200
@@ -605,7 +605,7 @@
-(** command syntax **)
+(** Isar command syntax **)
local
@@ -647,28 +647,10 @@
-(** print function **)
-
-val find_theoremsN = "find_theorems";
+(** PIDE query operation **)
-val _ = Command.print_function find_theoremsN
- (fn {args, ...} =>
- (case args of
- [instance, query] =>
- SOME {delay = NONE, pri = 0, persistent = false,
- print_fn = fn _ => fn state =>
- let
- val msg =
- XML.Elem ((Markup.writelnN, []),
- [XML.Text
- (Pretty.string_of (pretty_theorems_cmd state NONE false (parse_query query)))])
- handle exn =>
- if Exn.is_interrupt exn then reraise exn
- else XML.Elem ((Markup.errorN, []), [XML.Text (ML_Compiler.exn_message exn)]);
- in
- Output.result [(Markup.kindN, find_theoremsN), (Markup.instanceN, instance)]
- (YXML.string_of msg)
- end}
- | _ => NONE));
+val _ =
+ Query_Operation.register "find_theorems" (fn state => fn query =>
+ Pretty.string_of (pretty_theorems_cmd state NONE false (maps parse_query query)));
end;
--- a/src/Tools/jEdit/lib/Tools/jedit Mon Aug 05 16:12:03 2013 +0200
+++ b/src/Tools/jEdit/lib/Tools/jedit Mon Aug 05 17:14:02 2013 +0200
@@ -35,6 +35,7 @@
"src/pretty_text_area.scala"
"src/pretty_tooltip.scala"
"src/protocol_dockable.scala"
+ "src/query_operation.scala"
"src/raw_output_dockable.scala"
"src/readme_dockable.scala"
"src/rendering.scala"
--- a/src/Tools/jEdit/src/find_dockable.scala Mon Aug 05 16:12:03 2013 +0200
+++ b/src/Tools/jEdit/src/find_dockable.scala Mon Aug 05 17:14:02 2013 +0200
@@ -25,27 +25,22 @@
{
Swing_Thread.require()
-
- /* component state -- owned by Swing thread */
-
- private val FIND_THEOREMS = "find_theorems"
- private val instance = Document_ID.make().toString
-
- private var zoom_factor = 100
- private var current_location: Option[Command] = None
- private var current_query: String = ""
- private var current_result = false
- private var current_snapshot = Document.State.init.snapshot()
- private var current_state = Command.empty.init_state
- private var current_output: List[XML.Tree] = Nil
-
-
- /* pretty text area */
-
val pretty_text_area = new Pretty_Text_Area(view)
set_content(pretty_text_area)
+ /* query operation */
+
+ private val find_theorems =
+ Query_Operation(view, "find_theorems",
+ (snapshot, results, body) =>
+ pretty_text_area.update(snapshot, results, Pretty.separate(body)))
+
+
+ /* resize */
+
+ private var zoom_factor = 100
+
private def handle_resize()
{
Swing_Thread.require()
@@ -54,98 +49,12 @@
(Rendering.font_size("jedit_font_scale") * zoom_factor / 100).round)
}
- private def remove_overlay()
- {
- Swing_Thread.require()
-
- for {
- command <- current_location
- buffer <- JEdit_Lib.jedit_buffer(command.node_name.node)
- model <- PIDE.document_model(buffer)
- } model.remove_overlay(command, FIND_THEOREMS, List(instance, current_query))
- }
-
- private def handle_update()
- {
- Swing_Thread.require()
-
- val (new_snapshot, new_state) =
- Document_View(view.getTextArea) match {
- case Some(doc_view) =>
- val snapshot = doc_view.model.snapshot()
- if (!snapshot.is_outdated) {
- current_location match {
- case Some(cmd) =>
- (snapshot, snapshot.state.command_state(snapshot.version, cmd))
- case None =>
- (Document.State.init.snapshot(), Command.empty.init_state)
- }
- }
- else (current_snapshot, current_state)
- case None => (current_snapshot, current_state)
- }
-
- val new_output =
- (for {
- (_, XML.Elem(Markup(Markup.RESULT, props), List(XML.Elem(markup, body)))) <-
- new_state.results.entries
- if props.contains((Markup.KIND, FIND_THEOREMS))
- if props.contains((Markup.INSTANCE, instance))
- } yield XML.Elem(Markup(Markup.message(markup.name), markup.properties), body)).toList
-
- if (new_output != current_output)
- pretty_text_area.update(new_snapshot, new_state.results, Pretty.separate(new_output))
+ private val delay_resize =
+ Swing_Thread.delay_first(PIDE.options.seconds("editor_update_delay")) { handle_resize() }
- if (!new_output.isEmpty) {
- current_result = true
- remove_overlay()
- PIDE.flush_buffers()
- }
-
- current_snapshot = new_snapshot
- current_state = new_state
- current_output = new_output
- }
-
- private def apply_query(query: String)
- {
- Swing_Thread.require()
-
- Document_View(view.getTextArea) match {
- case Some(doc_view) =>
- val snapshot = doc_view.model.snapshot()
- remove_overlay()
- current_location = None
- current_query = ""
- current_result = false
- snapshot.node.command_at(doc_view.text_area.getCaretPosition).map(_._1) match {
- case Some(command) =>
- current_location = Some(command)
- current_query = query
- doc_view.model.insert_overlay(command, FIND_THEOREMS, List(instance, query))
- case None =>
- }
- PIDE.flush_buffers()
- case None =>
- }
- }
-
- private def locate_query()
- {
- Swing_Thread.require()
-
- current_location match {
- case Some(command) =>
- val snapshot = PIDE.session.snapshot(command.node_name)
- val commands = snapshot.node.commands
- if (commands.contains(command)) {
- val sources = commands.iterator.takeWhile(_ != command).map(_.source)
- val (line, column) = ((1, 1) /: sources)(Symbol.advance_line_column)
- Hyperlink(command.node_name.node, line, column).follow(view)
- }
- case None =>
- }
- }
+ addComponentListener(new ComponentAdapter {
+ override def componentResized(e: ComponentEvent) { delay_resize.invoke() }
+ })
/* main actor */
@@ -155,12 +64,6 @@
react {
case _: Session.Global_Options =>
Swing_Thread.later { handle_resize() }
- case changed: Session.Commands_Changed =>
- current_location match {
- case Some(command) if !current_result && changed.commands.contains(command) =>
- Swing_Thread.later { handle_update() }
- case _ =>
- }
case bad =>
java.lang.System.err.println("Find_Dockable: ignoring bad message " + bad)
}
@@ -172,30 +75,20 @@
Swing_Thread.require()
PIDE.session.global_options += main_actor
- PIDE.session.commands_changed += main_actor
handle_resize()
+ find_theorems.activate()
}
override def exit()
{
Swing_Thread.require()
+ find_theorems.deactivate()
PIDE.session.global_options -= main_actor
- PIDE.session.commands_changed -= main_actor
delay_resize.revoke()
}
- /* resize */
-
- private val delay_resize =
- Swing_Thread.delay_first(PIDE.options.seconds("editor_update_delay")) { handle_resize() }
-
- addComponentListener(new ComponentAdapter {
- override def componentResized(e: ComponentEvent) { delay_resize.invoke() }
- })
-
-
/* controls */
private val query = new HistoryTextArea("isabelle-find-theorems") {
@@ -208,12 +101,12 @@
private val find = new Button("Find") {
tooltip = "Find theorems meeting specified criteria"
- reactions += { case ButtonClicked(_) => apply_query(query.getText) }
+ reactions += { case ButtonClicked(_) => find_theorems.apply_query(List(query.getText)) }
}
private val locate = new Button("Locate") {
tooltip = "Locate context of current query within source text"
- reactions += { case ButtonClicked(_) => locate_query() }
+ reactions += { case ButtonClicked(_) => find_theorems.locate_query() }
}
private val zoom = new GUI.Zoom_Box(factor => { zoom_factor = factor; handle_resize() }) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tools/jEdit/src/query_operation.scala Mon Aug 05 17:14:02 2013 +0200
@@ -0,0 +1,153 @@
+/* Title: Tools/jEdit/src/query_operation.scala
+ Author: Makarius
+
+One-shot query operations via asynchronous print functions and temporary
+document overlay.
+*/
+
+package isabelle.jedit
+
+
+import isabelle._
+
+import scala.actors.Actor._
+
+import org.gjt.sp.jedit.View
+
+
+object Query_Operation
+{
+ def apply(
+ view: View,
+ name: String,
+ consume: (Document.Snapshot, Command.Results, XML.Body) => Unit) =
+ new Query_Operation(view, name, consume)
+}
+
+final class Query_Operation private(
+ view: View,
+ operation_name: String,
+ consume_result: (Document.Snapshot, Command.Results, XML.Body) => Unit)
+{
+ private val instance = Document_ID.make().toString
+
+
+ /* implicit state -- owned by Swing thread */
+
+ private var current_location: Option[Command] = None
+ private var current_query: List[String] = Nil
+ private var current_result = false
+ private var current_snapshot = Document.State.init.snapshot()
+ private var current_state = Command.empty.init_state
+ private var current_output: List[XML.Tree] = Nil
+
+ private def remove_overlay()
+ {
+ Swing_Thread.require()
+
+ for {
+ command <- current_location
+ buffer <- JEdit_Lib.jedit_buffer(command.node_name.node)
+ model <- PIDE.document_model(buffer)
+ } model.remove_overlay(command, operation_name, instance :: current_query)
+ }
+
+ private def handle_result()
+ {
+ Swing_Thread.require()
+
+ val (new_snapshot, new_state) =
+ Document_View(view.getTextArea) match {
+ case Some(doc_view) =>
+ val snapshot = doc_view.model.snapshot()
+ current_location match {
+ case Some(cmd) =>
+ (snapshot, snapshot.state.command_state(snapshot.version, cmd))
+ case None =>
+ (Document.State.init.snapshot(), Command.empty.init_state)
+ }
+ case None => (current_snapshot, current_state)
+ }
+
+ val new_output =
+ (for {
+ (_, XML.Elem(Markup(Markup.RESULT, props), List(XML.Elem(markup, body)))) <-
+ new_state.results.entries
+ if props.contains((Markup.INSTANCE, instance))
+ } yield XML.Elem(Markup(Markup.message(markup.name), markup.properties), body)).toList
+
+ if (new_output != current_output)
+ consume_result(new_snapshot, new_state.results, new_output)
+
+ if (!new_output.isEmpty) {
+ current_result = true
+ remove_overlay()
+ PIDE.flush_buffers()
+ }
+
+ current_snapshot = new_snapshot
+ current_state = new_state
+ current_output = new_output
+ }
+
+ def apply_query(query: List[String])
+ {
+ Swing_Thread.require()
+
+ Document_View(view.getTextArea) match {
+ case Some(doc_view) =>
+ val snapshot = doc_view.model.snapshot()
+ remove_overlay()
+ current_location = None
+ current_query = Nil
+ current_result = false
+ snapshot.node.command_at(doc_view.text_area.getCaretPosition).map(_._1) match {
+ case Some(command) =>
+ current_location = Some(command)
+ current_query = query
+ doc_view.model.insert_overlay(command, operation_name, instance :: query)
+ case None =>
+ }
+ PIDE.flush_buffers()
+ case None =>
+ }
+ }
+
+ def locate_query()
+ {
+ Swing_Thread.require()
+
+ current_location match {
+ case Some(command) =>
+ val snapshot = PIDE.session.snapshot(command.node_name)
+ val commands = snapshot.node.commands
+ if (commands.contains(command)) {
+ val sources = commands.iterator.takeWhile(_ != command).map(_.source)
+ val (line, column) = ((1, 1) /: sources)(Symbol.advance_line_column)
+ Hyperlink(command.node_name.node, line, column).follow(view)
+ }
+ case None =>
+ }
+ }
+
+
+ /* main actor */
+
+ private val main_actor = actor {
+ loop {
+ react {
+ case changed: Session.Commands_Changed =>
+ current_location match {
+ case Some(command) if !current_result && changed.commands.contains(command) =>
+ Swing_Thread.later { handle_result() }
+ case _ =>
+ }
+ case bad =>
+ java.lang.System.err.println("Query_Operation: ignoring bad message " + bad)
+ }
+ }
+ }
+
+ def activate() { PIDE.session.commands_changed += main_actor }
+ def deactivate() { PIDE.session.commands_changed -= main_actor }
+}