| author | wenzelm | 
| Sat, 03 Jan 2015 22:04:31 +0100 | |
| changeset 59255 | db265648139c | 
| parent 59073 | dcecfcc56dce | 
| child 59319 | 677615cba30d | 
| 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) | 
| 56175 | 34 | def merge(history: History, result1: Option[Result], result2: Option[Result]): Option[Result] = | 
| 35 |       (result1, result2) match {
 | |
| 36 | case (_, None) => result1 | |
| 37 | case (None, _) => result2 | |
| 38 | case (Some(res1), Some(res2)) => | |
| 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 | } | |
| 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._ | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 73 | list(pair(Symbol.decode_string, int))( | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 74 | YXML.parse_body(File.read(COMPLETION_HISTORY))) | 
| 
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 |           catch {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 77 | case ERROR(msg) => ignore_error(msg); Nil | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 78 |             case _: XML.Error => ignore_error(""); Nil
 | 
| 
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 | } | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 81 | else Nil | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 82 | (empty /: content)(_ + _) | 
| 
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 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 86 | 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 | 87 |   {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 88 |     override def toString: String = rep.mkString("Completion.History(", ",", ")")
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 89 | |
| 56878 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 90 | def frequency(name: String): Int = | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 91 | default_frequency(Symbol.encode(name)) getOrElse | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 92 | rep.getOrElse(name, 0) | 
| 53337 
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 + (entry: (String, Int)): History = | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 95 |     {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 96 | val (name, freq) = entry | 
| 56564 
94c55cc73747
added spell-checker completion dialog, without counting frequency of items due to empty name;
 wenzelm parents: 
56278diff
changeset | 97 | if (name == "") this | 
| 
94c55cc73747
added spell-checker completion dialog, without counting frequency of items due to empty name;
 wenzelm parents: 
56278diff
changeset | 98 | else new History(rep + (name -> (frequency(name) + freq))) | 
| 53337 
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 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 101 | def ordering: Ordering[Item] = | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 102 |       new Ordering[Item] {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 103 | def compare(item1: Item, item2: Item): Int = | 
| 56162 
ea6303e2261b
clarified completion ordering: prefer local names;
 wenzelm parents: 
56042diff
changeset | 104 | frequency(item2.name) compare frequency(item1.name) | 
| 
ea6303e2261b
clarified completion ordering: prefer local names;
 wenzelm parents: 
56042diff
changeset | 105 | } | 
| 
ea6303e2261b
clarified completion ordering: prefer local names;
 wenzelm parents: 
56042diff
changeset | 106 | |
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 107 | def save() | 
| 
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 | Isabelle_System.mkdirs(COMPLETION_HISTORY.dir) | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 110 | File.write_backup(COMPLETION_HISTORY, | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 111 |         {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 112 | import XML.Encode._ | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 113 | YXML.string_of_body(list(pair(Symbol.encode_string, int))(rep.toList)) | 
| 
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 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 118 | class History_Variable | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 119 |   {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 120 | private var history = History.empty | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 121 |     def value: History = synchronized { history }
 | 
| 
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 | def load() | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 124 |     {
 | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 125 | val h = History.load() | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 126 |       synchronized { history = h }
 | 
| 
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 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 129 |     def update(item: Item, freq: Int = 1): Unit = synchronized {
 | 
| 55666 | 130 | history = history + (item.name -> freq) | 
| 53337 
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 | |
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 134 | |
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 135 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 136 | /** semantic completion **/ | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 137 | |
| 56173 | 138 | object Semantic | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 139 |   {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 140 | object Info | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 141 |     {
 | 
| 56173 | 142 | 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 | 143 |         info.info match {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 144 | 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 | 145 |             try {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 146 | val (total, names) = | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 147 |               {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 148 | import XML.Decode._ | 
| 55977 | 149 | 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 | 150 | } | 
| 56173 | 151 | 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 | 152 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 153 |             catch { case _: XML.Error => None }
 | 
| 55914 
c5b752d549e3
clarified init_assignable: make double-sure that initial values are reset;
 wenzelm parents: 
55813diff
changeset | 154 | case XML.Elem(Markup(Markup.NO_COMPLETION, _), _) => | 
| 56173 | 155 | 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 | 156 | case _ => None | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 157 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 158 | } | 
| 
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 | |
| 56173 | 161 | sealed abstract class Semantic | 
| 56175 | 162 | case object No_Completion extends Semantic | 
| 163 | 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 | 164 |   {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 165 | def complete( | 
| 56173 | 166 | range: Text.Range, | 
| 167 | history: Completion.History, | |
| 168 | do_decode: Boolean, | |
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 169 | original: String): Option[Completion.Result] = | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 170 |     {
 | 
| 55977 | 171 | def decode(s: String): String = if (do_decode) Symbol.decode(s) else s | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 172 | val items = | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 173 |         for {
 | 
| 55977 | 174 | (xname, (kind, name)) <- names | 
| 175 | xname1 = decode(xname) | |
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 176 | if xname1 != original | 
| 55977 | 177 | (full_name, descr_name) = | 
| 178 | if (kind == "") (name, quote(decode(name))) | |
| 56600 | 179 | else | 
| 56800 | 180 | (Long_Name.qualify(kind, name), | 
| 56600 | 181 |               Word.implode(Word.explode('_', kind)) + " " + quote(decode(name)))
 | 
| 55978 | 182 |           description = List(xname1, "(" + descr_name + ")")
 | 
| 55977 | 183 | } yield Item(range, original, full_name, description, xname1, 0, true) | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 184 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 185 | if (items.isEmpty) None | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 186 | 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 | 187 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 188 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 189 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 190 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 191 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 192 | /** syntactic completion **/ | 
| 
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 | /* language context */ | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 195 | |
| 55749 | 196 | object Language_Context | 
| 55694 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 197 |   {
 | 
| 55749 | 198 |     val outer = Language_Context("", true, false)
 | 
| 199 | val inner = Language_Context(Markup.Language.UNKNOWN, true, false) | |
| 200 | val ML_outer = Language_Context(Markup.Language.ML, false, true) | |
| 201 | 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 | 202 | 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 | 203 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 204 | |
| 55749 | 205 | 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 | 206 |   {
 | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 207 | def is_outer: Boolean = language == "" | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 208 | } | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 209 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 210 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 211 | /* init */ | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 212 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 213 | val empty: Completion = new Completion() | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 214 | def init(): Completion = empty.add_symbols() | 
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 215 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 216 | |
| 
a1184dfb8e00
clarified semantic completion: retain kind.full_name as official item name for history;
 wenzelm parents: 
55693diff
changeset | 217 | /* word parsers */ | 
| 31763 | 218 | |
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 219 | private object Word_Parsers extends RegexParsers | 
| 31763 | 220 |   {
 | 
| 221 | override val whiteSpace = "".r | |
| 222 | ||
| 57589 | 223 | private val symbol_regex: Regex = """\\<\^?[A-Za-z0-9_']+>""".r | 
| 224 | def is_symbol(s: CharSequence): Boolean = symbol_regex.pattern.matcher(s).matches | |
| 225 | ||
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 226 | 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 | 227 |     private def reverse_symb: Parser[String] = """[A-Za-z0-9_']{2,}\^?<\\""".r
 | 
| 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 228 | private def escape: Parser[String] = """[a-zA-Z0-9_']+\\""".r | 
| 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 229 | |
| 56039 
5ff5208de089
include long identifiers in the reckoning of words (e.g. "integer.lifting" vs. 'lifting_update');
 wenzelm parents: 
56001diff
changeset | 230 | private val word_regex = "[a-zA-Z0-9_'.]+".r | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 231 | private def word: Parser[String] = word_regex | 
| 56039 
5ff5208de089
include long identifiers in the reckoning of words (e.g. "integer.lifting" vs. 'lifting_update');
 wenzelm parents: 
56001diff
changeset | 232 |     private def word3: Parser[String] = "[a-zA-Z0-9_'.]{3,}".r
 | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 233 | private def underscores: Parser[String] = "_*".r | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 234 | |
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 235 | 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 | 236 | def is_word_char(c: Char): Boolean = Symbol.is_ascii_letdig(c) || c == '.' | 
| 31763 | 237 | |
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 238 | def read_symbol(in: CharSequence): Option[String] = | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 239 |     {
 | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 240 | val reverse_in = new Library.Reverse(in) | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 241 |       parse(reverse_symbol ^^ (_.reverse), reverse_in) match {
 | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 242 | case Success(result, _) => Some(result) | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 243 | case _ => None | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 244 | } | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 245 | } | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 246 | |
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 247 | def read_word(explicit: Boolean, in: CharSequence): Option[(String, String)] = | 
| 31763 | 248 |     {
 | 
| 53322 | 249 | val parse_word = if (explicit) word else word3 | 
| 37072 
9105c8237c7a
renamed "rev" to "reverse" following usual Scala conventions;
 wenzelm parents: 
36012diff
changeset | 250 | 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 | 251 | val parser = | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 252 | (reverse_symbol | reverse_symb | escape) ^^ (x => (x.reverse, "")) | | 
| 56221 
a8dfbe9f25da
accomodate word as part of schematic variable name;
 wenzelm parents: 
56175diff
changeset | 253 |         underscores ~ parse_word ~ opt("?") ^^
 | 
| 
a8dfbe9f25da
accomodate word as part of schematic variable name;
 wenzelm parents: 
56175diff
changeset | 254 |         { 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 | 255 |       parse(parser, reverse_in) match {
 | 
| 31763 | 256 | case Success(result, _) => Some(result) | 
| 257 | case _ => None | |
| 258 | } | |
| 259 | } | |
| 260 | } | |
| 55666 | 261 | |
| 262 | ||
| 263 | /* abbreviations */ | |
| 264 | ||
| 56661 
ef623f6f036b
avoid octal escape literals -- deprecated in scala-2.11.0;
 wenzelm parents: 
56600diff
changeset | 265 | private val caret_indicator = '\u0007' | 
| 55666 | 266 |   private val antiquote = "@{"
 | 
| 56878 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 267 | |
| 55666 | 268 | private val default_abbrs = | 
| 56878 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 269 |     List("@{" -> "@{\u0007}",
 | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 270 | "`" -> "\\<close>", | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 271 | "`" -> "\\<open>", | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 272 | "`" -> "\\<open>\u0007\\<close>") | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 273 | |
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 274 | private def default_frequency(name: String): Option[Int] = | 
| 
a5d082a85124
hardwired default_frequency to avoid fluctuation of popup content;
 wenzelm parents: 
56800diff
changeset | 275 | default_abbrs.iterator.map(_._2).zipWithIndex.find(_._1 == name).map(_._2) | 
| 31763 | 276 | } | 
| 277 | ||
| 46712 | 278 | final class Completion private( | 
| 59073 | 279 | protected val keywords: Map[String, Boolean] = Map.empty, | 
| 280 | protected val words_lex: Scan.Lexicon = Scan.Lexicon.empty, | |
| 281 | protected val words_map: Multi_Map[String, String] = Multi_Map.empty, | |
| 282 | protected val abbrevs_lex: Scan.Lexicon = Scan.Lexicon.empty, | |
| 283 | protected val abbrevs_map: Multi_Map[String, (String, String)] = Multi_Map.empty) | |
| 31763 | 284 | {
 | 
| 59073 | 285 | /* merge */ | 
| 286 | ||
| 287 | def is_empty: Boolean = | |
| 288 | keywords.isEmpty && | |
| 289 | words_lex.is_empty && | |
| 290 | words_map.isEmpty && | |
| 291 | abbrevs_lex.is_empty && | |
| 292 | abbrevs_map.isEmpty | |
| 293 | ||
| 294 | def ++ (other: Completion): Completion = | |
| 295 | if (this eq other) this | |
| 296 | else if (is_empty) other | |
| 297 |     else {
 | |
| 298 | val keywords1 = | |
| 299 |         (keywords /: other.keywords) { case (m, e) => if (m.isDefinedAt(e._1)) m else m + e }
 | |
| 300 | val words_lex1 = words_lex ++ other.words_lex | |
| 301 | val words_map1 = words_map ++ other.words_map | |
| 302 | val abbrevs_lex1 = abbrevs_lex ++ other.abbrevs_lex | |
| 303 | val abbrevs_map1 = abbrevs_map ++ other.abbrevs_map | |
| 304 | new Completion(keywords1, words_lex1, words_map1, abbrevs_lex1, abbrevs_map1) | |
| 305 | } | |
| 306 | ||
| 307 | ||
| 55983 | 308 | /* keywords */ | 
| 31763 | 309 | |
| 55986 
61b0021ed674
more strict discrimination: symbols vs. keywords could overlap;
 wenzelm parents: 
55985diff
changeset | 310 | private def is_symbol(name: String): Boolean = Symbol.names.isDefinedAt(name) | 
| 
61b0021ed674
more strict discrimination: symbols vs. keywords could overlap;
 wenzelm parents: 
55985diff
changeset | 311 | private def is_keyword(name: String): Boolean = !is_symbol(name) && keywords.isDefinedAt(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 | 312 | private def is_keyword_template(name: String, template: Boolean): Boolean = | 
| 
2df1e7bca361
do allow replacement of words where this is appropriate, notably symbol abbrevs and keyword templates (see also 1c42ebdb3a58);
 wenzelm parents: 
55996diff
changeset | 313 | is_keyword(name) && keywords(name) == template | 
| 55984 | 314 | |
| 315 | def + (keyword: String, template: String): Completion = | |
| 46624 | 316 | new Completion( | 
| 55984 | 317 | keywords + (keyword -> (keyword != template)), | 
| 46624 | 318 | words_lex + keyword, | 
| 55984 | 319 | words_map + (keyword -> template), | 
| 46624 | 320 | abbrevs_lex, | 
| 321 | abbrevs_map) | |
| 31763 | 322 | |
| 40533 
e38e80686ce5
somewhat adhoc replacement for 'thus' and 'hence';
 wenzelm parents: 
37072diff
changeset | 323 | def + (keyword: String): Completion = this + (keyword, keyword) | 
| 
e38e80686ce5
somewhat adhoc replacement for 'thus' and 'hence';
 wenzelm parents: 
37072diff
changeset | 324 | |
| 55983 | 325 | |
| 326 | /* symbols with abbreviations */ | |
| 327 | ||
| 46624 | 328 | private def add_symbols(): Completion = | 
| 31763 | 329 |   {
 | 
| 330 | val words = | |
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 331 | (for ((x, _) <- Symbol.names.toList) yield (x, x)) ::: | 
| 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 332 |       (for ((x, y) <- Symbol.names.toList) yield ("\\" + y, x)) :::
 | 
| 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 333 | (for ((x, y) <- Symbol.abbrevs.toList if Completion.Word_Parsers.is_word(y)) yield (y, x)) | 
| 31763 | 334 | |
| 55666 | 335 | val symbol_abbrs = | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 336 | (for ((x, y) <- Symbol.abbrevs.iterator if !Completion.Word_Parsers.is_word(y)) | 
| 55666 | 337 | yield (y, x)).toList | 
| 338 | ||
| 339 | val abbrs = | |
| 56591 
1a59587f46ec
clarified abbreviations for cartouche delimiters, to work in any context;
 wenzelm parents: 
56564diff
changeset | 340 | for ((a, b) <- symbol_abbrs ::: Completion.default_abbrs) | 
| 55666 | 341 | yield (a.reverse, (a, b)) | 
| 31763 | 342 | |
| 46624 | 343 | new Completion( | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 344 | keywords, | 
| 46624 | 345 | words_lex ++ words.map(_._1), | 
| 346 | words_map ++ words, | |
| 347 | abbrevs_lex ++ abbrs.map(_._1), | |
| 348 | abbrevs_map ++ abbrs) | |
| 31763 | 349 | } | 
| 350 | ||
| 351 | ||
| 352 | /* complete */ | |
| 353 | ||
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 354 | def complete( | 
| 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 355 | history: Completion.History, | 
| 55977 | 356 | do_decode: Boolean, | 
| 53337 
b3817a0e3211
sort items according to persistent history of frequency of use;
 wenzelm parents: 
53325diff
changeset | 357 | explicit: Boolean, | 
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 358 | start: Text.Offset, | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 359 | text: CharSequence, | 
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 360 | caret: Int, | 
| 55749 | 361 | language_context: Completion.Language_Context): Option[Completion.Result] = | 
| 31763 | 362 |   {
 | 
| 55977 | 363 | def decode(s: String): String = if (do_decode) Symbol.decode(s) else s | 
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 364 | val length = text.length | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 365 | |
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 366 | val abbrevs_result = | 
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 367 |     {
 | 
| 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 368 | 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 | 369 |       Scan.Parsers.parse(Scan.Parsers.literal(abbrevs_lex), reverse_in) match {
 | 
| 55666 | 370 | case Scan.Parsers.Success(reverse_a, _) => | 
| 371 | val abbrevs = abbrevs_map.get_list(reverse_a) | |
| 372 |           abbrevs match {
 | |
| 373 | case Nil => None | |
| 374 | case (a, _) :: _ => | |
| 375 | val ok = | |
| 55749 | 376 | if (a == Completion.antiquote) language_context.antiquotes | 
| 57589 | 377 | else | 
| 378 | language_context.symbols || | |
| 379 | Completion.default_abbrs.exists(_._1 == a) || | |
| 380 | Completion.Word_Parsers.is_symbol(a) | |
| 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 | 381 | if (ok) Some((a, abbrevs)) | 
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 382 | else None | 
| 55666 | 383 | } | 
| 384 | case _ => None | |
| 385 | } | |
| 55813 
08a1c860bc12
allow completion within a word (or symbol), like semantic completion;
 wenzelm parents: 
55749diff
changeset | 386 | } | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 387 | |
| 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 388 | val words_result = | 
| 55982 | 389 | if (abbrevs_result.isDefined) None | 
| 390 |       else {
 | |
| 57602 
0f708666eb7c
no keyword completion within word context -- especially avoid its odd visual rendering;
 wenzelm parents: 
57589diff
changeset | 391 | val word_context = | 
| 
0f708666eb7c
no keyword completion within word context -- especially avoid its odd visual rendering;
 wenzelm parents: 
57589diff
changeset | 392 | 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 | 393 | 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 | 394 |           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 | 395 | case Some(symbol) => Some((symbol, "")) | 
| 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 | 396 | case None => Completion.Word_Parsers.read_word(explicit, text.subSequence(0, caret)) | 
| 55992 | 397 | } | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 398 | result.map( | 
| 55992 | 399 |           {
 | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 400 | case (word, underscores) => | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 401 | val complete_words = words_lex.completions(word) | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 402 | val full_word = word + underscores | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 403 | 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 | 404 | 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 | 405 | else | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 406 |                   for {
 | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 407 | complete_word <- complete_words | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 408 | ok = | 
| 57602 
0f708666eb7c
no keyword completion within word context -- especially avoid its odd visual rendering;
 wenzelm parents: 
57589diff
changeset | 409 | if (is_keyword(complete_word)) !word_context && language_context.is_outer | 
| 55996 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 410 | else language_context.symbols | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 411 | if ok | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 412 | completion <- words_map.get_list(complete_word) | 
| 
13a7d9661ffc
allow suffix of underscores for words (notably keywords), similar to semantic completion;
 wenzelm parents: 
55994diff
changeset | 413 | } yield (complete_word, completion) | 
| 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 | 414 | ((full_word, completions)) | 
| 55992 | 415 | }) | 
| 53275 | 416 | } | 
| 55615 
bf4bbe72f740
completion of keywords and symbols based on language context;
 wenzelm parents: 
55497diff
changeset | 417 | |
| 55982 | 418 |     (abbrevs_result orElse words_result) match {
 | 
| 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 | 419 | case Some((original, completions)) if !completions.isEmpty => | 
| 
ff31aad27661
discontinued unfinished attempts at syntactic word context (see 2e1398b484aa, 08a1c860bc12, 7f229b0212fe) -- back to more basic completion of Isabelle2013-2;
 wenzelm parents: 
56878diff
changeset | 420 | val range = Text.Range(- original.length, 0) + caret + start | 
| 55985 | 421 | val immediate = | 
| 422 | explicit || | |
| 423 | (!Completion.Word_Parsers.is_word(original) && | |
| 424 | Character.codePointCount(original, 0, original.length) > 1) | |
| 55993 | 425 | val unique = completions.length == 1 | 
| 55985 | 426 | |
| 427 | val items = | |
| 428 |           for {
 | |
| 55993 | 429 | (complete_word, name0) <- completions | 
| 430 | name1 = decode(name0) | |
| 55985 | 431 | if name1 != original | 
| 432 | (s1, s2) = | |
| 433 |               space_explode(Completion.caret_indicator, name1) match {
 | |
| 434 | case List(s1, s2) => (s1, s2) | |
| 435 | case _ => (name1, "") | |
| 436 | } | |
| 437 | move = - s2.length | |
| 438 | description = | |
| 439 |               if (is_symbol(name0)) {
 | |
| 440 | if (name0 == name1) List(name0) | |
| 441 | else List(name1, "(symbol " + quote(name0) + ")") | |
| 442 | } | |
| 56001 
2df1e7bca361
do allow replacement of words where this is appropriate, notably symbol abbrevs and keyword templates (see also 1c42ebdb3a58);
 wenzelm parents: 
55996diff
changeset | 443 | else if (is_keyword_template(complete_word, true)) | 
| 55993 | 444 | List(name1, "(template " + quote(complete_word) + ")") | 
| 445 | else if (move != 0) List(name1, "(template)") | |
| 446 | else if (is_keyword(complete_word)) List(name1, "(keyword)") | |
| 55985 | 447 | else List(name1) | 
| 448 | } | |
| 449 | yield Completion.Item(range, original, name1, description, s1 + s2, move, immediate) | |
| 450 | ||
| 451 | if (items.isEmpty) None | |
| 56174 | 452 | else | 
| 453 | Some(Completion.Result(range, original, unique, | |
| 454 | items.sortBy(_.name).sorted(history.ordering))) | |
| 55985 | 455 | |
| 55992 | 456 | case _ => None | 
| 31765 | 457 | } | 
| 31763 | 458 | } | 
| 459 | } |