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