| author | wenzelm | 
| Mon, 02 Jul 2018 16:43:06 +0200 | |
| changeset 68572 | c8bf6077a87d | 
| parent 67436 | e446505a4ec6 | 
| child 72375 | e48d93811ed7 | 
| permissions | -rw-r--r-- | 
| 55673 
0286219c1261
clarified module location (again, see 763d35697338);
 wenzelm parents: 
55666diff
changeset | 1 | /* Title: Pure/General/completion.scala | 
| 31763 | 2 | Author: Makarius | 
| 3 | ||
| 55687 | 4 | Semantic completion within the formal context (reported names). | 
| 55674 | 5 | Syntactic completion of keywords and symbols, with abbreviations | 
| 55992 | 6 | (based on language context). | 
| 7 | */ | |
| 31763 | 8 | |
| 9 | package isabelle | |
| 10 | ||
| 55618 | 11 | |
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 12 | import scala.collection.immutable.SortedMap | 
| 31763 | 13 | import scala.util.parsing.combinator.RegexParsers | 
| 57589 | 14 | import scala.util.matching.Regex | 
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 15 | import scala.math.Ordering | 
| 31763 | 16 | |
| 17 | ||
| 46624 | 18 | object Completion | 
| 31763 | 19 | {
 | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 20 | /** completion result **/ | 
| 53275 | 21 | |
| 53296 
65c60c782da5
less aggressive immediate completion, based on input and text;
 wenzelm parents: 
53295diff
changeset | 22 | sealed case class Item( | 
| 55692 
19e8b00684f7
more explicit Completion.Item.range, independently of caret;
 wenzelm parents: 
55687diff
changeset | 23 | range: Text.Range, | 
| 53296 
65c60c782da5
less aggressive immediate completion, based on input and text;
 wenzelm parents: 
53295diff
changeset | 24 | original: String, | 
| 55666 | 25 | name: String, | 
| 55978 | 26 | description: List[String], | 
| 53296 
65c60c782da5
less aggressive immediate completion, based on input and text;
 wenzelm parents: 
53295diff
changeset | 27 | replacement: String, | 
| 55666 | 28 | move: Int, | 
| 53296 
65c60c782da5
less aggressive immediate completion, based on input and text;
 wenzelm parents: 
53295diff
changeset | 29 | immediate: Boolean) | 
| 53275 | 30 | |
| 55914 
c5b752d549e3
clarified init_assignable: make double-sure that initial values are reset;
 wenzelm parents: 
55813diff
changeset | 31 | object Result | 
| 
c5b752d549e3
clarified init_assignable: make double-sure that initial values are reset;
 wenzelm parents: 
55813diff
changeset | 32 |   {
 | 
| 
c5b752d549e3
clarified init_assignable: make double-sure that initial values are reset;
 wenzelm parents: 
55813diff
changeset | 33 | def empty(range: Text.Range): Result = Result(range, "", false, Nil) | 
| 66157 | 34 | def merge(history: History, results: Option[Result]*): Option[Result] = | 
| 35 |       ((None: Option[Result]) /: results)({
 | |
| 36 | case (result1, None) => result1 | |
| 37 | case (None, result2) => result2 | |
| 38 | case (result1 @ Some(res1), Some(res2)) => | |
| 56175 | 39 | if (res1.range != res2.range || res1.original != res2.original) result1 | 
| 40 |           else {
 | |
| 41 | val items = (res1.items ::: res2.items).sorted(history.ordering) | |
| 42 | Some(Result(res1.range, res1.original, false, items)) | |
| 43 | } | |
| 66157 | 44 | }) | 
| 55914 
c5b752d549e3
clarified init_assignable: make double-sure that initial values are reset;
 wenzelm parents: 
55813diff
changeset | 45 | } | 
| 
c5b752d549e3
clarified init_assignable: make double-sure that initial values are reset;
 wenzelm parents: 
55813diff
changeset | 46 | |
| 55693 
93ba0085e888
try explicit semantic completion before syntax completion;
 wenzelm parents: 
55692diff
changeset | 47 | sealed case class Result( | 
| 
93ba0085e888
try explicit semantic completion before syntax completion;
 wenzelm parents: 
55692diff
changeset | 48 | range: Text.Range, | 
| 
93ba0085e888
try explicit semantic completion before syntax completion;
 wenzelm parents: 
55692diff
changeset | 49 | original: String, | 
| 
93ba0085e888
try explicit semantic completion before syntax completion;
 wenzelm parents: 
55692diff
changeset | 50 | unique: Boolean, | 
| 
93ba0085e888
try explicit semantic completion before syntax completion;
 wenzelm parents: 
55692diff
changeset | 51 | items: List[Item]) | 
| 53325 
ffabc0083786
more explicit indication of unique result (see also 45be26b98ca6, 3d654643cf56);
 wenzelm parents: 
53324diff
changeset | 52 | |
| 53275 | 53 | |
| 46624 | 54 | |
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 55 | /** persistent history **/ | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 56 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 57 |   private val COMPLETION_HISTORY = Path.explode("$ISABELLE_HOME_USER/etc/completion_history")
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 58 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 59 | object History | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 60 |   {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 61 | val empty: History = new History() | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 62 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 63 | def load(): History = | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 64 |     {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 65 | def ignore_error(msg: String): Unit = | 
| 56782 
433cf57550fa
more systematic Isabelle output, like in classic Isabelle/ML (without markup);
 wenzelm parents: 
56661diff
changeset | 66 |         Output.warning("Ignoring bad content of file " + COMPLETION_HISTORY +
 | 
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 67 | (if (msg == "") "" else "\n" + msg)) | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 68 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 69 | val content = | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 70 |         if (COMPLETION_HISTORY.is_file) {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 71 |           try {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 72 | import XML.Decode._ | 
| 65344 
b99283eed13c
clarified YXML vs. symbol encoding: operate on whole message;
 wenzelm parents: 
63887diff
changeset | 73 | list(pair(string, int))(Symbol.decode_yxml(File.read(COMPLETION_HISTORY))) | 
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 74 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 75 |           catch {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 76 | case ERROR(msg) => ignore_error(msg); Nil | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 77 |             case _: XML.Error => ignore_error(""); Nil
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 78 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 79 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 80 | else Nil | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 81 | (empty /: content)(_ + _) | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 82 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 83 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 84 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 85 | final class History private(rep: SortedMap[String, Int] = SortedMap.empty) | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 86 |   {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 87 |     override def toString: String = rep.mkString("Completion.History(", ",", ")")
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 88 | |
| 56878 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 89 | def frequency(name: String): Int = | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 90 | default_frequency(Symbol.encode(name)) getOrElse | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 91 | rep.getOrElse(name, 0) | 
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 92 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 93 | def + (entry: (String, Int)): History = | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 94 |     {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 95 | val (name, freq) = entry | 
| 56564 
94c55cc73747
added spell-checker completion dialog, without counting frequency of items due to empty name;
 wenzelm parents: 
56278diff
changeset | 96 | if (name == "") this | 
| 
94c55cc73747
added spell-checker completion dialog, without counting frequency of items due to empty name;
 wenzelm parents: 
56278diff
changeset | 97 | else new History(rep + (name -> (frequency(name) + freq))) | 
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 98 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 99 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 100 | def ordering: Ordering[Item] = | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 101 |       new Ordering[Item] {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 102 | def compare(item1: Item, item2: Item): Int = | 
| 56162 
ea6303e2261b
clarified completion ordering: prefer local names;
 wenzelm parents: 
56042diff
changeset | 103 | frequency(item2.name) compare frequency(item1.name) | 
| 
ea6303e2261b
clarified completion ordering: prefer local names;
 wenzelm parents: 
56042diff
changeset | 104 | } | 
| 
ea6303e2261b
clarified completion ordering: prefer local names;
 wenzelm parents: 
56042diff
changeset | 105 | |
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 106 | def save() | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 107 |     {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 108 | Isabelle_System.mkdirs(COMPLETION_HISTORY.dir) | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 109 | File.write_backup(COMPLETION_HISTORY, | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 110 |         {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 111 | import XML.Encode._ | 
| 65344 
b99283eed13c
clarified YXML vs. symbol encoding: operate on whole message;
 wenzelm parents: 
63887diff
changeset | 112 | Symbol.encode_yxml(list(pair(string, int))(rep.toList)) | 
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 113 | }) | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 114 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 115 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 116 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 117 | class History_Variable | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 118 |   {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 119 | private var history = History.empty | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 120 |     def value: History = synchronized { history }
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 121 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 122 | def load() | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 123 |     {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 124 | val h = History.load() | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 125 |       synchronized { history = h }
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 126 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 127 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 128 |     def update(item: Item, freq: Int = 1): Unit = synchronized {
 | 
| 55666 | 129 | history = history + (item.name -> freq) | 
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 130 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 131 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 132 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 133 | |
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 134 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 135 | /** semantic completion **/ | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 136 | |
| 61100 | 137 | def clean_name(s: String): Option[String] = | 
| 138 | if (s == "" || s == "_") None | |
| 139 | else Some(s.reverseIterator.dropWhile(_ == '_').toList.reverse.mkString) | |
| 140 | ||
| 66768 | 141 | def completed(input: String): String => Boolean = | 
| 142 |     clean_name(input) match {
 | |
| 143 | case None => (name: String) => false | |
| 144 | case Some(prefix) => (name: String) => name.startsWith(prefix) | |
| 145 | } | |
| 146 | ||
| 59717 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 147 | def report_no_completion(pos: Position.T): String = | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 148 | YXML.string_of_tree(Semantic.Info(pos, No_Completion)) | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 149 | |
| 66766 | 150 | def report_names(pos: Position.T, names: List[(String, (String, String))], total: Int = 0): String = | 
| 66768 | 151 | if (names.isEmpty) "" | 
| 152 | else | |
| 153 | YXML.string_of_tree(Semantic.Info(pos, Names(if (total > 0) total else names.length, names))) | |
| 66766 | 154 | |
| 155 | def report_theories(pos: Position.T, thys: List[String], total: Int = 0): String = | |
| 156 |     report_names(pos, thys.map(name => (name, ("theory", name))), total)
 | |
| 59717 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 157 | |
| 56173 | 158 | object Semantic | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 159 |   {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 160 | object Info | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 161 |     {
 | 
| 59717 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 162 | def apply(pos: Position.T, semantic: Semantic): XML.Elem = | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 163 |       {
 | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 164 | val elem = | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 165 |           semantic match {
 | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 166 | case No_Completion => XML.Elem(Markup(Markup.NO_COMPLETION, pos), Nil) | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 167 | case Names(total, names) => | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 168 | XML.Elem(Markup(Markup.COMPLETION, pos), | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 169 |                 {
 | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 170 | import XML.Encode._ | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 171 | pair(int, list(pair(string, pair(string, string))))(total, names) | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 172 | }) | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 173 | } | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 174 | XML.Elem(Markup(Markup.REPORT, pos), List(elem)) | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 175 | } | 
| 
44a3ed0b8265
support for completion reports produced in Scala (inlined into messages);
 wenzelm parents: 
59319diff
changeset | 176 | |
| 56173 | 177 | def unapply(info: Text.Markup): Option[Text.Info[Semantic]] = | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 178 |         info.info match {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 179 | case XML.Elem(Markup(Markup.COMPLETION, _), body) => | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 180 |             try {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 181 | val (total, names) = | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 182 |               {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 183 | import XML.Decode._ | 
| 55977 | 184 | pair(int, list(pair(string, pair(string, string))))(body) | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 185 | } | 
| 56173 | 186 | Some(Text.Info(info.range, Names(total, names))) | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 187 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 188 |             catch { case _: XML.Error => None }
 | 
| 55914 
c5b752d549e3
clarified init_assignable: make double-sure that initial values are reset;
 wenzelm parents: 
55813diff
changeset | 189 | case XML.Elem(Markup(Markup.NO_COMPLETION, _), _) => | 
| 56173 | 190 | Some(Text.Info(info.range, No_Completion)) | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 191 | case _ => None | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 192 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 193 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 194 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 195 | |
| 56173 | 196 | sealed abstract class Semantic | 
| 56175 | 197 | case object No_Completion extends Semantic | 
| 198 | case class Names(total: Int, names: List[(String, (String, String))]) extends Semantic | |
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 199 |   {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 200 | def complete( | 
| 56173 | 201 | range: Text.Range, | 
| 202 | history: Completion.History, | |
| 66055 | 203 | unicode: Boolean, | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 204 | original: String): Option[Completion.Result] = | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 205 |     {
 | 
| 66055 | 206 | def decode(s: String): String = if (unicode) Symbol.decode(s) else s | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 207 | val items = | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 208 |         for {
 | 
| 55977 | 209 | (xname, (kind, name)) <- names | 
| 210 | xname1 = decode(xname) | |
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 211 | if xname1 != original | 
| 55977 | 212 | (full_name, descr_name) = | 
| 213 | if (kind == "") (name, quote(decode(name))) | |
| 56600 | 214 | else | 
| 56800 | 215 | (Long_Name.qualify(kind, name), | 
| 60732 | 216 |               Word.implode(Word.explode('_', kind)) +
 | 
| 217 | (if (xname == name) "" else " " + quote(decode(name)))) | |
| 61622 
8bb7848b3d47
smart quoting of non-identifiers, e.g. jEdit actions;
 wenzelm parents: 
61613diff
changeset | 218 |         } yield {
 | 
| 
8bb7848b3d47
smart quoting of non-identifiers, e.g. jEdit actions;
 wenzelm parents: 
61613diff
changeset | 219 |           val description = List(xname1, "(" + descr_name + ")")
 | 
| 
8bb7848b3d47
smart quoting of non-identifiers, e.g. jEdit actions;
 wenzelm parents: 
61613diff
changeset | 220 | val replacement = | 
| 63761 
2ca536d0163e
more careful quoting, e.g. relevant for \<^control>cartouche;
 wenzelm parents: 
63587diff
changeset | 221 |             List(original, xname1).map(Token.explode(Keyword.Keywords.empty, _)) match {
 | 
| 
2ca536d0163e
more careful quoting, e.g. relevant for \<^control>cartouche;
 wenzelm parents: 
63587diff
changeset | 222 | case List(List(tok), _) if tok.kind == Token.Kind.CARTOUCHE => | 
| 67436 | 223 | Symbol.cartouche_decoded(xname1) | 
| 63761 
2ca536d0163e
more careful quoting, e.g. relevant for \<^control>cartouche;
 wenzelm parents: 
63587diff
changeset | 224 | case List(_, List(tok)) if tok.is_name => xname1 | 
| 61622 
8bb7848b3d47
smart quoting of non-identifiers, e.g. jEdit actions;
 wenzelm parents: 
61613diff
changeset | 225 | case _ => quote(xname1) | 
| 
8bb7848b3d47
smart quoting of non-identifiers, e.g. jEdit actions;
 wenzelm parents: 
61613diff
changeset | 226 | } | 
| 
8bb7848b3d47
smart quoting of non-identifiers, e.g. jEdit actions;
 wenzelm parents: 
61613diff
changeset | 227 | Item(range, original, full_name, description, replacement, 0, true) | 
| 
8bb7848b3d47
smart quoting of non-identifiers, e.g. jEdit actions;
 wenzelm parents: 
61613diff
changeset | 228 | } | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 229 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 230 | if (items.isEmpty) None | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 231 | else Some(Result(range, original, names.length == 1, items.sorted(history.ordering))) | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 232 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 233 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 234 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 235 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 236 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 237 | /** syntactic completion **/ | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 238 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 239 | /* language context */ | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 240 | |
| 55749 | 241 | object Language_Context | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 242 |   {
 | 
| 55749 | 243 |     val outer = Language_Context("", true, false)
 | 
| 244 | val inner = Language_Context(Markup.Language.UNKNOWN, true, false) | |
| 245 | val ML_outer = Language_Context(Markup.Language.ML, false, true) | |
| 246 | val ML_inner = Language_Context(Markup.Language.ML, true, false) | |
| 56278 
2576d3a40ed6
separate tokenization and language context for SML: no symbols, no antiquotes;
 wenzelm parents: 
56221diff
changeset | 247 | val SML_outer = Language_Context(Markup.Language.SML, false, false) | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 248 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 249 | |
| 55749 | 250 | sealed case class Language_Context(language: String, symbols: Boolean, antiquotes: Boolean) | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 251 |   {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 252 | def is_outer: Boolean = language == "" | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 253 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 254 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 255 | |
| 67004 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 256 | /* make */ | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 257 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 258 | val empty: Completion = new Completion() | 
| 66984 | 259 | |
| 67004 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 260 | def make(keywords: List[String], abbrevs: List[(String, String)]): Completion = | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 261 | empty.add_symbols.add_keywords(keywords).add_abbrevs( | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 262 | Completion.symbol_abbrevs ::: Completion.default_abbrevs ::: abbrevs) | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 263 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 264 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 265 | /* word parsers */ | 
| 31763 | 266 | |
| 63587 
881e8e2cfec2
implicit keyword completion only for actual words (amending 73939a9b70a3);
 wenzelm parents: 
63579diff
changeset | 267 | object Word_Parsers extends RegexParsers | 
| 31763 | 268 |   {
 | 
| 269 | override val whiteSpace = "".r | |
| 270 | ||
| 61613 | 271 | private val symboloid_regex: Regex = """\\([A-Za-z0-9_']+|<\^?[A-Za-z0-9_']+>?)""".r | 
| 61600 
1ca11ddfcc70
clarified completion of explicit symbols (see also f6bd97a587b7, e0e4ac981cf1);
 wenzelm parents: 
61599diff
changeset | 272 | def is_symboloid(s: CharSequence): Boolean = symboloid_regex.pattern.matcher(s).matches | 
| 57589 | 273 | |
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 274 | private def reverse_symbol: Parser[String] = """>[A-Za-z0-9_']+\^?<\\""".r | 
| 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 275 |     private def reverse_symb: Parser[String] = """[A-Za-z0-9_']{2,}\^?<\\""".r
 | 
| 61599 | 276 | private def reverse_escape: Parser[String] = """[a-zA-Z0-9_']+\\""".r | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 277 | |
| 56039 
5ff5208de089
include long identifiers in the reckoning of words (e.g. "integer.lifting" vs. 'lifting_update');
 wenzelm parents: 
56001diff
changeset | 278 | private val word_regex = "[a-zA-Z0-9_'.]+".r | 
| 63887 
2d9c12eba726
more uniform completion of short word: exclude single character prefix but include two chracter prefix (see also 31633e503c17);
 wenzelm parents: 
63873diff
changeset | 279 |     private def word2: Parser[String] = "[a-zA-Z0-9_'.]{2,}".r
 | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 280 | private def underscores: Parser[String] = "_*".r | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 281 | |
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 282 | def is_word(s: CharSequence): Boolean = word_regex.pattern.matcher(s).matches | 
| 56042 
d3c35a300433
proper Char comparison, despite weakly-typed Scala (cf. 5ff5208de089);
 wenzelm parents: 
56039diff
changeset | 283 | def is_word_char(c: Char): Boolean = Symbol.is_ascii_letdig(c) || c == '.' | 
| 31763 | 284 | |
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 285 | def read_symbol(in: CharSequence): Option[String] = | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 286 |     {
 | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 287 | val reverse_in = new Library.Reverse(in) | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 288 |       parse(reverse_symbol ^^ (_.reverse), reverse_in) match {
 | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 289 | case Success(result, _) => Some(result) | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 290 | case _ => None | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 291 | } | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 292 | } | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 293 | |
| 63887 
2d9c12eba726
more uniform completion of short word: exclude single character prefix but include two chracter prefix (see also 31633e503c17);
 wenzelm parents: 
63873diff
changeset | 294 | def read_word(in: CharSequence): Option[(String, String)] = | 
| 31763 | 295 |     {
 | 
| 37072 
9105c8237c7a
renamed "rev" to "reverse" following usual Scala conventions;
 wenzelm parents: 
36012diff
changeset | 296 | val reverse_in = new Library.Reverse(in) | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 297 | val parser = | 
| 61599 | 298 | (reverse_symbol | reverse_symb | reverse_escape) ^^ (x => (x.reverse, "")) | | 
| 63887 
2d9c12eba726
more uniform completion of short word: exclude single character prefix but include two chracter prefix (see also 31633e503c17);
 wenzelm parents: 
63873diff
changeset | 299 |         underscores ~ word2 ~ opt("?") ^^
 | 
| 56221 
a8dfbe9f25da
accomodate word as part of schematic variable name;
 wenzelm parents: 
56175diff
changeset | 300 |         { case x ~ y ~ z => (z.getOrElse("") + y.reverse, x) }
 | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 301 |       parse(parser, reverse_in) match {
 | 
| 31763 | 302 | case Success(result, _) => Some(result) | 
| 303 | case _ => None | |
| 304 | } | |
| 305 | } | |
| 306 | } | |
| 55666 | 307 | |
| 308 | ||
| 63871 | 309 | /* templates */ | 
| 61960 | 310 | |
| 63869 | 311 | val caret_indicator = '\u0007' | 
| 63871 | 312 | |
| 63869 | 313 | def split_template(s: String): (String, String) = | 
| 314 |     space_explode(caret_indicator, s) match {
 | |
| 315 | case List(s1, s2) => (s1, s2) | |
| 316 | case _ => (s, "") | |
| 317 | } | |
| 318 | ||
| 63871 | 319 | |
| 320 | /* abbreviations */ | |
| 321 | ||
| 322 | private def symbol_abbrevs: Thy_Header.Abbrevs = | |
| 323 | for ((sym, abbr) <- Symbol.abbrevs.toList) yield (abbr, sym) | |
| 324 | ||
| 55666 | 325 |   private val antiquote = "@{"
 | 
| 56878 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 326 | |
| 63578 | 327 | private val default_abbrevs = | 
| 56878 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 328 |     List("@{" -> "@{\u0007}",
 | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 329 | "`" -> "\\<close>", | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 330 | "`" -> "\\<open>", | 
| 63135 | 331 | "`" -> "\\<open>\u0007\\<close>", | 
| 332 | "\"" -> "\\<close>", | |
| 333 | "\"" -> "\\<open>", | |
| 334 | "\"" -> "\\<open>\u0007\\<close>") | |
| 56878 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 335 | |
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 336 | private def default_frequency(name: String): Option[Int] = | 
| 63578 | 337 | default_abbrevs.iterator.map(_._2).zipWithIndex.find(_._1 == name).map(_._2) | 
| 31763 | 338 | } | 
| 339 | ||
| 46712 | 340 | final class Completion private( | 
| 67004 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 341 | keywords: Set[String] = Set.empty, | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 342 | words_lex: Scan.Lexicon = Scan.Lexicon.empty, | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 343 | words_map: Multi_Map[String, String] = Multi_Map.empty, | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 344 | abbrevs_lex: Scan.Lexicon = Scan.Lexicon.empty, | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 345 | abbrevs_map: Multi_Map[String, (String, String)] = Multi_Map.empty) | 
| 31763 | 346 | {
 | 
| 55983 | 347 | /* keywords */ | 
| 31763 | 348 | |
| 55986 
61b0021ed674
more strict discrimination: symbols vs. keywords could overlap;
 wenzelm parents: 
55985diff
changeset | 349 | private def is_symbol(name: String): Boolean = Symbol.names.isDefinedAt(name) | 
| 63579 | 350 | private def is_keyword(name: String): Boolean = !is_symbol(name) && keywords(name) | 
| 56001 
2df1e7bca361
do allow replacement of words where this is appropriate, notably symbol abbrevs and keyword templates (see also 1c42ebdb3a58);
 wenzelm parents: 
55996diff
changeset | 351 | private def is_keyword_template(name: String, template: Boolean): Boolean = | 
| 63579 | 352 | is_keyword(name) && (words_map.getOrElse(name, name) != name) == template | 
| 55984 | 353 | |
| 63579 | 354 | def add_keyword(keyword: String): Completion = | 
| 355 | new Completion(keywords + keyword, words_lex, words_map, abbrevs_lex, abbrevs_map) | |
| 40533 
e38e80686ce5
somewhat adhoc replacement for 'thus' and 'hence';
 wenzelm parents: 
37072diff
changeset | 356 | |
| 67004 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 357 | def add_keywords(names: List[String]): Completion = | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 358 |   {
 | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 359 |     val keywords1 = (keywords /: names) { case (ks, k) => if (ks(k)) ks else ks + k }
 | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 360 | if (keywords eq keywords1) this | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 361 | else new Completion(keywords1, words_lex, words_map, abbrevs_lex, abbrevs_map) | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 362 | } | 
| 
af72fa58f71b
clarified lazy Completion within Outer_Syntax: measurable speedup of Sessions.deps;
 wenzelm parents: 
66985diff
changeset | 363 | |
| 55983 | 364 | |
| 63578 | 365 | /* symbols and abbrevs */ | 
| 55983 | 366 | |
| 63871 | 367 | def add_symbols: Completion = | 
| 31763 | 368 |   {
 | 
| 369 | val words = | |
| 67311 | 370 |       Symbol.names.toList.flatMap({ case (sym, (name, argument)) =>
 | 
| 371 | val word = "\\" + name | |
| 372 | val seps = | |
| 373 |           if (argument == Symbol.ARGUMENT_CARTOUCHE) List("")
 | |
| 374 |           else if (argument == Symbol.ARGUMENT_SPACE_CARTOUCHE) List(" ")
 | |
| 375 | else Nil | |
| 376 | List(sym -> sym, word -> sym) ::: | |
| 377 | seps.map(sep => word -> (sym + sep + "\\<open>\u0007\\<close>")) | |
| 378 | }) | |
| 31763 | 379 | |
| 63578 | 380 | new Completion( | 
| 381 | keywords, | |
| 382 | words_lex ++ words.map(_._1), | |
| 383 | words_map ++ words, | |
| 384 | abbrevs_lex, | |
| 385 | abbrevs_map) | |
| 386 | } | |
| 55666 | 387 | |
| 63578 | 388 | def add_abbrevs(abbrevs: List[(String, String)]): Completion = | 
| 63808 | 389 | (this /: abbrevs)(_.add_abbrev(_)) | 
| 390 | ||
| 391 | private def add_abbrev(abbrev: (String, String)): Completion = | |
| 63873 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 392 |     abbrev match {
 | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 393 |       case ("", _) => this
 | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 394 | case (abbr, text) => | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 395 | val rev_abbr = abbr.reverse | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 396 | val is_word = Completion.Word_Parsers.is_word(abbr) | 
| 31763 | 397 | |
| 63873 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 398 | val (words_lex1, words_map1) = | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 399 | if (!is_word) (words_lex, words_map) | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 400 | else if (text != "") (words_lex + abbr, words_map + abbrev) | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 401 | else (words_lex -- List(abbr), words_map - abbr) | 
| 63808 | 402 | |
| 63873 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 403 | val (abbrevs_lex1, abbrevs_map1) = | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 404 | if (is_word) (abbrevs_lex, abbrevs_map) | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 405 | else if (text != "") (abbrevs_lex + rev_abbr, abbrevs_map + (rev_abbr -> abbrev)) | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 406 | else (abbrevs_lex -- List(rev_abbr), abbrevs_map - rev_abbr) | 
| 63808 | 407 | |
| 63873 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 408 | new Completion(keywords, words_lex1, words_map1, abbrevs_lex1, abbrevs_map1) | 
| 
228a85f1d6af
clarified GUI representation of replacement texts with zero or more abbrevs;
 wenzelm parents: 
63871diff
changeset | 409 | } | 
| 31763 | 410 | |
| 411 | ||
| 412 | /* complete */ | |
| 413 | ||
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 414 | def complete( | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 415 | history: Completion.History, | 
| 66055 | 416 | unicode: Boolean, | 
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 417 | explicit: Boolean, | 
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 418 | start: Text.Offset, | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 419 | text: CharSequence, | 
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 420 | caret: Int, | 
| 55749 | 421 | language_context: Completion.Language_Context): Option[Completion.Result] = | 
| 31763 | 422 |   {
 | 
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 423 | val length = text.length | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 424 | |
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 425 | val abbrevs_result = | 
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 426 |     {
 | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 427 | val reverse_in = new Library.Reverse(text.subSequence(0, caret)) | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 428 |       Scan.Parsers.parse(Scan.Parsers.literal(abbrevs_lex), reverse_in) match {
 | 
| 61599 | 429 | case Scan.Parsers.Success(reverse_abbr, _) => | 
| 430 | val abbrevs = abbrevs_map.get_list(reverse_abbr) | |
| 55666 | 431 |           abbrevs match {
 | 
| 432 | case Nil => None | |
| 61599 | 433 | case (abbr, _) :: _ => | 
| 55666 | 434 | val ok = | 
| 61599 | 435 | if (abbr == Completion.antiquote) language_context.antiquotes | 
| 63578 | 436 | else language_context.symbols || Completion.default_abbrevs.exists(_._1 == abbr) | 
| 61599 | 437 | if (ok) Some((abbr, abbrevs)) | 
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 438 | else None | 
| 55666 | 439 | } | 
| 440 | case _ => None | |
| 441 | } | |
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 442 | } | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 443 | |
| 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 444 | val words_result = | 
| 55982 | 445 | if (abbrevs_result.isDefined) None | 
| 446 |       else {
 | |
| 57602 
0f708666eb7c
no keyword completion within word context -- especially avoid its odd visual rendering;
 wenzelm parents: 
57589diff
changeset | 447 | val word_context = | 
| 
0f708666eb7c
no keyword completion within word context -- especially avoid its odd visual rendering;
 wenzelm parents: 
57589diff
changeset | 448 | caret < length && Completion.Word_Parsers.is_word_char(text.charAt(caret)) | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 449 | val result = | 
| 57588 
ff31aad27661
discontinued unfinished attempts at syntactic word context (see 2e1398b484aa, 08a1c860bc12, 7f229b0212fe) -- back to more basic completion of Isabelle2013-2;
 wenzelm parents: 
56878diff
changeset | 450 |           Completion.Word_Parsers.read_symbol(text.subSequence(0, caret)) match {
 | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 451 | case Some(symbol) => Some((symbol, "")) | 
| 63887 
2d9c12eba726
more uniform completion of short word: exclude single character prefix but include two chracter prefix (see also 31633e503c17);
 wenzelm parents: 
63873diff
changeset | 452 | case None => Completion.Word_Parsers.read_word(text.subSequence(0, caret)) | 
| 55992 | 453 | } | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 454 | result.map( | 
| 55992 | 455 |           {
 | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 456 | case (word, underscores) => | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 457 | val complete_words = words_lex.completions(word) | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 458 | val full_word = word + underscores | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 459 | val completions = | 
| 56001 
2df1e7bca361
do allow replacement of words where this is appropriate, notably symbol abbrevs and keyword templates (see also 1c42ebdb3a58);
 wenzelm parents: 
55996diff
changeset | 460 | if (complete_words.contains(full_word) && is_keyword_template(full_word, false)) Nil | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 461 | else | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 462 |                   for {
 | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 463 | complete_word <- complete_words | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 464 | ok = | 
| 57602 
0f708666eb7c
no keyword completion within word context -- especially avoid its odd visual rendering;
 wenzelm parents: 
57589diff
changeset | 465 | if (is_keyword(complete_word)) !word_context && language_context.is_outer | 
| 61600 
1ca11ddfcc70
clarified completion of explicit symbols (see also f6bd97a587b7, e0e4ac981cf1);
 wenzelm parents: 
61599diff
changeset | 466 | else language_context.symbols || Completion.Word_Parsers.is_symboloid(word) | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 467 | if ok | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 468 | completion <- words_map.get_list(complete_word) | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 469 | } yield (complete_word, completion) | 
| 60215 | 470 | (full_word, completions) | 
| 55992 | 471 | }) | 
| 53275 | 472 | } | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 473 | |
| 55982 | 474 |     (abbrevs_result orElse words_result) match {
 | 
| 59319 | 475 | case Some((original, completions)) if completions.nonEmpty => | 
| 57588 
ff31aad27661
discontinued unfinished attempts at syntactic word context (see 2e1398b484aa, 08a1c860bc12, 7f229b0212fe) -- back to more basic completion of Isabelle2013-2;
 wenzelm parents: 
56878diff
changeset | 476 | val range = Text.Range(- original.length, 0) + caret + start | 
| 55985 | 477 | val immediate = | 
| 478 | explicit || | |
| 479 | (!Completion.Word_Parsers.is_word(original) && | |
| 61600 
1ca11ddfcc70
clarified completion of explicit symbols (see also f6bd97a587b7, e0e4ac981cf1);
 wenzelm parents: 
61599diff
changeset | 480 | !Completion.Word_Parsers.is_symboloid(original) && | 
| 55985 | 481 | Character.codePointCount(original, 0, original.length) > 1) | 
| 55993 | 482 | val unique = completions.length == 1 | 
| 55985 | 483 | |
| 66056 | 484 | def decode1(s: String): String = if (unicode) Symbol.decode(s) else s | 
| 485 | def decode2(s: String): String = if (unicode) s else Symbol.decode(s) | |
| 486 | ||
| 55985 | 487 | val items = | 
| 488 |           for {
 | |
| 55993 | 489 | (complete_word, name0) <- completions | 
| 66056 | 490 | name1 = decode1(name0) | 
| 491 | name2 = decode2(name0) | |
| 55985 | 492 | if name1 != original | 
| 63869 | 493 | (s1, s2) = Completion.split_template(name1) | 
| 55985 | 494 | move = - s2.length | 
| 495 | description = | |
| 496 |               if (is_symbol(name0)) {
 | |
| 66056 | 497 | if (name1 == name2) List(name1) | 
| 498 | else List(name1, "(symbol " + quote(name2) + ")") | |
| 55985 | 499 | } | 
| 56001 
2df1e7bca361
do allow replacement of words where this is appropriate, notably symbol abbrevs and keyword templates (see also 1c42ebdb3a58);
 wenzelm parents: 
55996diff
changeset | 500 | else if (is_keyword_template(complete_word, true)) | 
| 55993 | 501 | List(name1, "(template " + quote(complete_word) + ")") | 
| 502 | else if (move != 0) List(name1, "(template)") | |
| 503 | else if (is_keyword(complete_word)) List(name1, "(keyword)") | |
| 55985 | 504 | else List(name1) | 
| 505 | } | |
| 506 | yield Completion.Item(range, original, name1, description, s1 + s2, move, immediate) | |
| 507 | ||
| 508 | if (items.isEmpty) None | |
| 56174 | 509 | else | 
| 510 | Some(Completion.Result(range, original, unique, | |
| 511 | items.sortBy(_.name).sorted(history.ordering))) | |
| 55985 | 512 | |
| 55992 | 513 | case _ => None | 
| 31765 | 514 | } | 
| 31763 | 515 | } | 
| 516 | } |