author | wenzelm |
Wed, 02 Apr 2025 23:18:12 +0200 | |
changeset 82418 | 6898054035d6 |
parent 81657 | 4210fd10e776 |
permissions | -rw-r--r-- |
50143
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
1 |
/* Title: Tools/jEdit/src/symbols_dockable.scala |
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
2 |
Author: Fabian Immler |
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
3 |
|
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
4 |
Dockable window for Symbol Palette. |
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
5 |
*/ |
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
6 |
|
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
7 |
package isabelle.jedit |
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
8 |
|
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
9 |
|
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
10 |
import isabelle._ |
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
11 |
|
56755 | 12 |
import scala.swing.event.{SelectionChanged, ValueChanged} |
63874 | 13 |
import scala.swing.{Component, Action, Button, TabbedPane, TextField, BorderPanel, |
14 |
Label, ScrollPane} |
|
50143
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
15 |
|
63872 | 16 |
import org.gjt.sp.jedit.{EditBus, EBComponent, EBMessage, View} |
50299 | 17 |
|
18 |
||
75393 | 19 |
class Symbols_Dockable(view: View, position: String) extends Dockable(view, position) { |
63870 | 20 |
private def font_size: Int = |
81381 | 21 |
Font_Info.main_size(scale = PIDE.options.real("jedit_font_scale")).round |
63870 | 22 |
|
63872 | 23 |
|
63877 | 24 |
/* abbrevs */ |
63872 | 25 |
|
26 |
private val abbrevs_panel = new Abbrevs_Panel |
|
27 |
||
28 |
private val abbrevs_refresh_delay = |
|
76610 | 29 |
Delay.last(PIDE.session.update_delay, gui = true) { abbrevs_panel.refresh() } |
63872 | 30 |
|
75393 | 31 |
private class Abbrev_Component(txt: String, abbrs: List[String]) extends Button { |
75200
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
32 |
def update_font(): Unit = { font = GUI.font(size = font_size) } |
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
33 |
update_font() |
63874 | 34 |
|
81657 | 35 |
text = GUI.Style_HTML.enclose_text(Symbol.decode(txt)) |
63870 | 36 |
action = |
37 |
Action(text) { |
|
38 |
val text_area = view.getTextArea |
|
63873
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
39 |
val (s1, s2) = |
67130 | 40 |
Completion.split_template(Isabelle_Encoding.perhaps_decode(text_area.getBuffer, txt)) |
63873
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
41 |
text_area.setSelectedText(s1 + s2) |
63870 | 42 |
text_area.moveCaretPosition(text_area.getCaretPosition - s2.length) |
73367 | 43 |
text_area.requestFocus() |
63870 | 44 |
} |
63873
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
45 |
tooltip = GUI.tooltip_lines(cat_lines(txt :: abbrs.map(a => "abbrev: " + a))) |
63870 | 46 |
} |
47 |
||
75393 | 48 |
private class Abbrevs_Panel extends Wrap_Panel(Nil, Wrap_Panel.Alignment.Center) { |
63870 | 49 |
private var abbrevs: Thy_Header.Abbrevs = Nil |
50 |
||
75200
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
51 |
def refresh(): Unit = GUI_Thread.require { |
63873
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
52 |
val abbrevs1 = Isabelle.buffer_syntax(view.getBuffer).getOrElse(Outer_Syntax.empty).abbrevs |
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
53 |
|
63870 | 54 |
if (abbrevs != abbrevs1) { |
55 |
abbrevs = abbrevs1 |
|
56 |
||
63873
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
57 |
val entries: List[(String, List[String])] = |
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
58 |
Multi_Map( |
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
59 |
(for { |
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
60 |
(abbr, txt0) <- abbrevs |
63926 | 61 |
txt = Symbol.encode(txt0) |
63873
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
62 |
if !Symbol.iterator(txt). |
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
63 |
forall(s => s.length == 1 && s(0) != Completion.caret_indicator) |
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
64 |
} yield (txt, abbr)): _*).iterator_list.toList |
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
65 |
|
73367 | 66 |
contents.clear() |
63873
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
67 |
for ((txt, abbrs) <- entries.sortBy(_._1)) |
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
wenzelm
parents:
63872
diff
changeset
|
68 |
contents += new Abbrev_Component(txt, abbrs.filterNot(_ == "").sorted) |
63870 | 69 |
|
73367 | 70 |
revalidate() |
71 |
repaint() |
|
63870 | 72 |
} |
73 |
} |
|
63872 | 74 |
|
75200
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
75 |
refresh() |
63870 | 76 |
} |
77 |
||
63872 | 78 |
|
79 |
/* symbols */ |
|
80 |
||
75393 | 81 |
private class Symbol_Component(val symbol: String, is_control: Boolean) extends Button { |
82 |
def update_font(): Unit = { |
|
63874 | 83 |
font = |
75195 | 84 |
Symbol.symbols.fonts.get(symbol) match { |
63874 | 85 |
case None => GUI.font(size = font_size) |
86 |
case Some(font_family) => GUI.font(family = font_family, size = font_size) |
|
87 |
} |
|
88 |
} |
|
75200
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
89 |
update_font() |
63874 | 90 |
|
50187
b5a09812abc4
special handling of control symbols in Symbols dockable;
wenzelm
parents:
50186
diff
changeset
|
91 |
action = |
62104
fb73c0d7bb37
clarified symbol insertion, depending on buffer encoding;
wenzelm
parents:
62024
diff
changeset
|
92 |
Action(Symbol.decode(symbol)) { |
50187
b5a09812abc4
special handling of control symbols in Symbols dockable;
wenzelm
parents:
50186
diff
changeset
|
93 |
val text_area = view.getTextArea |
65997
e3dc9ea67a62
output control symbols like ML version, with optionally hidden source;
wenzelm
parents:
65259
diff
changeset
|
94 |
if (is_control && HTML.is_control(symbol)) |
65259 | 95 |
Syntax_Style.edit_control_style(text_area, symbol) |
62104
fb73c0d7bb37
clarified symbol insertion, depending on buffer encoding;
wenzelm
parents:
62024
diff
changeset
|
96 |
else |
67130 | 97 |
text_area.setSelectedText(Isabelle_Encoding.perhaps_decode(text_area.getBuffer, symbol)) |
73367 | 98 |
text_area.requestFocus() |
50187
b5a09812abc4
special handling of control symbols in Symbols dockable;
wenzelm
parents:
50186
diff
changeset
|
99 |
} |
56622
891d1b8b64fb
clarified tooltip_lines: HTML.encode already takes care of newline (but not space);
wenzelm
parents:
56609
diff
changeset
|
100 |
tooltip = |
891d1b8b64fb
clarified tooltip_lines: HTML.encode already takes care of newline (but not space);
wenzelm
parents:
56609
diff
changeset
|
101 |
GUI.tooltip_lines( |
75199 | 102 |
cat_lines(symbol :: Symbol.symbols.get_abbrevs(symbol).map(a => "abbrev: " + a))) |
50143
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
103 |
} |
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
104 |
|
75393 | 105 |
private class Reset_Component extends Button { |
50187
b5a09812abc4
special handling of control symbols in Symbols dockable;
wenzelm
parents:
50186
diff
changeset
|
106 |
action = Action("Reset") { |
b5a09812abc4
special handling of control symbols in Symbols dockable;
wenzelm
parents:
50186
diff
changeset
|
107 |
val text_area = view.getTextArea |
65259 | 108 |
Syntax_Style.edit_control_style(text_area, "") |
73367 | 109 |
text_area.requestFocus() |
50187
b5a09812abc4
special handling of control symbols in Symbols dockable;
wenzelm
parents:
50186
diff
changeset
|
110 |
} |
b5a09812abc4
special handling of control symbols in Symbols dockable;
wenzelm
parents:
50186
diff
changeset
|
111 |
tooltip = "Reset control symbols within text" |
b5a09812abc4
special handling of control symbols in Symbols dockable;
wenzelm
parents:
50186
diff
changeset
|
112 |
} |
b5a09812abc4
special handling of control symbols in Symbols dockable;
wenzelm
parents:
50186
diff
changeset
|
113 |
|
63872 | 114 |
|
63877 | 115 |
/* search */ |
116 |
||
117 |
private class Search_Panel extends BorderPanel { |
|
118 |
val search_field = new TextField(10) |
|
75200
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
119 |
val results_panel: Wrap_Panel = Wrap_Panel(Nil, Wrap_Panel.Alignment.Center) |
63877 | 120 |
layout(search_field) = BorderPanel.Position.North |
121 |
layout(new ScrollPane(results_panel)) = BorderPanel.Position.Center |
|
122 |
||
75200
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
123 |
private val search_space = |
75197 | 124 |
for (entry <- Symbol.symbols.entries if entry.code.isDefined) |
125 |
yield entry.symbol -> Word.lowercase(entry.symbol) |
|
75200
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
126 |
val search_delay: Delay = |
76610 | 127 |
Delay.last(PIDE.session.input_delay, gui = true) { |
63877 | 128 |
val search_words = Word.explode(Word.lowercase(search_field.text)) |
129 |
val search_limit = PIDE.options.int("jedit_symbols_search_limit") max 0 |
|
130 |
val results = |
|
131 |
for ((sym, s) <- search_space; if search_words.forall(s.contains(_))) yield sym |
|
132 |
||
73367 | 133 |
results_panel.contents.clear() |
63877 | 134 |
for (sym <- results.take(search_limit)) |
135 |
results_panel.contents += new Symbol_Component(sym, false) |
|
136 |
if (results.length > search_limit) |
|
137 |
results_panel.contents += |
|
138 |
new Label("...") { tooltip = "(" + (results.length - search_limit) + " more)" } |
|
73367 | 139 |
revalidate() |
140 |
repaint() |
|
63877 | 141 |
} |
75402 | 142 |
search_field.reactions += { case ValueChanged(_) => search_delay.invoke() } |
63877 | 143 |
} |
144 |
||
145 |
||
63872 | 146 |
/* tabs */ |
63870 | 147 |
|
56756 | 148 |
private val group_tabs: TabbedPane = new TabbedPane { |
63870 | 149 |
pages += new TabbedPane.Page("abbrevs", abbrevs_panel) |
150 |
||
50192 | 151 |
pages ++= |
75195 | 152 |
Symbol.symbols.groups_code.map({ case (group, symbols) => |
66205 | 153 |
val control = group == "control" |
50151 | 154 |
new TabbedPane.Page(group, |
66205 | 155 |
new ScrollPane(Wrap_Panel( |
156 |
symbols.map(new Symbol_Component(_, control)) ::: |
|
66206 | 157 |
(if (control) List(new Reset_Component) else Nil), |
158 |
Wrap_Panel.Alignment.Center)), null) |
|
56753 | 159 |
}) |
160 |
||
63877 | 161 |
val search_panel = new Search_Panel |
162 |
val search_page = new TabbedPane.Page("search", search_panel, "Search Symbols") |
|
56755 | 163 |
pages += search_page |
164 |
||
165 |
listenTo(selection) |
|
166 |
reactions += { |
|
63877 | 167 |
case SelectionChanged(_) if selection.page == search_page => |
73367 | 168 |
search_panel.search_field.requestFocus() |
56755 | 169 |
} |
170 |
||
56756 | 171 |
for (page <- pages) |
78614 | 172 |
page.title = Word.implode(Word.explode('_', page.title).map(Word.perhaps_capitalized)) |
50143
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
173 |
} |
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
174 |
set_content(group_tabs) |
63872 | 175 |
|
176 |
||
177 |
||
178 |
/* main */ |
|
179 |
||
180 |
private val edit_bus_handler: EBComponent = |
|
75200
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
181 |
(_: EBMessage) => abbrevs_refresh_delay.invoke() |
63872 | 182 |
|
183 |
private val main = |
|
184 |
Session.Consumer[Any](getClass.getName) { |
|
63874 | 185 |
case _: Session.Global_Options => |
186 |
GUI_Thread.later { |
|
187 |
val comp = group_tabs.peer |
|
188 |
GUI.traverse_components(comp, |
|
189 |
{ |
|
190 |
case c0: javax.swing.JComponent => |
|
191 |
Component.wrap(c0) match { |
|
75200
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
192 |
case c: Abbrev_Component => c.update_font() |
c05f0e8a54de
misc tuning, based on suggestions by IntelliJ IDEA;
wenzelm
parents:
75199
diff
changeset
|
193 |
case c: Symbol_Component => c.update_font() |
63874 | 194 |
case _ => |
195 |
} |
|
196 |
case _ => |
|
197 |
}) |
|
71601 | 198 |
comp.revalidate() |
63874 | 199 |
comp.repaint() |
200 |
} |
|
63872 | 201 |
case _: Session.Commands_Changed => abbrevs_refresh_delay.invoke() |
202 |
} |
|
203 |
||
75393 | 204 |
override def init(): Unit = { |
63872 | 205 |
EditBus.addToBus(edit_bus_handler) |
63874 | 206 |
PIDE.session.global_options += main |
63872 | 207 |
PIDE.session.commands_changed += main |
208 |
} |
|
209 |
||
75393 | 210 |
override def exit(): Unit = { |
63872 | 211 |
EditBus.removeFromBus(edit_bus_handler) |
63874 | 212 |
PIDE.session.global_options -= main |
63872 | 213 |
PIDE.session.commands_changed -= main |
214 |
} |
|
50143
4ff5d795ed08
dockable with buttons for symbols, grouped and sorted in tabs according to ~~/etc/symbols;
immler
parents:
diff
changeset
|
215 |
} |