| author | wenzelm | 
| Mon, 06 Apr 2020 13:40:44 +0200 | |
| changeset 71705 | 7b75d52a1bf1 | 
| parent 71476 | ecefde4f9103 | 
| child 71774 | 491f185fd705 | 
| permissions | -rw-r--r-- | 
| 66098 | 1 | /* Title: Tools/VSCode/src/state_panel.scala | 
| 66096 | 2 | Author: Makarius | 
| 3 | ||
| 4 | Show proof state. | |
| 5 | */ | |
| 6 | ||
| 7 | package isabelle.vscode | |
| 8 | ||
| 9 | ||
| 10 | import isabelle._ | |
| 70302 | 11 | import isabelle.vscode.{Protocol, Server}
 | 
| 66096 | 12 | |
| 13 | ||
| 66098 | 14 | object State_Panel | 
| 66096 | 15 | {
 | 
| 16 | private val make_id = Counter.make() | |
| 66098 | 17 | private val instances = Synchronized(Map.empty[Counter.ID, State_Panel]) | 
| 66096 | 18 | |
| 19 | def init(server: Server) | |
| 20 |   {
 | |
| 66098 | 21 | val instance = new State_Panel(server) | 
| 66096 | 22 | instances.change(_ + (instance.id -> instance)) | 
| 23 | instance.init() | |
| 24 | } | |
| 25 | ||
| 26 | def exit(id: Counter.ID) | |
| 27 |   {
 | |
| 28 | instances.change(map => | |
| 29 |       map.get(id) match {
 | |
| 30 | case None => map | |
| 31 | case Some(instance) => instance.exit(); map - id | |
| 32 | }) | |
| 33 | } | |
| 34 | ||
| 35 | def locate(id: Counter.ID): Unit = | |
| 36 | instances.value.get(id).foreach(state => | |
| 37 | state.server.editor.send_dispatcher(state.locate())) | |
| 38 | ||
| 39 | def update(id: Counter.ID): Unit = | |
| 40 | instances.value.get(id).foreach(state => | |
| 41 | state.server.editor.send_dispatcher(state.update())) | |
| 66211 | 42 | |
| 43 | def auto_update(id: Counter.ID, enabled: Boolean): Unit = | |
| 44 | instances.value.get(id).foreach(state => | |
| 45 | state.server.editor.send_dispatcher(state.auto_update(Some(enabled)))) | |
| 66096 | 46 | } | 
| 47 | ||
| 48 | ||
| 66098 | 49 | class State_Panel private(val server: Server) | 
| 66096 | 50 | {
 | 
| 51 | /* output */ | |
| 52 | ||
| 66098 | 53 | val id: Counter.ID = State_Panel.make_id() | 
| 66096 | 54 | |
| 55 | private def output(content: String): Unit = | |
| 56 | server.channel.write(Protocol.State_Output(id, content)) | |
| 57 | ||
| 58 | ||
| 59 | /* query operation */ | |
| 60 | ||
| 66397 | 61 | private val output_active = Synchronized(true) | 
| 62 | ||
| 66096 | 63 | private val print_state = | 
| 64 | new Query_Operation(server.editor, (), "print_state", _ => (), | |
| 65 | (snapshot, results, body) => | |
| 66397 | 66 |         if (output_active.value) {
 | 
| 66096 | 67 | val text = server.resources.output_pretty_message(Pretty.separate(body)) | 
| 68 | val content = | |
| 69 | HTML.output_document( | |
| 70 | List(HTML.style(HTML.fonts_css()), | |
| 66212 | 71 | HTML.style_file(HTML.isabelle_css), | 
| 66211 | 72 | HTML.script(controls_script)), | 
| 66201 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 73 | List(controls, HTML.source(text)), | 
| 67337 
4254cfd15b00
more tight HTML output: avoid extra lines within <pre>;
 wenzelm parents: 
66397diff
changeset | 74 | css = "", structural = true) | 
| 66096 | 75 | output(content) | 
| 76 | }) | |
| 77 | ||
| 78 |   def locate() { print_state.locate_query() }
 | |
| 79 | ||
| 80 | def update() | |
| 81 |   {
 | |
| 82 |     server.editor.current_node_snapshot(()) match {
 | |
| 83 | case Some(snapshot) => | |
| 84 |         (server.editor.current_command((), snapshot), print_state.get_location) match {
 | |
| 85 | case (Some(command1), Some(command2)) if command1.id == command2.id => | |
| 86 | case _ => print_state.apply_query(Nil) | |
| 87 | } | |
| 88 | case None => | |
| 89 | } | |
| 90 | } | |
| 91 | ||
| 92 | ||
| 93 | /* auto update */ | |
| 94 | ||
| 95 | private val auto_update_enabled = Synchronized(true) | |
| 96 | ||
| 66211 | 97 | def auto_update(set: Option[Boolean] = None) | 
| 98 |   {
 | |
| 99 | val enabled = | |
| 100 | auto_update_enabled.guarded_access(a => | |
| 101 |         set match {
 | |
| 102 | case None => Some((a, a)) | |
| 103 | case Some(b) => Some((b, b)) | |
| 104 | }) | |
| 105 | if (enabled) update() | |
| 106 | } | |
| 66096 | 107 | |
| 108 | ||
| 66201 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 109 | /* controls */ | 
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 110 | |
| 66211 | 111 | private def controls_script = | 
| 112 | """ | |
| 71476 
ecefde4f9103
proper message passing -- discontinued obsolete auxiliary commands;
 wenzelm parents: 
70302diff
changeset | 113 | const vscode = acquireVsCodeApi(); | 
| 
ecefde4f9103
proper message passing -- discontinued obsolete auxiliary commands;
 wenzelm parents: 
70302diff
changeset | 114 | |
| 66211 | 115 | function invoke_auto_update(enabled) | 
| 71476 
ecefde4f9103
proper message passing -- discontinued obsolete auxiliary commands;
 wenzelm parents: 
70302diff
changeset | 116 | { vscode.postMessage({'command': 'auto_update', 'enabled': enabled}) }
 | 
| 66211 | 117 | |
| 71476 
ecefde4f9103
proper message passing -- discontinued obsolete auxiliary commands;
 wenzelm parents: 
70302diff
changeset | 118 | function invoke_update() | 
| 
ecefde4f9103
proper message passing -- discontinued obsolete auxiliary commands;
 wenzelm parents: 
70302diff
changeset | 119 | { vscode.postMessage({'command': 'update'}) }
 | 
| 66211 | 120 | |
| 71476 
ecefde4f9103
proper message passing -- discontinued obsolete auxiliary commands;
 wenzelm parents: 
70302diff
changeset | 121 | function invoke_locate() | 
| 
ecefde4f9103
proper message passing -- discontinued obsolete auxiliary commands;
 wenzelm parents: 
70302diff
changeset | 122 | { vscode.postMessage({'command': 'locate'}) }
 | 
| 66211 | 123 | """ | 
| 66201 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 124 | |
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 125 | private def auto_update_button: XML.Elem = | 
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 126 |     HTML.GUI.checkbox(HTML.text("Auto update"),
 | 
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 127 | name = "auto_update", | 
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 128 | tooltip = "Indicate automatic update following cursor movement", | 
| 66211 | 129 | selected = auto_update_enabled.value, | 
| 130 | script = "invoke_auto_update(this.checked)") | |
| 66201 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 131 | |
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 132 | private def update_button: XML.Elem = | 
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 133 |     HTML.GUI.button(List(HTML.bold(HTML.text("Update"))),
 | 
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 134 | name = "update", | 
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 135 | tooltip = "Update display according to the command at cursor position", | 
| 66211 | 136 | script = "invoke_update()") | 
| 66201 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 137 | |
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 138 | private def locate_button: XML.Elem = | 
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 139 |     HTML.GUI.button(HTML.text("Locate"),
 | 
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 140 | name = "locate", | 
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 141 | tooltip = "Locate printed command within source text", | 
| 66211 | 142 | script = "invoke_locate()") | 
| 66201 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 143 | |
| 66213 
9380ec9babfb
proper dynamic controls, notably for auto_update_enabled;
 wenzelm parents: 
66212diff
changeset | 144 | private def controls: XML.Elem = | 
| 66211 | 145 | HTML.Wrap_Panel(List(auto_update_button, update_button, locate_button)) | 
| 66201 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 146 | |
| 
d8f2c745f572
GUI controls similar to Tools/jEdit/src/state_dockable.scala;
 wenzelm parents: 
66099diff
changeset | 147 | |
| 66096 | 148 | /* main */ | 
| 149 | ||
| 150 | private val main = | |
| 151 |     Session.Consumer[Any](getClass.getName) {
 | |
| 66099 | 152 | case changed: Session.Commands_Changed => | 
| 153 | if (changed.assignment) auto_update() | |
| 154 | ||
| 155 | case Session.Caret_Focus => | |
| 156 | auto_update() | |
| 66096 | 157 | } | 
| 158 | ||
| 159 | def init() | |
| 160 |   {
 | |
| 161 | server.session.commands_changed += main | |
| 162 | server.session.caret_focus += main | |
| 163 |     server.editor.send_wait_dispatcher { print_state.activate() }
 | |
| 164 |     server.editor.send_dispatcher { auto_update() }
 | |
| 165 | } | |
| 166 | ||
| 167 | def exit() | |
| 168 |   {
 | |
| 66397 | 169 | output_active.change(_ => false) | 
| 66096 | 170 | server.session.commands_changed -= main | 
| 171 | server.session.caret_focus -= main | |
| 66397 | 172 |     server.editor.send_wait_dispatcher { print_state.deactivate() }
 | 
| 66096 | 173 | } | 
| 174 | } |