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