wenzelm@31763: /* Title: Pure/Thy/completion.scala wenzelm@31763: Author: Makarius wenzelm@31763: wenzelm@31763: Completion of symbols and keywords. wenzelm@31763: */ wenzelm@31763: wenzelm@31763: package isabelle wenzelm@31763: wenzelm@31763: import scala.util.matching.Regex wenzelm@31763: import scala.util.parsing.combinator.RegexParsers wenzelm@31763: wenzelm@31763: wenzelm@31763: private object Completion wenzelm@31763: { wenzelm@31763: /** String/CharSequence utilities */ wenzelm@31763: wenzelm@31763: def length_ord(s1: String, s2: String): Boolean = wenzelm@31763: s1.length < s2.length || s1.length == s2.length && s1 <= s2 wenzelm@31763: wenzelm@31763: class Reverse(text: CharSequence, start: Int, end: Int) extends CharSequence wenzelm@31763: { wenzelm@31763: require(0 <= start && start <= end && end <= text.length) wenzelm@31763: wenzelm@31763: def this(text: CharSequence) = this(text, 0, text.length) wenzelm@31763: wenzelm@31763: def length: Int = end - start wenzelm@31763: def charAt(i: Int): Char = text.charAt(end - i - 1) wenzelm@31763: wenzelm@31763: def subSequence(i: Int, j: Int): CharSequence = wenzelm@31763: if (0 <= i && i <= j && j <= length) new Reverse(text, end - j, end - i) wenzelm@31763: else throw new IndexOutOfBoundsException wenzelm@31763: wenzelm@31763: override def toString: String = wenzelm@31763: { wenzelm@31763: val buf = new StringBuffer(length) wenzelm@31763: for (i <- 0 until length) wenzelm@31763: buf.append(charAt(i)) wenzelm@31763: buf.toString wenzelm@31763: } wenzelm@31763: } wenzelm@31763: wenzelm@31763: wenzelm@31763: /** word completion **/ wenzelm@31763: wenzelm@31763: val word_regex = "[a-zA-Z0-9_']+".r wenzelm@31763: def is_word(s: CharSequence): Boolean = word_regex.pattern.matcher(s).matches wenzelm@31763: wenzelm@31763: object Parse extends RegexParsers wenzelm@31763: { wenzelm@31763: override val whiteSpace = "".r wenzelm@31763: wenzelm@31765: def rev_symbol: Parser[String] = """>[A-Za-z0-9_']+<\\""".r wenzelm@31765: def rev_symb: Parser[String] = """[A-Za-z0-9_']{2,}<\\""".r wenzelm@31763: def word: Parser[String] = "[a-zA-Z0-9_']{3,}".r wenzelm@31763: wenzelm@31763: def read(in: CharSequence): Option[String] = wenzelm@31763: { wenzelm@31765: val rev_in = new Reverse(in) wenzelm@31765: parse((rev_symbol | rev_symb | word) ^^ (_.reverse), rev_in) match { wenzelm@31763: case Success(result, _) => Some(result) wenzelm@31763: case _ => None wenzelm@31763: } wenzelm@31763: } wenzelm@31763: } wenzelm@31763: } wenzelm@31763: wenzelm@31763: class Completion wenzelm@31763: { wenzelm@31763: /* representation */ wenzelm@31763: wenzelm@31780: protected val words_lex = Scan.Lexicon() wenzelm@31780: protected val words_map = Map[String, String]() wenzelm@31763: wenzelm@31780: protected val abbrevs_lex = Scan.Lexicon() wenzelm@31780: protected val abbrevs_map = Map[String, (String, String)]() wenzelm@31763: wenzelm@31763: wenzelm@31763: /* adding stuff */ wenzelm@31763: wenzelm@31763: def + (keyword: String): Completion = wenzelm@31763: { wenzelm@31763: val old = this wenzelm@31763: new Completion { wenzelm@31763: override val words_lex = old.words_lex + keyword wenzelm@31763: override val words_map = old.words_map + (keyword -> keyword) wenzelm@31763: override val abbrevs_lex = old.abbrevs_lex wenzelm@31763: override val abbrevs_map = old.abbrevs_map wenzelm@31763: } wenzelm@31763: } wenzelm@31763: wenzelm@31763: def + (symbols: Symbol.Interpretation): Completion = wenzelm@31763: { wenzelm@31763: val words = wenzelm@31763: (for ((x, _) <- symbols.names) yield (x, x)).toList ::: wenzelm@31763: (for ((x, y) <- symbols.names) yield (y, x)).toList ::: wenzelm@31763: (for ((x, y) <- symbols.abbrevs if Completion.is_word(y)) yield (y, x)).toList wenzelm@31763: wenzelm@31763: val abbrs = wenzelm@31763: (for ((x, y) <- symbols.abbrevs if !Completion.is_word(y)) wenzelm@31765: yield (y.reverse.toString, (y, x))).toList wenzelm@31763: wenzelm@31763: val old = this wenzelm@31763: new Completion { wenzelm@31763: override val words_lex = old.words_lex ++ words.map(_._1) wenzelm@31765: override val words_map = old.words_map ++ words wenzelm@31763: override val abbrevs_lex = old.abbrevs_lex ++ abbrs.map(_._1) wenzelm@31763: override val abbrevs_map = old.abbrevs_map ++ abbrs wenzelm@31763: } wenzelm@31763: } wenzelm@31763: wenzelm@31763: wenzelm@31763: /* complete */ wenzelm@31763: wenzelm@31765: def complete(line: CharSequence): Option[(String, List[String])] = wenzelm@31763: { wenzelm@31765: abbrevs_lex.parse(abbrevs_lex.keyword, new Completion.Reverse(line)) match { wenzelm@31765: case abbrevs_lex.Success(rev_a, _) => wenzelm@31765: val (word, c) = abbrevs_map(rev_a) wenzelm@31765: Some(word, List(c)) wenzelm@31765: case _ => wenzelm@31765: Completion.Parse.read(line) match { wenzelm@31765: case Some(word) => wenzelm@31765: words_lex.completions(word) match { wenzelm@31765: case Nil => None wenzelm@31765: case cs => Some(word, cs.map(words_map(_)).sort(Completion.length_ord _)) wenzelm@31765: } wenzelm@31765: case None => None wenzelm@31765: } wenzelm@31765: } wenzelm@31763: } wenzelm@31763: }