# HG changeset patch # User blanchet # Date 1482315295 -3600 # Node ID c6330e16743fbe49119b2bd1fbe10614f2b63a72 # Parent f3f457535fe2d5569954b5fdd47278b789838f23# Parent 83f012ce256791a0ee559db4989d1a4701dbc0a4 merge diff -r f3f457535fe2 -r c6330e16743f etc/components --- a/etc/components Wed Dec 21 11:14:37 2016 +0100 +++ b/etc/components Wed Dec 21 11:14:55 2016 +0100 @@ -1,6 +1,7 @@ #hard-wired components src/Tools/jEdit src/Tools/Graphview +src/Tools/VSCode src/HOL/Mirabelle src/HOL/Mutabelle src/HOL/Library/Sum_of_Squares diff -r f3f457535fe2 -r c6330e16743f src/Pure/Admin/check_sources.scala --- a/src/Pure/Admin/check_sources.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Pure/Admin/check_sources.scala Wed Dec 21 11:14:55 2016 +0100 @@ -25,9 +25,9 @@ try { Symbol.decode_strict(line) - for { c <- Word.codepoint_iterator(line); if c > 128 && !Character.isAlphabetic(c) } + for { c <- Codepoint.iterator(line); if c > 128 && !Character.isAlphabetic(c) } { - Output.warning("Suspicious Unicode character " + quote(Word.codepoint(c)) + + Output.warning("Suspicious Unicode character " + quote(Codepoint.string(c)) + Position.here(line_pos(i))) } } diff -r f3f457535fe2 -r c6330e16743f src/Pure/General/codepoint.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Pure/General/codepoint.scala Wed Dec 21 11:14:55 2016 +0100 @@ -0,0 +1,53 @@ +/* Title: Pure/General/codepoint.scala + Author: Makarius + +Unicode codepoints vs. Unicode string encoding. +*/ + +package isabelle + + +object Codepoint +{ + def string(c: Int): String = new String(Array(c), 0, 1) + + def iterator(s: String): Iterator[Int] = + new Iterator[Int] { + var offset = 0 + def hasNext: Boolean = offset < s.length + def next: Int = + { + val c = s.codePointAt(offset) + offset += Character.charCount(c) + c + } + } + + def length(s: String): Int = iterator(s).length + + trait Length extends isabelle.Length + { + protected def codepoint_length(c: Int): Int = 1 + + def apply(s: String): Int = + (0 /: iterator(s)) { case (n, c) => n + codepoint_length(c) } + + def offset(s: String, i: Int): Option[Text.Offset] = + { + if (i <= 0 || s.forall(_ < 0x80)) isabelle.Length.offset(s, i) + else { + val length = s.length + var offset = 0 + var j = 0 + while (offset < length && j < i) { + val c = s.codePointAt(offset) + offset += Character.charCount(c) + j += codepoint_length(c) + } + if (j >= i) Some(offset) else None + } + } + } + + object Length extends Length +} diff -r f3f457535fe2 -r c6330e16743f src/Pure/General/length.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Pure/General/length.scala Wed Dec 21 11:14:55 2016 +0100 @@ -0,0 +1,33 @@ +/* Title: Pure/General/length.scala + Author: Makarius + +Text length wrt. encoding. +*/ + +package isabelle + + +trait Length +{ + def apply(text: String): Int + def offset(text: String, i: Int): Option[Text.Offset] +} + +object Length extends Length +{ + def apply(text: String): Int = text.length + def offset(text: String, i: Int): Option[Text.Offset] = + if (0 <= i && i <= text.length) Some(i) else None + + val encodings: List[(String, Length)] = + List( + "UTF-16" -> Length, + "UTF-8" -> UTF8.Length, + "codepoints" -> Codepoint.Length, + "symbols" -> Symbol.Length) + + def encoding(name: String): Length = + encodings.collectFirst({ case (a, length) if name == a => length }) getOrElse + error("Bad text length encoding: " + quote(name) + + " (expected " + commas_quote(encodings.map(_._1)) + ")") +} diff -r f3f457535fe2 -r c6330e16743f src/Pure/General/symbol.scala --- a/src/Pure/General/symbol.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Pure/General/symbol.scala Wed Dec 21 11:14:55 2016 +0100 @@ -128,14 +128,15 @@ def explode(text: CharSequence): List[Symbol] = iterator(text).toList - def advance_line_column(pos: (Int, Int), text: CharSequence): (Int, Int) = + def length(text: CharSequence): Int = iterator(text).length + + object Length extends isabelle.Length { - var (line, column) = pos - for (sym <- iterator(text)) { - if (is_newline(sym)) { line += 1; column = 1 } - else column += 1 - } - (line, column) + def apply(text: String): Int = length(text) + def offset(text: String, i: Int): Option[Text.Offset] = + if (i <= 0 || iterator(text).forall(s => s.length == 1)) isabelle.Length.offset(text, i) + else if (i <= length(text)) Some(iterator(text).take(i).mkString.length) + else None } diff -r f3f457535fe2 -r c6330e16743f src/Pure/General/word.scala --- a/src/Pure/General/word.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Pure/General/word.scala Wed Dec 21 11:14:55 2016 +0100 @@ -12,23 +12,6 @@ object Word { - /* codepoints */ - - def codepoint_iterator(str: String): Iterator[Int] = - new Iterator[Int] { - var offset = 0 - def hasNext: Boolean = offset < str.length - def next: Int = - { - val c = str.codePointAt(offset) - offset += Character.charCount(c) - c - } - } - - def codepoint(c: Int): String = new String(Array(c), 0, 1) - - /* directionality */ def bidi_detect(str: String): Boolean = @@ -51,7 +34,7 @@ } def perhaps_capitalize(str: String): String = - if (codepoint_iterator(str).forall(c => Character.isLowerCase(c) || Character.isDigit(c))) + if (Codepoint.iterator(str).forall(c => Character.isLowerCase(c) || Character.isDigit(c))) capitalize(str) else str @@ -70,10 +53,10 @@ } def unapply(str: String): Option[Case] = if (str.nonEmpty) { - if (codepoint_iterator(str).forall(Character.isLowerCase(_))) Some(Lowercase) - else if (codepoint_iterator(str).forall(Character.isUpperCase(_))) Some(Uppercase) + if (Codepoint.iterator(str).forall(Character.isLowerCase(_))) Some(Lowercase) + else if (Codepoint.iterator(str).forall(Character.isUpperCase(_))) Some(Uppercase) else { - val it = codepoint_iterator(str) + val it = Codepoint.iterator(str) if (Character.isUpperCase(it.next) && it.forall(Character.isLowerCase(_))) Some(Capitalized) else None diff -r f3f457535fe2 -r c6330e16743f src/Pure/Isar/document_structure.scala --- a/src/Pure/Isar/document_structure.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Pure/Isar/document_structure.scala Wed Dec 21 11:14:55 2016 +0100 @@ -190,8 +190,7 @@ toks.filterNot(_.is_space) match { case List(tok) if tok.is_comment => val s = tok.source - if (Word.codepoint_iterator(s).exists(c => - Character.isLetter(c) || Character.isDigit(c))) + if (Codepoint.iterator(s).exists(c => Character.isLetter(c) || Character.isDigit(c))) { if (s.startsWith("(**** ") && s.endsWith(" ****)")) Some(0) else if (s.startsWith("(*** ") && s.endsWith(" ***)")) Some(1) diff -r f3f457535fe2 -r c6330e16743f src/Pure/Isar/outer_syntax.scala --- a/src/Pure/Isar/outer_syntax.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Pure/Isar/outer_syntax.scala Wed Dec 21 11:14:55 2016 +0100 @@ -154,8 +154,8 @@ val name = cmd.source val offset = (0 /: span.takeWhile(_ != cmd)) { - case (i, tok) => i + Symbol.iterator(tok.source).length } - val end_offset = offset + Symbol.iterator(name).length + case (i, tok) => i + Symbol.length(tok.source) } + val end_offset = offset + Symbol.length(name) val pos = Position.Range(Text.Range(offset, end_offset) + 1) Command_Span.Command_Span(name, pos) } diff -r f3f457535fe2 -r c6330e16743f src/Pure/PIDE/line.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Pure/PIDE/line.scala Wed Dec 21 11:14:55 2016 +0100 @@ -0,0 +1,134 @@ +/* Title: Pure/PIDE/line.scala + Author: Makarius + +Line-oriented text. +*/ + +package isabelle + + +import scala.annotation.tailrec + + +object Line +{ + /* position */ + + object Position + { + val zero: Position = Position(0, 0) + } + + sealed case class Position(line: Int, column: Int) + { + def line1: Int = line + 1 + def column1: Int = column + 1 + def print: String = line1.toString + ":" + column1.toString + + def compare(that: Position): Int = + line compare that.line match { + case 0 => column compare that.column + case i => i + } + + def advance(text: String, length: Length = Length): Position = + if (text.isEmpty) this + else { + val lines = Library.split_lines(text) + val l = line + lines.length - 1 + val c = (if (l == line) column else 0) + length(Library.trim_line(lines.last)) + Position(l, c) + } + } + + + /* range (right-open interval) */ + + sealed case class Range(start: Position, stop: Position) + { + if (start.compare(stop) > 0) + error("Bad line range: " + start.print + ".." + stop.print) + + def print: String = start.print + ".." + stop.print + } + + + /* document with newline as separator (not terminator) */ + + object Document + { + val empty: Document = new Document("", Nil) + + def apply(lines: List[Line]): Document = + if (lines.isEmpty) empty + else new Document(lines.mkString("", "\n", ""), lines) + + def apply(text: String): Document = + if (text.contains('\r')) + apply(Library.cat_lines(Library.split_lines(text).map(Library.trim_line(_)))) + else if (text == "") Document.empty + else new Document(text, Library.split_lines(text).map(Line(_))) + } + + final class Document private(val text: String, val lines: List[Line]) + { + override def toString: String = text + + override def equals(that: Any): Boolean = + that match { + case other: Document => lines == other.lines + case _ => false + } + override def hashCode(): Int = lines.hashCode + + def position(offset: Text.Offset, length: Length = Length): Position = + { + @tailrec def move(i: Text.Offset, lines_count: Int, lines_rest: List[Line]): Position = + { + lines_rest match { + case Nil => require(i == 0); Position(lines_count, 0) + case line :: ls => + val n = line.text.length + if (ls.isEmpty || i <= n) + Position(lines_count, 0).advance(line.text.substring(n - i), length) + else move(i - (n + 1), lines_count + 1, ls) + } + } + move(offset, 0, lines) + } + + def offset(pos: Position, length: Length = Length): Option[Text.Offset] = + { + val l = pos.line + val c = pos.column + if (0 <= l && l < lines.length) { + val line_offset = + if (l == 0) 0 + else (0 /: lines.iterator.take(l - 1))({ case (n, line) => n + length(line.text) + 1 }) + length.offset(lines(l).text, c).map(line_offset + _) + } + else None + } + } + + + /* line text */ + + val empty: Line = new Line("") + def apply(text: String): Line = if (text == "") empty else new Line(text) +} + +final class Line private(val text: String) +{ + require(text.forall(c => c != '\r' && c != '\n')) + + lazy val length_codepoints: Int = Codepoint.iterator(text).length + + override def equals(that: Any): Boolean = + that match { + case other: Line => text == other.text + case _ => false + } + override def hashCode(): Int = text.hashCode + override def toString: String = text +} diff -r f3f457535fe2 -r c6330e16743f src/Pure/PIDE/protocol.scala --- a/src/Pure/PIDE/protocol.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Pure/PIDE/protocol.scala Wed Dec 21 11:14:55 2016 +0100 @@ -337,8 +337,7 @@ val toks_yxml = { import XML.Encode._ - val encode_tok: T[Token] = - (tok => pair(int, int)((tok.kind.id, Symbol.iterator(tok.source).length))) + val encode_tok: T[Token] = (tok => pair(int, int)((tok.kind.id, Symbol.length(tok.source)))) YXML.string_of_body(list(encode_tok)(toks)) } diff -r f3f457535fe2 -r c6330e16743f src/Pure/PIDE/rendering.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Pure/PIDE/rendering.scala Wed Dec 21 11:14:55 2016 +0100 @@ -0,0 +1,147 @@ +/* Title: Pure/PIDE/rendering.scala + Author: Makarius + +Isabelle-specific implementation of quasi-abstract rendering and +markup interpretation. +*/ + +package isabelle + + +object Rendering +{ + private val tooltip_descriptions = + Map( + Markup.CITATION -> "citation", + Markup.TOKEN_RANGE -> "inner syntax token", + Markup.FREE -> "free variable", + Markup.SKOLEM -> "skolem variable", + Markup.BOUND -> "bound variable", + Markup.VAR -> "schematic variable", + Markup.TFREE -> "free type variable", + Markup.TVAR -> "schematic type variable") + + private val tooltip_elements = + Markup.Elements(Markup.LANGUAGE, Markup.EXPRESSION, Markup.TIMING, Markup.ENTITY, + Markup.SORTING, Markup.TYPING, Markup.CLASS_PARAMETER, Markup.ML_TYPING, + Markup.ML_BREAKPOINT, Markup.PATH, Markup.DOC, Markup.URL, Markup.MARKDOWN_PARAGRAPH, + Markup.Markdown_List.name) ++ Markup.Elements(tooltip_descriptions.keySet) + + private def pretty_typing(kind: String, body: XML.Body): XML.Tree = + Pretty.block(XML.Text(kind) :: Pretty.brk(1) :: body) +} + +abstract class Rendering( + val snapshot: Document.Snapshot, + val options: Options, + val resources: Resources) +{ + override def toString: String = "Rendering(" + snapshot.toString + ")" + + + /* resources */ + + def resolve_file(name: String): String = + if (Path.is_valid(name)) + resources.append(snapshot.node_name.master_dir, Path.explode(name)) + else name + + + /* tooltips */ + + def tooltip_margin: Int + def timing_threshold: Double + + def tooltip(range: Text.Range): Option[Text.Info[XML.Body]] = + { + def add(prev: Text.Info[(Timing, Vector[(Boolean, XML.Tree)])], + r0: Text.Range, p: (Boolean, XML.Tree)): Text.Info[(Timing, Vector[(Boolean, XML.Tree)])] = + { + val r = snapshot.convert(r0) + val (t, info) = prev.info + if (prev.range == r) + Text.Info(r, (t, info :+ p)) + else Text.Info(r, (t, Vector(p))) + } + + val results = + snapshot.cumulate[Text.Info[(Timing, Vector[(Boolean, XML.Tree)])]]( + range, Text.Info(range, (Timing.zero, Vector.empty)), Rendering.tooltip_elements, _ => + { + case (Text.Info(r, (t1, info)), Text.Info(_, XML.Elem(Markup.Timing(t2), _))) => + Some(Text.Info(r, (t1 + t2, info))) + + case (prev, Text.Info(r, XML.Elem(Markup.Entity(kind, name), _))) + if kind != "" && + kind != Markup.ML_DEF && + kind != Markup.ML_OPEN && + kind != Markup.ML_STRUCTURE => + val kind1 = Word.implode(Word.explode('_', kind)) + val txt1 = + if (name == "") kind1 + else if (kind1 == "") quote(name) + else kind1 + " " + quote(name) + val t = prev.info._1 + val txt2 = + if (kind == Markup.COMMAND && t.elapsed.seconds >= timing_threshold) + "\n" + t.message + else "" + Some(add(prev, r, (true, XML.Text(txt1 + txt2)))) + + case (prev, Text.Info(r, XML.Elem(Markup.Path(name), _))) => + val file = resolve_file(name) + val text = + if (name == file) "file " + quote(file) + else "path " + quote(name) + "\nfile " + quote(file) + Some(add(prev, r, (true, XML.Text(text)))) + + case (prev, Text.Info(r, XML.Elem(Markup.Doc(name), _))) => + val text = "doc " + quote(name) + Some(add(prev, r, (true, XML.Text(text)))) + + case (prev, Text.Info(r, XML.Elem(Markup.Url(name), _))) => + Some(add(prev, r, (true, XML.Text("URL " + quote(name))))) + + case (prev, Text.Info(r, XML.Elem(Markup(name, _), body))) + if name == Markup.SORTING || name == Markup.TYPING => + Some(add(prev, r, (true, Rendering.pretty_typing("::", body)))) + + case (prev, Text.Info(r, XML.Elem(Markup(Markup.CLASS_PARAMETER, _), body))) => + Some(add(prev, r, (true, Pretty.block(0, body)))) + + case (prev, Text.Info(r, XML.Elem(Markup(Markup.ML_TYPING, _), body))) => + Some(add(prev, r, (false, Rendering.pretty_typing("ML:", body)))) + + case (prev, Text.Info(r, Protocol.ML_Breakpoint(breakpoint))) => + val text = + if (Debugger.breakpoint_state(breakpoint)) "breakpoint (enabled)" + else "breakpoint (disabled)" + Some(add(prev, r, (true, XML.Text(text)))) + + case (prev, Text.Info(r, XML.Elem(Markup.Language(language, _, _, _), _))) => + val lang = Word.implode(Word.explode('_', language)) + Some(add(prev, r, (true, XML.Text("language: " + lang)))) + + case (prev, Text.Info(r, XML.Elem(Markup.Expression(kind), _))) => + val descr = if (kind == "") "expression" else "expression: " + kind + Some(add(prev, r, (true, XML.Text(descr)))) + + case (prev, Text.Info(r, XML.Elem(Markup(Markup.MARKDOWN_PARAGRAPH, _), _))) => + Some(add(prev, r, (true, XML.Text("Markdown: paragraph")))) + case (prev, Text.Info(r, XML.Elem(Markup.Markdown_List(kind), _))) => + Some(add(prev, r, (true, XML.Text("Markdown: " + kind)))) + + case (prev, Text.Info(r, XML.Elem(Markup(name, _), _))) => + Rendering.tooltip_descriptions.get(name). + map(descr => add(prev, r, (true, XML.Text(descr)))) + }).map(_.info) + + results.map(_.info).flatMap(res => res._2.toList) match { + case Nil => None + case tips => + val r = Text.Range(results.head.range.start, results.last.range.stop) + val all_tips = (tips.filter(_._1) ++ tips.filter(!_._1).lastOption.toList).map(_._2) + Some(Text.Info(r, Library.separate(Pretty.fbrk, all_tips))) + } + } +} diff -r f3f457535fe2 -r c6330e16743f src/Pure/System/utf8.scala --- a/src/Pure/System/utf8.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Pure/System/utf8.scala Wed Dec 21 11:14:55 2016 +0100 @@ -21,6 +21,15 @@ def bytes(s: String): Array[Byte] = s.getBytes(charset) + object Length extends Codepoint.Length + { + override def codepoint_length(c: Int): Int = + if (c < 0x80) 1 + else if (c < 0x800) 2 + else if (c < 0x10000) 3 + else 4 + } + /* permissive UTF-8 decoding */ @@ -88,4 +97,3 @@ new Decode_Chars(decode, buffer, start, end) } } - diff -r f3f457535fe2 -r c6330e16743f src/Pure/build-jars --- a/src/Pure/build-jars Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Pure/build-jars Wed Dec 21 11:14:55 2016 +0100 @@ -39,6 +39,7 @@ GUI/wrap_panel.scala General/antiquote.scala General/bytes.scala + General/codepoint.scala General/completion.scala General/date.scala General/exn.scala @@ -48,6 +49,7 @@ General/graphics_file.scala General/http_server.scala General/json.scala + General/length.scala General/linear_set.scala General/logger.scala General/long_name.scala @@ -85,12 +87,14 @@ PIDE/document.scala PIDE/document_id.scala PIDE/editor.scala + PIDE/line.scala PIDE/markup.scala PIDE/markup_tree.scala PIDE/protocol.scala PIDE/protocol_message.scala PIDE/prover.scala PIDE/query_operation.scala + PIDE/rendering.scala PIDE/resources.scala PIDE/session.scala PIDE/text.scala @@ -141,25 +145,25 @@ library.scala term.scala term_xml.scala - "../Tools/Graphview/graph_file.scala" - "../Tools/Graphview/graph_panel.scala" - "../Tools/Graphview/graphview.scala" - "../Tools/Graphview/layout.scala" - "../Tools/Graphview/main_panel.scala" - "../Tools/Graphview/metrics.scala" - "../Tools/Graphview/model.scala" - "../Tools/Graphview/mutator.scala" - "../Tools/Graphview/mutator_dialog.scala" - "../Tools/Graphview/mutator_event.scala" - "../Tools/Graphview/popups.scala" - "../Tools/Graphview/shapes.scala" - "../Tools/Graphview/tree_panel.scala" - "../Tools/VSCode/src/channel.scala" - "../Tools/VSCode/src/document_model.scala" - "../Tools/VSCode/src/line.scala" - "../Tools/VSCode/src/protocol.scala" - "../Tools/VSCode/src/server.scala" - "../Tools/VSCode/src/uri_resources.scala" + ../Tools/Graphview/graph_file.scala + ../Tools/Graphview/graph_panel.scala + ../Tools/Graphview/graphview.scala + ../Tools/Graphview/layout.scala + ../Tools/Graphview/main_panel.scala + ../Tools/Graphview/metrics.scala + ../Tools/Graphview/model.scala + ../Tools/Graphview/mutator.scala + ../Tools/Graphview/mutator_dialog.scala + ../Tools/Graphview/mutator_event.scala + ../Tools/Graphview/popups.scala + ../Tools/Graphview/shapes.scala + ../Tools/Graphview/tree_panel.scala + ../Tools/VSCode/src/channel.scala + ../Tools/VSCode/src/document_model.scala + ../Tools/VSCode/src/protocol.scala + ../Tools/VSCode/src/server.scala + ../Tools/VSCode/src/vscode_rendering.scala + ../Tools/VSCode/src/vscode_resources.scala ) diff -r f3f457535fe2 -r c6330e16743f src/Tools/VSCode/etc/options --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Tools/VSCode/etc/options Wed Dec 21 11:14:55 2016 +0100 @@ -0,0 +1,7 @@ +(* :mode=isabelle-options: *) + +option vscode_tooltip_margin : int = 60 + -- "margin for tooltip pretty-printing" + +option vscode_timing_threshold : real = 0.1 + -- "default threshold for timing display (seconds)" diff -r f3f457535fe2 -r c6330e16743f src/Tools/VSCode/src/document_model.scala --- a/src/Tools/VSCode/src/document_model.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/VSCode/src/document_model.scala Wed Dec 21 11:14:55 2016 +0100 @@ -52,7 +52,10 @@ def unchanged: Document_Model = if (changed) copy(changed = false) else this - /* snapshot */ + /* snapshot and rendering */ def snapshot(): Document.Snapshot = session.snapshot(node_name, text_edits) + + def rendering(options: Options): VSCode_Rendering = + new VSCode_Rendering(snapshot(), options, session.resources) } diff -r f3f457535fe2 -r c6330e16743f src/Tools/VSCode/src/line.scala --- a/src/Tools/VSCode/src/line.scala Wed Dec 21 11:14:37 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -/* Title: Tools/VSCode/src/line.scala - Author: Makarius - -Line-oriented text. -*/ - -package isabelle.vscode - - -import isabelle._ - -import scala.annotation.tailrec - - -object Line -{ - /* position */ - - object Position - { - val zero: Position = Position(0, 0) - } - - sealed case class Position(line: Int, column: Int) - { - def line1: Int = line + 1 - def column1: Int = column + 1 - def print: String = line1.toString + ":" + column1.toString - - def compare(that: Position): Int = - line compare that.line match { - case 0 => column compare that.column - case i => i - } - - private def advance[A](iterator: Iterator[A], is_newline: A => Boolean): Position = - { - var l = line - var c = column - for (x <- iterator) { - if (is_newline(x)) { l += 1; c = 0 } else c += 1 - } - Position(l, c) - } - - def advance(text: String): Position = - if (text.isEmpty) this else advance[Char](text.iterator, _ == '\n') - - def advance_symbols(text: String): Position = - if (text.isEmpty) this else advance[Symbol.Symbol](Symbol.iterator(text), Symbol.is_newline _) - - def advance_codepoints(text: String): Position = - if (text.isEmpty) this else advance[Int](Word.codepoint_iterator(text), _ == 10) - } - - - /* range (right-open interval) */ - - sealed case class Range(start: Position, stop: Position) - { - if (start.compare(stop) > 0) - error("Bad line range: " + start.print + ".." + stop.print) - - def print: String = start.print + ".." + stop.print - } - - - /* document with newline as separator (not terminator) */ - - object Document - { - val empty: Document = new Document("", Nil) - - def apply(lines: List[Line]): Document = - if (lines.isEmpty) empty - else new Document(lines.mkString("", "\n", ""), lines) - - def apply(text: String): Document = - if (text.contains('\r')) - apply(Library.cat_lines(Library.split_lines(text).map(Library.trim_line(_)))) - else if (text == "") Document.empty - else new Document(text, Library.split_lines(text).map(Line(_))) - } - - final class Document private(val text: String, val lines: List[Line]) - { - override def toString: String = text - - override def equals(that: Any): Boolean = - that match { - case other: Document => lines == other.lines - case _ => false - } - override def hashCode(): Int = lines.hashCode - - private def position(advance: (Position, String) => Position, offset: Text.Offset): Position = - { - @tailrec def move(i: Text.Offset, lines_count: Int, lines_rest: List[Line]): Position = - { - lines_rest match { - case Nil => require(i == 0); Position(lines_count, 0) - case line :: ls => - val n = line.text.length - if (ls.isEmpty || i <= n) advance(Position(lines_count, 0), line.text.substring(n - i)) - else move(i - (n + 1), lines_count + 1, ls) - } - } - move(offset, 0, lines) - } - - def position(i: Text.Offset): Position = position(_.advance(_), i) - def position_symbols(i: Text.Offset): Position = position(_.advance_symbols(_), i) - def position_codepoints(i: Text.Offset): Position = position(_.advance_codepoints(_), i) - - // FIXME symbols, codepoints - def offset(pos: Position): Option[Text.Offset] = - { - val l = pos.line - val c = pos.column - if (0 <= l && l < lines.length) { - val line_offset = - if (l == 0) 0 - else (0 /: lines.take(l - 1))({ case (n, line) => n + line.text.length + 1 }) - if (c <= lines(l).text.length) Some(line_offset + c) else None - } - else None - } - } - - - /* line text */ - - val empty: Line = new Line("") - def apply(text: String): Line = if (text == "") empty else new Line(text) -} - -final class Line private(val text: String) -{ - require(text.forall(c => c != '\r' && c != '\n')) - - lazy val length_symbols: Int = Symbol.iterator(text).length - lazy val length_codepoints: Int = Word.codepoint_iterator(text).length - - override def equals(that: Any): Boolean = - that match { - case other: Line => text == other.text - case _ => false - } - override def hashCode(): Int = text.hashCode - override def toString: String = text -} diff -r f3f457535fe2 -r c6330e16743f src/Tools/VSCode/src/server.scala --- a/src/Tools/VSCode/src/server.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/VSCode/src/server.scala Wed Dec 21 11:14:55 2016 +0100 @@ -20,21 +20,28 @@ { /* Isabelle tool wrapper */ + private val default_text_length = "UTF-16" private lazy val default_logic = Isabelle_System.getenv("ISABELLE_LOGIC") val isabelle_tool = Isabelle_Tool("vscode_server", "VSCode Language Server for PIDE", args => { var log_file: Option[Path] = None + var text_length = Length.encoding(default_text_length) var dirs: List[Path] = Nil var logic = default_logic var modes: List[String] = Nil var options = Options.init() + def text_length_choice: String = + commas(Length.encodings.map( + { case (a, _) => if (a == default_text_length) a + " (default)" else a })) + val getopts = Getopts(""" Usage: isabelle vscode_server [OPTIONS] Options are: -L FILE enable logging on FILE + -T LENGTH text length encoding: """ + text_length_choice + """ -d DIR include session directory -l NAME logic session name (default ISABELLE_LOGIC=""" + quote(logic) + """) -m MODE add print mode for output @@ -43,6 +50,7 @@ Run the VSCode Language Server protocol (JSON RPC) over stdin/stdout. """, "L:" -> (arg => log_file = Some(Path.explode(arg))), + "T:" -> (arg => Length.encoding(arg)), "d:" -> (arg => dirs = dirs ::: List(Path.explode(arg))), "l:" -> (arg => logic = arg), "m:" -> (arg => modes = arg :: modes), @@ -56,7 +64,7 @@ error("Missing logic image " + quote(logic)) val channel = new Channel(System.in, System.out, log_file) - val server = new Server(channel, options, logic, dirs, modes) + val server = new Server(channel, options, text_length, logic, dirs, modes) // prevent spurious garbage on the main protocol channel val orig_out = System.out @@ -78,6 +86,7 @@ class Server( channel: Channel, options: Options, + text_length: Length = Length.encoding(Server.default_text_length), session_name: String = Server.default_logic, session_dirs: List[Path] = Nil, modes: List[String] = Nil) @@ -87,7 +96,7 @@ private val state = Synchronized(Server.State()) def session: Session = state.value.session getOrElse error("Session inactive") - def resources: URI_Resources = session.resources.asInstanceOf[URI_Resources] + def resources: VSCode_Resources = session.resources.asInstanceOf[VSCode_Resources] /* init and exit */ @@ -96,7 +105,7 @@ { val content = Build.session_content(options, false, session_dirs, session_name) val resources = - new URI_Resources(content.loaded_theories, content.known_theories, content.syntax) + new VSCode_Resources(content.loaded_theories, content.known_theories, content.syntax) val session = new Session(resources) { @@ -179,124 +188,21 @@ } - /* tooltips -- see $ISABELLE_HOME/src/Tools/jEdit/rendering.scala */ + /* hover */ def hover(uri: String, pos: Line.Position): Option[(Line.Range, List[String])] = for { model <- state.value.models.get(uri) - snapshot = model.snapshot() - offset <- model.doc.offset(pos) - info <- tooltip(snapshot, Text.Range(offset, offset + 1)) + rendering = model.rendering(options) + offset <- model.doc.offset(pos, text_length) + info <- rendering.tooltip(Text.Range(offset, offset + 1)) } yield { - val r = Line.Range(model.doc.position(info.range.start), model.doc.position(info.range.stop)) - val s = Pretty.string_of(info.info, margin = tooltip_margin.toDouble) - (r, List("```\n" + s + "\n```")) - } - - private val tooltip_descriptions = - Map( - Markup.CITATION -> "citation", - Markup.TOKEN_RANGE -> "inner syntax token", - Markup.FREE -> "free variable", - Markup.SKOLEM -> "skolem variable", - Markup.BOUND -> "bound variable", - Markup.VAR -> "schematic variable", - Markup.TFREE -> "free type variable", - Markup.TVAR -> "schematic type variable") - - private val tooltip_elements = - Markup.Elements(Markup.LANGUAGE, Markup.EXPRESSION, Markup.TIMING, Markup.ENTITY, - Markup.SORTING, Markup.TYPING, Markup.CLASS_PARAMETER, Markup.ML_TYPING, - Markup.ML_BREAKPOINT, Markup.PATH, Markup.DOC, Markup.URL, Markup.MARKDOWN_PARAGRAPH, - Markup.Markdown_List.name) ++ Markup.Elements(tooltip_descriptions.keySet) - - private def pretty_typing(kind: String, body: XML.Body): XML.Tree = - Pretty.block(XML.Text(kind) :: Pretty.brk(1) :: body) - - private def timing_threshold: Double = options.real("jedit_timing_threshold") - - def tooltip(snapshot: Document.Snapshot, range: Text.Range): Option[Text.Info[XML.Body]] = - { - def add(prev: Text.Info[(Timing, Vector[(Boolean, XML.Tree)])], - r0: Text.Range, p: (Boolean, XML.Tree)): Text.Info[(Timing, Vector[(Boolean, XML.Tree)])] = - { - val r = snapshot.convert(r0) - val (t, info) = prev.info - if (prev.range == r) - Text.Info(r, (t, info :+ p)) - else Text.Info(r, (t, Vector(p))) + val start = model.doc.position(info.range.start, text_length) + val stop = model.doc.position(info.range.stop, text_length) + val s = Pretty.string_of(info.info, margin = rendering.tooltip_margin) + (Line.Range(start, stop), List("```\n" + s + "\n```")) } - val results = - snapshot.cumulate[Text.Info[(Timing, Vector[(Boolean, XML.Tree)])]]( - range, Text.Info(range, (Timing.zero, Vector.empty)), tooltip_elements, _ => - { - case (Text.Info(r, (t1, info)), Text.Info(_, XML.Elem(Markup.Timing(t2), _))) => - Some(Text.Info(r, (t1 + t2, info))) - - case (prev, Text.Info(r, XML.Elem(Markup.Entity(kind, name), _))) - if kind != "" && - kind != Markup.ML_DEF && - kind != Markup.ML_OPEN && - kind != Markup.ML_STRUCTURE => - val kind1 = Word.implode(Word.explode('_', kind)) - val txt1 = - if (name == "") kind1 - else if (kind1 == "") quote(name) - else kind1 + " " + quote(name) - val t = prev.info._1 - val txt2 = - if (kind == Markup.COMMAND && t.elapsed.seconds >= timing_threshold) - "\n" + t.message - else "" - Some(add(prev, r, (true, XML.Text(txt1 + txt2)))) - - case (prev, Text.Info(r, XML.Elem(Markup.Doc(name), _))) => - val text = "doc " + quote(name) - Some(add(prev, r, (true, XML.Text(text)))) - - case (prev, Text.Info(r, XML.Elem(Markup.Url(name), _))) => - Some(add(prev, r, (true, XML.Text("URL " + quote(name))))) - - case (prev, Text.Info(r, XML.Elem(Markup(name, _), body))) - if name == Markup.SORTING || name == Markup.TYPING => - Some(add(prev, r, (true, pretty_typing("::", body)))) - - case (prev, Text.Info(r, XML.Elem(Markup(Markup.CLASS_PARAMETER, _), body))) => - Some(add(prev, r, (true, Pretty.block(0, body)))) - - case (prev, Text.Info(r, XML.Elem(Markup(Markup.ML_TYPING, _), body))) => - Some(add(prev, r, (false, pretty_typing("ML:", body)))) - - case (prev, Text.Info(r, XML.Elem(Markup.Language(language, _, _, _), _))) => - val lang = Word.implode(Word.explode('_', language)) - Some(add(prev, r, (true, XML.Text("language: " + lang)))) - - case (prev, Text.Info(r, XML.Elem(Markup.Expression(kind), _))) => - val descr = if (kind == "") "expression" else "expression: " + kind - Some(add(prev, r, (true, XML.Text(descr)))) - - case (prev, Text.Info(r, XML.Elem(Markup(Markup.MARKDOWN_PARAGRAPH, _), _))) => - Some(add(prev, r, (true, XML.Text("Markdown: paragraph")))) - case (prev, Text.Info(r, XML.Elem(Markup.Markdown_List(kind), _))) => - Some(add(prev, r, (true, XML.Text("Markdown: " + kind)))) - - case (prev, Text.Info(r, XML.Elem(Markup(name, _), _))) => - tooltip_descriptions.get(name). - map(descr => add(prev, r, (true, XML.Text(descr)))) - }).map(_.info) - - results.map(_.info).flatMap(res => res._2.toList) match { - case Nil => None - case tips => - val r = Text.Range(results.head.range.start, results.last.range.stop) - val all_tips = (tips.filter(_._1) ++ tips.filter(!_._1).lastOption.toList).map(_._2) - Some(Text.Info(r, Library.separate(Pretty.fbrk, all_tips))) - } - } - - def tooltip_margin: Int = options.int("jedit_tooltip_margin") - /* main loop */ diff -r f3f457535fe2 -r c6330e16743f src/Tools/VSCode/src/uri_resources.scala --- a/src/Tools/VSCode/src/uri_resources.scala Wed Dec 21 11:14:37 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* Title: Tools/VSCode/src/uri_resources.scala - Author: Makarius - -Resources based on file-system URIs. -*/ - -package isabelle.vscode - - -import isabelle._ - -import java.net.{URI, URISyntaxException} -import java.io.{File => JFile} - - -object URI_Resources -{ - def is_wellformed(uri: String): Boolean = - try { new JFile(new URI(uri)); true } - catch { case _: URISyntaxException | _: IllegalArgumentException => false } - - def canonical_file(uri: String): JFile = - new JFile(new URI(uri)).getCanonicalFile - - val empty: URI_Resources = - new URI_Resources(Set.empty, Map.empty, Outer_Syntax.empty) -} - -class URI_Resources( - loaded_theories: Set[String], - known_theories: Map[String, Document.Node.Name], - base_syntax: Outer_Syntax) - extends Resources(loaded_theories, known_theories, base_syntax) -{ - def node_name(uri: String): Document.Node.Name = - { - val file = URI_Resources.canonical_file(uri) // FIXME wellformed!? - val node = file.getPath - val theory = Thy_Header.thy_name_bootstrap(node).getOrElse("") - val master_dir = if (theory == "") "" else file.getParent - Document.Node.Name(node, master_dir, theory) - } -} diff -r f3f457535fe2 -r c6330e16743f src/Tools/VSCode/src/vscode_rendering.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Tools/VSCode/src/vscode_rendering.scala Wed Dec 21 11:14:55 2016 +0100 @@ -0,0 +1,21 @@ +/* Title: Tools/VSCode/src/vscode_rendering.scala + Author: Makarius + +Isabelle/VSCode-specific implementation of quasi-abstract rendering and +markup interpretation. +*/ + +package isabelle.vscode + + +import isabelle._ + + +class VSCode_Rendering(snapshot: Document.Snapshot, options: Options, resources: Resources) + extends Rendering(snapshot, options, resources) +{ + /* tooltips */ + + def tooltip_margin: Int = options.int("vscode_tooltip_margin") + def timing_threshold: Double = options.real("vscode_timing_threshold") +} diff -r f3f457535fe2 -r c6330e16743f src/Tools/VSCode/src/vscode_resources.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Tools/VSCode/src/vscode_resources.scala Wed Dec 21 11:14:55 2016 +0100 @@ -0,0 +1,43 @@ +/* Title: Tools/VSCode/src/vscode_resources.scala + Author: Makarius + +Resources for VSCode Language Server, based on file-system URIs. +*/ + +package isabelle.vscode + + +import isabelle._ + +import java.net.{URI, URISyntaxException} +import java.io.{File => JFile} + + +object VSCode_Resources +{ + def is_wellformed(uri: String): Boolean = + try { new JFile(new URI(uri)); true } + catch { case _: URISyntaxException | _: IllegalArgumentException => false } + + def canonical_file(uri: String): JFile = + new JFile(new URI(uri)).getCanonicalFile + + val empty: VSCode_Resources = + new VSCode_Resources(Set.empty, Map.empty, Outer_Syntax.empty) +} + +class VSCode_Resources( + loaded_theories: Set[String], + known_theories: Map[String, Document.Node.Name], + base_syntax: Outer_Syntax) + extends Resources(loaded_theories, known_theories, base_syntax) +{ + def node_name(uri: String): Document.Node.Name = + { + val file = VSCode_Resources.canonical_file(uri) // FIXME wellformed!? + val node = file.getPath + val theory = Thy_Header.thy_name_bootstrap(node).getOrElse("") + val master_dir = if (theory == "") "" else file.getParent + Document.Node.Name(node, master_dir, theory) + } +} diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/lib/Tools/jedit --- a/src/Tools/jEdit/lib/Tools/jedit Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/lib/Tools/jedit Wed Dec 21 11:14:55 2016 +0100 @@ -40,6 +40,7 @@ "src/jedit_editor.scala" "src/jedit_lib.scala" "src/jedit_options.scala" + "src/jedit_rendering.scala" "src/jedit_resources.scala" "src/jedit_sessions.scala" "src/keymap_merge.scala" @@ -53,7 +54,6 @@ "src/protocol_dockable.scala" "src/query_dockable.scala" "src/raw_output_dockable.scala" - "src/rendering.scala" "src/rich_text_area.scala" "src/scala_console.scala" "src/session_build.scala" diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/bibtex_jedit.scala --- a/src/Tools/jEdit/src/bibtex_jedit.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/bibtex_jedit.scala Wed Dec 21 11:14:55 2016 +0100 @@ -75,7 +75,7 @@ def completion( history: Completion.History, text_area: JEditTextArea, - rendering: Rendering): Option[Completion.Result] = + rendering: JEdit_Rendering): Option[Completion.Result] = { for { Text.Info(r, name) <- rendering.citation(JEdit_Lib.before_caret_range(text_area, rendering)) diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/completion_popup.scala --- a/src/Tools/jEdit/src/completion_popup.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/completion_popup.scala Wed Dec 21 11:14:55 2016 +0100 @@ -120,7 +120,7 @@ /* rendering */ - def rendering(rendering: Rendering, line_range: Text.Range): Option[Text.Info[Color]] = + def rendering(rendering: JEdit_Rendering, line_range: Text.Range): Option[Text.Info[Color]] = { active_range match { case Some(range) => range.try_restrict(line_range) @@ -153,7 +153,7 @@ def syntax_completion( history: Completion.History, explicit: Boolean, - opt_rendering: Option[Rendering]): Option[Completion.Result] = + opt_rendering: Option[JEdit_Rendering]): Option[Completion.Result] = { val buffer = text_area.getBuffer val decode = Isabelle_Encoding.is_active(buffer) @@ -185,7 +185,7 @@ /* path completion */ - def path_completion(rendering: Rendering): Option[Completion.Result] = + def path_completion(rendering: JEdit_Rendering): Option[Completion.Result] = { def complete(text: String): List[(String, List[String])] = { @@ -750,7 +750,7 @@ val size = { val geometry = JEdit_Lib.window_geometry(completion, completion) - val bounds = Rendering.popup_bounds + val bounds = JEdit_Rendering.popup_bounds val w = geometry.width min (screen.bounds.width * bounds).toInt min layered.getWidth val h = geometry.height min (screen.bounds.height * bounds).toInt min layered.getHeight new Dimension(w, h) diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/document_view.scala --- a/src/Tools/jEdit/src/document_view.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/document_view.scala Wed Dec 21 11:14:55 2016 +0100 @@ -60,7 +60,7 @@ { private val session = model.session - def get_rendering(): Rendering = Rendering(model.snapshot(), PIDE.options.value) + def get_rendering(): JEdit_Rendering = JEdit_Rendering(model.snapshot(), PIDE.options.value) val rich_text_area = new Rich_Text_Area(text_area.getView, text_area, get_rendering _, () => (), () => None, diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/fold_handling.scala --- a/src/Tools/jEdit/src/fold_handling.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/fold_handling.scala Wed Dec 21 11:14:55 2016 +0100 @@ -50,7 +50,7 @@ /* output: static document rendering */ - class Document_Fold_Handler(private val rendering: Rendering) + class Document_Fold_Handler(private val rendering: JEdit_Rendering) extends FoldHandler("isabelle-document") { override def equals(other: Any): Boolean = diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/graphview_dockable.scala --- a/src/Tools/jEdit/src/graphview_dockable.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/graphview_dockable.scala Wed Dec 21 11:14:55 2016 +0100 @@ -68,7 +68,7 @@ { Pretty_Tooltip.invoke(() => { - val rendering = Rendering(snapshot, options) + val rendering = JEdit_Rendering(snapshot, options) val info = Text.Info(Text.Range(~1), body) Pretty_Tooltip(view, parent, new Point(x, y), rendering, Command.Results.empty, info) }) diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/jedit_editor.scala --- a/src/Tools/jEdit/src/jedit_editor.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/jedit_editor.scala Wed Dec 21 11:14:55 2016 +0100 @@ -269,14 +269,13 @@ case Some(name) => JEdit_Lib.jedit_buffer(name) match { case Some(buffer) if offset > 0 => - val (line, column) = + val pos = JEdit_Lib.buffer_lock(buffer) { - ((1, 1) /: + (Line.Position.zero /: (Symbol.iterator(JEdit_Lib.buffer_text(buffer)). - zipWithIndex.takeWhile(p => p._2 < offset - 1).map(_._1)))( - Symbol.advance_line_column) + zipWithIndex.takeWhile(p => p._2 < offset - 1).map(_._1)))(_.advance(_)) } - Some(hyperlink_file(focus, name, line, column)) + Some(hyperlink_file(focus, name, pos.line1, pos.column1)) case _ => Some(hyperlink_file(focus, name, line)) } case None => None @@ -297,8 +296,8 @@ node.commands.iterator.takeWhile(_ != command).map(_.source) ++ (if (offset == 0) Iterator.empty else Iterator.single(command.source(Text.Range(0, command.chunk.decode(offset))))) - val (line, column) = ((1, 1) /: sources_iterator)(Symbol.advance_line_column) - Some(hyperlink_file(focus, file_name, line, column)) + val pos = (Line.Position.zero /: sources_iterator)(_.advance(_)) + Some(hyperlink_file(focus, file_name, pos.line1, pos.column1)) } } } diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/jedit_lib.scala --- a/src/Tools/jEdit/src/jedit_lib.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/jedit_lib.scala Wed Dec 21 11:14:55 2016 +0100 @@ -198,7 +198,7 @@ def caret_range(text_area: TextArea): Text.Range = point_range(text_area.getBuffer, text_area.getCaretPosition) - def before_caret_range(text_area: TextArea, rendering: Rendering): Text.Range = + def before_caret_range(text_area: TextArea, rendering: JEdit_Rendering): Text.Range = { val snapshot = rendering.snapshot val former_caret = snapshot.revert(text_area.getCaretPosition) diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/jedit_rendering.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Tools/jEdit/src/jedit_rendering.scala Wed Dec 21 11:14:55 2016 +0100 @@ -0,0 +1,802 @@ +/* Title: Tools/jEdit/src/jedit_rendering.scala + Author: Makarius + +Isabelle/jEdit-specific implementation of quasi-abstract rendering and +markup interpretation. +*/ + +package isabelle.jedit + + +import isabelle._ + +import java.awt.Color +import javax.swing.Icon + +import org.gjt.sp.jedit.syntax.{Token => JEditToken} +import org.gjt.sp.jedit.jEdit + +import scala.collection.immutable.SortedMap + + +object JEdit_Rendering +{ + def apply(snapshot: Document.Snapshot, options: Options): JEdit_Rendering = + new JEdit_Rendering(snapshot, options) + + + /* message priorities */ + + private val state_pri = 1 + private val writeln_pri = 2 + private val information_pri = 3 + private val tracing_pri = 4 + private val warning_pri = 5 + private val legacy_pri = 6 + private val error_pri = 7 + + private val message_pri = Map( + Markup.STATE -> state_pri, + Markup.STATE_MESSAGE -> state_pri, + Markup.WRITELN -> writeln_pri, + Markup.WRITELN_MESSAGE -> writeln_pri, + Markup.INFORMATION -> information_pri, + Markup.INFORMATION_MESSAGE -> information_pri, + Markup.TRACING -> tracing_pri, + Markup.TRACING_MESSAGE -> tracing_pri, + Markup.WARNING -> warning_pri, + Markup.WARNING_MESSAGE -> warning_pri, + Markup.LEGACY -> legacy_pri, + Markup.LEGACY_MESSAGE -> legacy_pri, + Markup.ERROR -> error_pri, + Markup.ERROR_MESSAGE -> error_pri) + + + /* popup window bounds */ + + def popup_bounds: Double = (PIDE.options.real("jedit_popup_bounds") max 0.2) min 0.8 + + + /* Isabelle/Isar token markup */ + + private val command_style: Map[String, Byte] = + { + import JEditToken._ + Map[String, Byte]( + Keyword.THY_END -> KEYWORD2, + Keyword.PRF_ASM -> KEYWORD3, + Keyword.PRF_ASM_GOAL -> KEYWORD3 + ).withDefaultValue(KEYWORD1) + } + + private val token_style: Map[Token.Kind.Value, Byte] = + { + import JEditToken._ + Map[Token.Kind.Value, Byte]( + Token.Kind.KEYWORD -> KEYWORD2, + Token.Kind.IDENT -> NULL, + Token.Kind.LONG_IDENT -> NULL, + Token.Kind.SYM_IDENT -> NULL, + Token.Kind.VAR -> NULL, + Token.Kind.TYPE_IDENT -> NULL, + Token.Kind.TYPE_VAR -> NULL, + Token.Kind.NAT -> NULL, + Token.Kind.FLOAT -> NULL, + Token.Kind.SPACE -> NULL, + Token.Kind.STRING -> LITERAL1, + Token.Kind.ALT_STRING -> LITERAL2, + Token.Kind.VERBATIM -> COMMENT3, + Token.Kind.CARTOUCHE -> COMMENT4, + Token.Kind.COMMENT -> COMMENT1, + Token.Kind.ERROR -> INVALID + ).withDefaultValue(NULL) + } + + def token_markup(syntax: Outer_Syntax, token: Token): Byte = + if (token.is_command) command_style(syntax.keywords.kinds.getOrElse(token.content, "")) + else if (token.is_keyword && token.source == Symbol.comment_decoded) JEditToken.NULL + else if (token.is_delimiter) JEditToken.OPERATOR + else token_style(token.kind) + + + /* Isabelle/ML token markup */ + + private val ml_token_style: Map[ML_Lex.Kind.Value, Byte] = + { + import JEditToken._ + Map[ML_Lex.Kind.Value, Byte]( + ML_Lex.Kind.KEYWORD -> NULL, + ML_Lex.Kind.IDENT -> NULL, + ML_Lex.Kind.LONG_IDENT -> NULL, + ML_Lex.Kind.TYPE_VAR -> NULL, + ML_Lex.Kind.WORD -> DIGIT, + ML_Lex.Kind.INT -> DIGIT, + ML_Lex.Kind.REAL -> DIGIT, + ML_Lex.Kind.CHAR -> LITERAL2, + ML_Lex.Kind.STRING -> LITERAL1, + ML_Lex.Kind.SPACE -> NULL, + ML_Lex.Kind.COMMENT -> COMMENT1, + ML_Lex.Kind.ANTIQ -> NULL, + ML_Lex.Kind.ANTIQ_START -> LITERAL4, + ML_Lex.Kind.ANTIQ_STOP -> LITERAL4, + ML_Lex.Kind.ANTIQ_OTHER -> NULL, + ML_Lex.Kind.ANTIQ_STRING -> NULL, + ML_Lex.Kind.ANTIQ_ALT_STRING -> NULL, + ML_Lex.Kind.ANTIQ_CARTOUCHE -> NULL, + ML_Lex.Kind.ERROR -> INVALID + ).withDefaultValue(NULL) + } + + def ml_token_markup(token: ML_Lex.Token): Byte = + if (!token.is_keyword) ml_token_style(token.kind) + else if (token.is_delimiter) JEditToken.OPERATOR + else if (ML_Lex.keywords2(token.source)) JEditToken.KEYWORD2 + else if (ML_Lex.keywords3(token.source)) JEditToken.KEYWORD3 + else JEditToken.KEYWORD1 + + + /* markup elements */ + + private val indentation_elements = + Markup.Elements(Markup.Command_Indent.name) + + private val semantic_completion_elements = + Markup.Elements(Markup.COMPLETION, Markup.NO_COMPLETION) + + private val language_context_elements = + Markup.Elements(Markup.STRING, Markup.ALT_STRING, Markup.VERBATIM, + Markup.CARTOUCHE, Markup.COMMENT, Markup.LANGUAGE, + Markup.ML_STRING, Markup.ML_COMMENT) + + private val language_elements = Markup.Elements(Markup.LANGUAGE) + + private val citation_elements = Markup.Elements(Markup.CITATION) + + private val breakpoint_elements = Markup.Elements(Markup.ML_BREAKPOINT) + + private val caret_focus_elements = Markup.Elements(Markup.ENTITY) + + private val highlight_elements = + Markup.Elements(Markup.EXPRESSION, Markup.CITATION, Markup.LANGUAGE, Markup.ML_TYPING, + Markup.TOKEN_RANGE, Markup.ENTITY, Markup.PATH, Markup.DOC, Markup.URL, Markup.SORTING, + Markup.TYPING, Markup.CLASS_PARAMETER, Markup.FREE, Markup.SKOLEM, Markup.BOUND, + Markup.VAR, Markup.TFREE, Markup.TVAR, Markup.ML_BREAKPOINT, + Markup.MARKDOWN_PARAGRAPH, Markup.Markdown_List.name) + + private val hyperlink_elements = + Markup.Elements(Markup.ENTITY, Markup.PATH, Markup.DOC, Markup.POSITION, + Markup.CITATION, Markup.URL) + + private val active_elements = + Markup.Elements(Markup.DIALOG, Markup.BROWSER, Markup.GRAPHVIEW, + Markup.SENDBACK, Markup.JEDIT_ACTION, Markup.SIMP_TRACE_PANEL) + + private val tooltip_message_elements = + Markup.Elements(Markup.WRITELN, Markup.INFORMATION, Markup.WARNING, Markup.LEGACY, Markup.ERROR, + Markup.BAD) + + private val gutter_elements = + Markup.Elements(Markup.WRITELN, Markup.INFORMATION, Markup.WARNING, Markup.LEGACY, Markup.ERROR) + + private val squiggly_elements = + Markup.Elements(Markup.WRITELN, Markup.INFORMATION, Markup.WARNING, Markup.LEGACY, Markup.ERROR) + + private val line_background_elements = + Markup.Elements(Markup.WRITELN_MESSAGE, Markup.STATE_MESSAGE, Markup.INFORMATION_MESSAGE, + Markup.TRACING_MESSAGE, Markup.WARNING_MESSAGE, Markup.LEGACY_MESSAGE, + Markup.ERROR_MESSAGE) + + private val separator_elements = + Markup.Elements(Markup.SEPARATOR) + + private val background_elements = + Protocol.proper_status_elements + Markup.WRITELN_MESSAGE + + Markup.STATE_MESSAGE + Markup.INFORMATION_MESSAGE + + Markup.TRACING_MESSAGE + Markup.WARNING_MESSAGE + + Markup.LEGACY_MESSAGE + Markup.ERROR_MESSAGE + + Markup.BAD + Markup.INTENSIFY + Markup.ENTITY + + Markup.Markdown_Item.name ++ active_elements + + private val foreground_elements = + Markup.Elements(Markup.STRING, Markup.ALT_STRING, Markup.VERBATIM, + Markup.CARTOUCHE, Markup.ANTIQUOTED) + + private val bullet_elements = + Markup.Elements(Markup.BULLET, Markup.ML_BREAKPOINT) + + private val fold_depth_elements = + Markup.Elements(Markup.TEXT_FOLD, Markup.GOAL, Markup.SUBGOAL) +} + + +class JEdit_Rendering(snapshot: Document.Snapshot, options: Options) + extends Rendering(snapshot, options, PIDE.resources) +{ + /* colors */ + + def color_value(s: String): Color = Color_Value(options.string(s)) + + val outdated_color = color_value("outdated_color") + val unprocessed_color = color_value("unprocessed_color") + val unprocessed1_color = color_value("unprocessed1_color") + val running_color = color_value("running_color") + val running1_color = color_value("running1_color") + val bullet_color = color_value("bullet_color") + val tooltip_color = color_value("tooltip_color") + val writeln_color = color_value("writeln_color") + val information_color = color_value("information_color") + val warning_color = color_value("warning_color") + val legacy_color = color_value("legacy_color") + val error_color = color_value("error_color") + val writeln_message_color = color_value("writeln_message_color") + val information_message_color = color_value("information_message_color") + val tracing_message_color = color_value("tracing_message_color") + val warning_message_color = color_value("warning_message_color") + val legacy_message_color = color_value("legacy_message_color") + val error_message_color = color_value("error_message_color") + val spell_checker_color = color_value("spell_checker_color") + val bad_color = color_value("bad_color") + val intensify_color = color_value("intensify_color") + val entity_color = color_value("entity_color") + val entity_ref_color = color_value("entity_ref_color") + val breakpoint_disabled_color = color_value("breakpoint_disabled_color") + val breakpoint_enabled_color = color_value("breakpoint_enabled_color") + val caret_debugger_color = color_value("caret_debugger_color") + val quoted_color = color_value("quoted_color") + val antiquoted_color = color_value("antiquoted_color") + val antiquote_color = color_value("antiquote_color") + val highlight_color = color_value("highlight_color") + val hyperlink_color = color_value("hyperlink_color") + val active_color = color_value("active_color") + val active_hover_color = color_value("active_hover_color") + val active_result_color = color_value("active_result_color") + val keyword1_color = color_value("keyword1_color") + val keyword2_color = color_value("keyword2_color") + val keyword3_color = color_value("keyword3_color") + val quasi_keyword_color = color_value("quasi_keyword_color") + val improper_color = color_value("improper_color") + val operator_color = color_value("operator_color") + val caret_invisible_color = color_value("caret_invisible_color") + val completion_color = color_value("completion_color") + val search_color = color_value("search_color") + + val tfree_color = color_value("tfree_color") + val tvar_color = color_value("tvar_color") + val free_color = color_value("free_color") + val skolem_color = color_value("skolem_color") + val bound_color = color_value("bound_color") + val var_color = color_value("var_color") + val inner_numeral_color = color_value("inner_numeral_color") + val inner_quoted_color = color_value("inner_quoted_color") + val inner_cartouche_color = color_value("inner_cartouche_color") + val inner_comment_color = color_value("inner_comment_color") + val dynamic_color = color_value("dynamic_color") + val class_parameter_color = color_value("class_parameter_color") + + val markdown_item_color1 = color_value("markdown_item_color1") + val markdown_item_color2 = color_value("markdown_item_color2") + val markdown_item_color3 = color_value("markdown_item_color3") + val markdown_item_color4 = color_value("markdown_item_color4") + + + /* indentation */ + + def indentation(range: Text.Range): Int = + snapshot.select(range, JEdit_Rendering.indentation_elements, _ => + { + case Text.Info(_, XML.Elem(Markup.Command_Indent(i), _)) => Some(i) + case _ => None + }).headOption.map(_.info).getOrElse(0) + + + /* completion */ + + def semantic_completion(completed_range: Option[Text.Range], range: Text.Range) + : Option[Text.Info[Completion.Semantic]] = + if (snapshot.is_outdated) None + else { + snapshot.select(range, JEdit_Rendering.semantic_completion_elements, _ => + { + case Completion.Semantic.Info(info) => + completed_range match { + case Some(range0) if range0.contains(info.range) && range0 != info.range => None + case _ => Some(info) + } + case _ => None + }).headOption.map(_.info) + } + + def language_context(range: Text.Range): Option[Completion.Language_Context] = + snapshot.select(range, JEdit_Rendering.language_context_elements, _ => + { + case Text.Info(_, XML.Elem(Markup.Language(language, symbols, antiquotes, delimited), _)) => + if (delimited) Some(Completion.Language_Context(language, symbols, antiquotes)) + else None + case Text.Info(_, elem) + if elem.name == Markup.ML_STRING || elem.name == Markup.ML_COMMENT => + Some(Completion.Language_Context.ML_inner) + case Text.Info(_, _) => + Some(Completion.Language_Context.inner) + }).headOption.map(_.info) + + def language_path(range: Text.Range): Option[Text.Range] = + snapshot.select(range, JEdit_Rendering.language_elements, _ => + { + case Text.Info(info_range, XML.Elem(Markup.Language(Markup.Language.PATH, _, _, _), _)) => + Some(snapshot.convert(info_range)) + case _ => None + }).headOption.map(_.info) + + def citation(range: Text.Range): Option[Text.Info[String]] = + snapshot.select(range, JEdit_Rendering.citation_elements, _ => + { + case Text.Info(info_range, XML.Elem(Markup.Citation(name), _)) => + Some(Text.Info(snapshot.convert(info_range), name)) + case _ => None + }).headOption.map(_.info) + + + /* spell checker */ + + private lazy val spell_checker_elements = + Markup.Elements(space_explode(',', options.string("spell_checker_elements")): _*) + + def spell_checker_ranges(range: Text.Range): List[Text.Range] = + snapshot.select(range, spell_checker_elements, _ => _ => Some(())).map(_.range) + + def spell_checker_point(range: Text.Range): Option[Text.Range] = + snapshot.select(range, spell_checker_elements, _ => + { + case info => Some(snapshot.convert(info.range)) + }).headOption.map(_.info) + + + /* breakpoints */ + + def breakpoint(range: Text.Range): Option[(Command, Long)] = + if (snapshot.is_outdated) None + else + snapshot.select(range, JEdit_Rendering.breakpoint_elements, command_states => + { + case Text.Info(_, Protocol.ML_Breakpoint(breakpoint)) => + command_states match { + case st :: _ => Some((st.command, breakpoint)) + case _ => None + } + case _ => None + }).headOption.map(_.info) + + + /* command status overview */ + + def overview_color(range: Text.Range): Option[Color] = + { + if (snapshot.is_outdated) None + else { + val results = + snapshot.cumulate[List[Markup]](range, Nil, Protocol.liberal_status_elements, _ => + { + case (status, Text.Info(_, elem)) => Some(elem.markup :: status) + }, status = true) + if (results.isEmpty) None + else { + val status = Protocol.Status.make(results.iterator.flatMap(_.info)) + + if (status.is_running) Some(running_color) + else if (status.is_failed) Some(error_color) + else if (status.is_warned) Some(warning_color) + else if (status.is_unprocessed) Some(unprocessed_color) + else None + } + } + } + + + /* caret focus */ + + def entity_focus(range: Text.Range, + check: (Boolean, Long) => Boolean = (is_def: Boolean, i: Long) => is_def): Set[Long] = + { + val results = + snapshot.cumulate[Set[Long]](range, Set.empty, JEdit_Rendering.caret_focus_elements, _ => + { + case (serials, Text.Info(_, XML.Elem(Markup(Markup.ENTITY, props), _))) => + props match { + case Markup.Entity.Def(i) if check(true, i) => Some(serials + i) + case Markup.Entity.Ref(i) if check(false, i) => Some(serials + i) + case _ => None + } + case _ => None + }) + (Set.empty[Long] /: results){ case (s1, Text.Info(_, s2)) => s1 ++ s2 } + } + + def caret_focus(caret_range: Text.Range, visible_range: Text.Range): Set[Long] = + { + val focus_defs = entity_focus(caret_range) + if (focus_defs.nonEmpty) focus_defs + else { + val visible_defs = entity_focus(visible_range) + entity_focus(caret_range, (is_def: Boolean, i: Long) => !is_def && visible_defs.contains(i)) + } + } + + def caret_focus_ranges(caret_range: Text.Range, visible_range: Text.Range): List[Text.Range] = + { + val focus = caret_focus(caret_range, visible_range) + if (focus.nonEmpty) { + val results = + snapshot.cumulate[Boolean](visible_range, false, JEdit_Rendering.caret_focus_elements, _ => + { + case (_, Text.Info(_, XML.Elem(Markup(Markup.ENTITY, props), _))) => + props match { + case Markup.Entity.Def(i) if focus(i) => Some(true) + case Markup.Entity.Ref(i) if focus(i) => Some(true) + case _ => None + } + }) + for (info <- results if info.info) yield info.range + } + else Nil + } + + def entity_ref(range: Text.Range, focus: Set[Long]): List[Text.Info[Color]] = + snapshot.select(range, JEdit_Rendering.caret_focus_elements, _ => + { + case Text.Info(_, XML.Elem(Markup(Markup.ENTITY, Markup.Entity.Ref(i)), _)) if focus(i) => + Some(entity_ref_color) + case _ => None + }) + + + /* highlighted area */ + + def highlight(range: Text.Range): Option[Text.Info[Color]] = + snapshot.select(range, JEdit_Rendering.highlight_elements, _ => + { + case info => Some(Text.Info(snapshot.convert(info.range), highlight_color)) + }).headOption.map(_.info) + + + /* hyperlinks */ + + def hyperlink(range: Text.Range): Option[Text.Info[PIDE.editor.Hyperlink]] = + { + snapshot.cumulate[Vector[Text.Info[PIDE.editor.Hyperlink]]]( + range, Vector.empty, JEdit_Rendering.hyperlink_elements, _ => + { + case (links, Text.Info(info_range, XML.Elem(Markup.Path(name), _))) => + val link = PIDE.editor.hyperlink_file(true, resolve_file(name)) + Some(links :+ Text.Info(snapshot.convert(info_range), link)) + + case (links, Text.Info(info_range, XML.Elem(Markup.Doc(name), _))) => + PIDE.editor.hyperlink_doc(name).map(link => + (links :+ Text.Info(snapshot.convert(info_range), link))) + + case (links, Text.Info(info_range, XML.Elem(Markup.Url(name), _))) => + val link = PIDE.editor.hyperlink_url(name) + Some(links :+ Text.Info(snapshot.convert(info_range), link)) + + case (links, Text.Info(info_range, XML.Elem(Markup(Markup.ENTITY, props), _))) + if !props.exists( + { case (Markup.KIND, Markup.ML_OPEN) => true + case (Markup.KIND, Markup.ML_STRUCTURE) => true + case _ => false }) => + val opt_link = PIDE.editor.hyperlink_def_position(true, snapshot, props) + opt_link.map(link => links :+ Text.Info(snapshot.convert(info_range), link)) + + case (links, Text.Info(info_range, XML.Elem(Markup(Markup.POSITION, props), _))) => + val opt_link = PIDE.editor.hyperlink_position(true, snapshot, props) + opt_link.map(link => links :+ Text.Info(snapshot.convert(info_range), link)) + + case (links, Text.Info(info_range, XML.Elem(Markup.Citation(name), _))) => + val opt_link = + Bibtex_JEdit.entries_iterator.collectFirst( + { case (a, buffer, offset) if a == name => + PIDE.editor.hyperlink_buffer(true, buffer, offset) }) + opt_link.map(link => links :+ Text.Info(snapshot.convert(info_range), link)) + + case _ => None + }) match { case Text.Info(_, _ :+ info) :: _ => Some(info) case _ => None } + } + + + /* active elements */ + + def active(range: Text.Range): Option[Text.Info[XML.Elem]] = + snapshot.select(range, JEdit_Rendering.active_elements, command_states => + { + case Text.Info(info_range, elem) => + if (elem.name == Markup.DIALOG) { + elem match { + case Protocol.Dialog(_, serial, _) + if !command_states.exists(st => st.results.defined(serial)) => + Some(Text.Info(snapshot.convert(info_range), elem)) + case _ => None + } + } + else Some(Text.Info(snapshot.convert(info_range), elem)) + }).headOption.map(_.info) + + def command_results(range: Text.Range): Command.Results = + Command.State.merge_results( + snapshot.select[List[Command.State]](range, Markup.Elements.full, command_states => + { case _ => Some(command_states) }).flatMap(_.info)) + + + /* tooltip messages */ + + def tooltip_message(range: Text.Range): Option[Text.Info[XML.Body]] = + { + val results = + snapshot.cumulate[List[Text.Info[Command.Results.Entry]]]( + range, Nil, JEdit_Rendering.tooltip_message_elements, _ => + { + case (msgs, Text.Info(info_range, msg @ XML.Elem(Markup(Markup.BAD, _), body))) + if body.nonEmpty => + val entry: Command.Results.Entry = (Document_ID.make(), msg) + Some(Text.Info(snapshot.convert(info_range), entry) :: msgs) + + case (msgs, Text.Info(info_range, + XML.Elem(Markup(name, props @ Markup.Serial(serial)), body))) => + val entry: Command.Results.Entry = + serial -> XML.Elem(Markup(Markup.message(name), props), body) + Some(Text.Info(snapshot.convert(info_range), entry) :: msgs) + + case _ => None + }).flatMap(_.info) + if (results.isEmpty) None + else { + val r = Text.Range(results.head.range.start, results.last.range.stop) + val msgs = Command.Results.make(results.map(_.info)) + Some(Text.Info(r, Pretty.separate(msgs.iterator.map(_._2).toList))) + } + } + + + /* tooltips */ + + def tooltip_margin: Int = options.int("jedit_tooltip_margin") + def timing_threshold: Double = options.real("jedit_timing_threshold") + + lazy val tooltip_close_icon = JEdit_Lib.load_icon(options.string("tooltip_close_icon")) + lazy val tooltip_detach_icon = JEdit_Lib.load_icon(options.string("tooltip_detach_icon")) + + + /* gutter */ + + private def gutter_message_pri(msg: XML.Tree): Int = + if (Protocol.is_error(msg)) JEdit_Rendering.error_pri + else if (Protocol.is_legacy(msg)) JEdit_Rendering.legacy_pri + else if (Protocol.is_warning(msg)) JEdit_Rendering.warning_pri + else if (Protocol.is_information(msg)) JEdit_Rendering.information_pri + else 0 + + private lazy val gutter_message_content = Map( + JEdit_Rendering.information_pri -> + (JEdit_Lib.load_icon(options.string("gutter_information_icon")), information_message_color), + JEdit_Rendering.warning_pri -> + (JEdit_Lib.load_icon(options.string("gutter_warning_icon")), warning_message_color), + JEdit_Rendering.legacy_pri -> + (JEdit_Lib.load_icon(options.string("gutter_legacy_icon")), warning_message_color), + JEdit_Rendering.error_pri -> + (JEdit_Lib.load_icon(options.string("gutter_error_icon")), error_message_color)) + + def gutter_content(range: Text.Range): Option[(Icon, Color)] = + { + val pris = + snapshot.cumulate[Int](range, 0, JEdit_Rendering.gutter_elements, _ => + { + case (pri, Text.Info(_, msg @ XML.Elem(Markup(_, Markup.Serial(serial)), _))) => + Some(pri max gutter_message_pri(msg)) + case _ => None + }).map(_.info) + + gutter_message_content.get((0 /: pris)(_ max _)) + } + + + /* squiggly underline */ + + private lazy val squiggly_colors = Map( + JEdit_Rendering.writeln_pri -> writeln_color, + JEdit_Rendering.information_pri -> information_color, + JEdit_Rendering.warning_pri -> warning_color, + JEdit_Rendering.legacy_pri -> legacy_color, + JEdit_Rendering.error_pri -> error_color) + + def squiggly_underline(range: Text.Range): List[Text.Info[Color]] = + { + val results = + snapshot.cumulate[Int](range, 0, JEdit_Rendering.squiggly_elements, _ => + { + case (pri, Text.Info(_, elem)) => Some(pri max JEdit_Rendering.message_pri(elem.name)) + }) + for { + Text.Info(r, pri) <- results + color <- squiggly_colors.get(pri) + } yield Text.Info(r, color) + } + + + /* message output */ + + private lazy val message_colors = Map( + JEdit_Rendering.writeln_pri -> writeln_message_color, + JEdit_Rendering.information_pri -> information_message_color, + JEdit_Rendering.tracing_pri -> tracing_message_color, + JEdit_Rendering.warning_pri -> warning_message_color, + JEdit_Rendering.legacy_pri -> legacy_message_color, + JEdit_Rendering.error_pri -> error_message_color) + + def line_background(range: Text.Range): Option[(Color, Boolean)] = + { + val results = + snapshot.cumulate[Int](range, 0, JEdit_Rendering.line_background_elements, _ => + { + case (pri, Text.Info(_, elem)) => Some(pri max JEdit_Rendering.message_pri(elem.name)) + }) + val pri = (0 /: results) { case (p1, Text.Info(_, p2)) => p1 max p2 } + + message_colors.get(pri).map(message_color => + { + val is_separator = + snapshot.cumulate[Boolean](range, false, JEdit_Rendering.separator_elements, _ => + { + case _ => Some(true) + }).exists(_.info) + (message_color, is_separator) + }) + } + + def output_messages(results: Command.Results): List[XML.Tree] = + { + val (states, other) = + results.iterator.map(_._2).filterNot(Protocol.is_result(_)).toList + .partition(Protocol.is_state(_)) + states ::: other + } + + + /* text background */ + + def background(range: Text.Range, focus: Set[Long]): List[Text.Info[Color]] = + { + for { + Text.Info(r, result) <- + snapshot.cumulate[(List[Markup], Option[Color])]( + range, (List(Markup.Empty), None), JEdit_Rendering.background_elements, + command_states => + { + case (((status, color), Text.Info(_, XML.Elem(markup, _)))) + if status.nonEmpty && Protocol.proper_status_elements(markup.name) => + Some((markup :: status, color)) + case (_, Text.Info(_, XML.Elem(Markup(Markup.BAD, _), _))) => + Some((Nil, Some(bad_color))) + case (_, Text.Info(_, XML.Elem(Markup(Markup.INTENSIFY, _), _))) => + Some((Nil, Some(intensify_color))) + case (_, Text.Info(_, XML.Elem(Markup(Markup.ENTITY, props), _))) => + props match { + case Markup.Entity.Def(i) if focus(i) => Some((Nil, Some(entity_color))) + case Markup.Entity.Ref(i) if focus(i) => Some((Nil, Some(entity_color))) + case _ => None + } + case (_, Text.Info(_, XML.Elem(Markup.Markdown_Item(depth), _))) => + val color = + depth match { + case 1 => markdown_item_color1 + case 2 => markdown_item_color2 + case 3 => markdown_item_color3 + case _ => markdown_item_color4 + } + Some((Nil, Some(color))) + case (acc, Text.Info(_, Protocol.Dialog(_, serial, result))) => + command_states.collectFirst( + { case st if st.results.defined(serial) => st.results.get(serial).get }) match + { + case Some(Protocol.Dialog_Result(res)) if res == result => + Some((Nil, Some(active_result_color))) + case _ => + Some((Nil, Some(active_color))) + } + case (_, Text.Info(_, elem)) => + if (JEdit_Rendering.active_elements(elem.name)) Some((Nil, Some(active_color))) + else None + }) + color <- + (result match { + case (markups, opt_color) if markups.nonEmpty => + val status = Protocol.Status.make(markups.iterator) + if (status.is_unprocessed) Some(unprocessed1_color) + else if (status.is_running) Some(running1_color) + else opt_color + case (_, opt_color) => opt_color + }) + } yield Text.Info(r, color) + } + + + /* text foreground */ + + def foreground(range: Text.Range): List[Text.Info[Color]] = + snapshot.select(range, JEdit_Rendering.foreground_elements, _ => + { + case Text.Info(_, elem) => + if (elem.name == Markup.ANTIQUOTED) Some(antiquoted_color) else Some(quoted_color) + }) + + + /* text color */ + + val foreground_color = jEdit.getColorProperty("view.fgColor") + + private lazy val text_colors: Map[String, Color] = Map( + Markup.KEYWORD1 -> keyword1_color, + Markup.KEYWORD2 -> keyword2_color, + Markup.KEYWORD3 -> keyword3_color, + Markup.QUASI_KEYWORD -> quasi_keyword_color, + Markup.IMPROPER -> improper_color, + Markup.OPERATOR -> operator_color, + Markup.STRING -> foreground_color, + Markup.ALT_STRING -> foreground_color, + Markup.VERBATIM -> foreground_color, + Markup.CARTOUCHE -> foreground_color, + Markup.LITERAL -> keyword1_color, + Markup.DELIMITER -> foreground_color, + Markup.TFREE -> tfree_color, + Markup.TVAR -> tvar_color, + Markup.FREE -> free_color, + Markup.SKOLEM -> skolem_color, + Markup.BOUND -> bound_color, + Markup.VAR -> var_color, + Markup.INNER_STRING -> inner_quoted_color, + Markup.INNER_CARTOUCHE -> inner_cartouche_color, + Markup.INNER_COMMENT -> inner_comment_color, + Markup.DYNAMIC_FACT -> dynamic_color, + Markup.CLASS_PARAMETER -> class_parameter_color, + Markup.ANTIQUOTE -> antiquote_color, + Markup.ML_KEYWORD1 -> keyword1_color, + Markup.ML_KEYWORD2 -> keyword2_color, + Markup.ML_KEYWORD3 -> keyword3_color, + Markup.ML_DELIMITER -> foreground_color, + Markup.ML_NUMERAL -> inner_numeral_color, + Markup.ML_CHAR -> inner_quoted_color, + Markup.ML_STRING -> inner_quoted_color, + Markup.ML_COMMENT -> inner_comment_color, + Markup.SML_STRING -> inner_quoted_color, + Markup.SML_COMMENT -> inner_comment_color) + + private lazy val text_color_elements = + Markup.Elements(text_colors.keySet) + + def text_color(range: Text.Range, color: Color): List[Text.Info[Color]] = + { + if (color == Token_Markup.hidden_color) List(Text.Info(range, color)) + else + snapshot.cumulate(range, color, text_color_elements, _ => + { + case (_, Text.Info(_, elem)) => text_colors.get(elem.name) + }) + } + + + /* virtual bullets */ + + def bullet(range: Text.Range): List[Text.Info[Color]] = + snapshot.select(range, JEdit_Rendering.bullet_elements, _ => + { + case Text.Info(_, Protocol.ML_Breakpoint(breakpoint)) => + Debugger.active_breakpoint_state(breakpoint).map(b => + if (b) breakpoint_enabled_color else breakpoint_disabled_color) + case _ => Some(bullet_color) + }) + + + /* text folds */ + + def fold_depth(range: Text.Range): List[Text.Info[Int]] = + snapshot.cumulate[Int](range, 0, JEdit_Rendering.fold_depth_elements, _ => + { + case (depth, _) => Some(depth + 1) + }) +} diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/output_dockable.scala --- a/src/Tools/jEdit/src/output_dockable.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/output_dockable.scala Wed Dec 21 11:14:55 2016 +0100 @@ -66,7 +66,7 @@ val new_output = if (!restriction.isDefined || restriction.get.contains(new_command)) { - val rendering = Rendering(new_snapshot, PIDE.options.value) + val rendering = JEdit_Rendering(new_snapshot, PIDE.options.value) rendering.output_messages(new_results) } else current_output diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/plugin.scala --- a/src/Tools/jEdit/src/plugin.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/plugin.scala Wed Dec 21 11:14:55 2016 +0100 @@ -158,7 +158,7 @@ } } - def rendering(view: View): Rendering = GUI_Thread.now + def rendering(view: View): JEdit_Rendering = GUI_Thread.now { val text_area = view.getTextArea document_view(text_area) match { diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/pretty_text_area.scala --- a/src/Tools/jEdit/src/pretty_text_area.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/pretty_text_area.scala Wed Dec 21 11:14:55 2016 +0100 @@ -54,10 +54,10 @@ } private def text_rendering(base_snapshot: Document.Snapshot, base_results: Command.Results, - formatted_body: XML.Body): (String, Rendering) = + formatted_body: XML.Body): (String, JEdit_Rendering) = { val (text, state) = document_state(base_snapshot, base_results, formatted_body) - val rendering = Rendering(state.snapshot(), PIDE.options.value) + val rendering = JEdit_Rendering(state.snapshot(), PIDE.options.value) (text, rendering) } } @@ -75,7 +75,7 @@ private var current_body: XML.Body = Nil private var current_base_snapshot = Document.Snapshot.init private var current_base_results = Command.Results.empty - private var current_rendering: Rendering = + private var current_rendering: JEdit_Rendering = Pretty_Text_Area.text_rendering(current_base_snapshot, current_base_results, Nil)._2 private var future_refresh: Option[Future[Unit]] = None diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/pretty_tooltip.scala --- a/src/Tools/jEdit/src/pretty_tooltip.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/pretty_tooltip.scala Wed Dec 21 11:14:55 2016 +0100 @@ -43,7 +43,7 @@ view: View, parent: JComponent, location: Point, - rendering: Rendering, + rendering: JEdit_Rendering, results: Command.Results, info: Text.Info[XML.Body]) { @@ -167,7 +167,7 @@ layered: JLayeredPane, val original_parent: JComponent, location: Point, - rendering: Rendering, + rendering: JEdit_Rendering, private val results: Command.Results, private val info: Text.Info[XML.Body]) extends JPanel(new BorderLayout) { @@ -246,7 +246,7 @@ val screen = JEdit_Lib.screen_location(layered, location) val size = { - val bounds = Rendering.popup_bounds + val bounds = JEdit_Rendering.popup_bounds val w_max = layered.getWidth min (screen.bounds.width * bounds).toInt val h_max = layered.getHeight min (screen.bounds.height * bounds).toInt diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/rendering.scala --- a/src/Tools/jEdit/src/rendering.scala Wed Dec 21 11:14:37 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,923 +0,0 @@ -/* Title: Tools/jEdit/src/rendering.scala - Author: Makarius - -Isabelle-specific implementation of quasi-abstract rendering and -markup interpretation. -*/ - -package isabelle.jedit - - -import isabelle._ - -import java.awt.Color -import javax.swing.Icon - -import org.gjt.sp.jedit.syntax.{Token => JEditToken} -import org.gjt.sp.jedit.jEdit - -import scala.collection.immutable.SortedMap - - -object Rendering -{ - def apply(snapshot: Document.Snapshot, options: Options): Rendering = - new Rendering(snapshot, options) - - - /* message priorities */ - - private val state_pri = 1 - private val writeln_pri = 2 - private val information_pri = 3 - private val tracing_pri = 4 - private val warning_pri = 5 - private val legacy_pri = 6 - private val error_pri = 7 - - private val message_pri = Map( - Markup.STATE -> state_pri, - Markup.STATE_MESSAGE -> state_pri, - Markup.WRITELN -> writeln_pri, - Markup.WRITELN_MESSAGE -> writeln_pri, - Markup.INFORMATION -> information_pri, - Markup.INFORMATION_MESSAGE -> information_pri, - Markup.TRACING -> tracing_pri, - Markup.TRACING_MESSAGE -> tracing_pri, - Markup.WARNING -> warning_pri, - Markup.WARNING_MESSAGE -> warning_pri, - Markup.LEGACY -> legacy_pri, - Markup.LEGACY_MESSAGE -> legacy_pri, - Markup.ERROR -> error_pri, - Markup.ERROR_MESSAGE -> error_pri) - - - /* popup window bounds */ - - def popup_bounds: Double = (PIDE.options.real("jedit_popup_bounds") max 0.2) min 0.8 - - - /* Isabelle/Isar token markup */ - - private val command_style: Map[String, Byte] = - { - import JEditToken._ - Map[String, Byte]( - Keyword.THY_END -> KEYWORD2, - Keyword.PRF_ASM -> KEYWORD3, - Keyword.PRF_ASM_GOAL -> KEYWORD3 - ).withDefaultValue(KEYWORD1) - } - - private val token_style: Map[Token.Kind.Value, Byte] = - { - import JEditToken._ - Map[Token.Kind.Value, Byte]( - Token.Kind.KEYWORD -> KEYWORD2, - Token.Kind.IDENT -> NULL, - Token.Kind.LONG_IDENT -> NULL, - Token.Kind.SYM_IDENT -> NULL, - Token.Kind.VAR -> NULL, - Token.Kind.TYPE_IDENT -> NULL, - Token.Kind.TYPE_VAR -> NULL, - Token.Kind.NAT -> NULL, - Token.Kind.FLOAT -> NULL, - Token.Kind.SPACE -> NULL, - Token.Kind.STRING -> LITERAL1, - Token.Kind.ALT_STRING -> LITERAL2, - Token.Kind.VERBATIM -> COMMENT3, - Token.Kind.CARTOUCHE -> COMMENT4, - Token.Kind.COMMENT -> COMMENT1, - Token.Kind.ERROR -> INVALID - ).withDefaultValue(NULL) - } - - def token_markup(syntax: Outer_Syntax, token: Token): Byte = - if (token.is_command) command_style(syntax.keywords.kinds.getOrElse(token.content, "")) - else if (token.is_keyword && token.source == Symbol.comment_decoded) JEditToken.NULL - else if (token.is_delimiter) JEditToken.OPERATOR - else token_style(token.kind) - - - /* Isabelle/ML token markup */ - - private val ml_token_style: Map[ML_Lex.Kind.Value, Byte] = - { - import JEditToken._ - Map[ML_Lex.Kind.Value, Byte]( - ML_Lex.Kind.KEYWORD -> NULL, - ML_Lex.Kind.IDENT -> NULL, - ML_Lex.Kind.LONG_IDENT -> NULL, - ML_Lex.Kind.TYPE_VAR -> NULL, - ML_Lex.Kind.WORD -> DIGIT, - ML_Lex.Kind.INT -> DIGIT, - ML_Lex.Kind.REAL -> DIGIT, - ML_Lex.Kind.CHAR -> LITERAL2, - ML_Lex.Kind.STRING -> LITERAL1, - ML_Lex.Kind.SPACE -> NULL, - ML_Lex.Kind.COMMENT -> COMMENT1, - ML_Lex.Kind.ANTIQ -> NULL, - ML_Lex.Kind.ANTIQ_START -> LITERAL4, - ML_Lex.Kind.ANTIQ_STOP -> LITERAL4, - ML_Lex.Kind.ANTIQ_OTHER -> NULL, - ML_Lex.Kind.ANTIQ_STRING -> NULL, - ML_Lex.Kind.ANTIQ_ALT_STRING -> NULL, - ML_Lex.Kind.ANTIQ_CARTOUCHE -> NULL, - ML_Lex.Kind.ERROR -> INVALID - ).withDefaultValue(NULL) - } - - def ml_token_markup(token: ML_Lex.Token): Byte = - if (!token.is_keyword) ml_token_style(token.kind) - else if (token.is_delimiter) JEditToken.OPERATOR - else if (ML_Lex.keywords2(token.source)) JEditToken.KEYWORD2 - else if (ML_Lex.keywords3(token.source)) JEditToken.KEYWORD3 - else JEditToken.KEYWORD1 - - - /* markup elements */ - - private val indentation_elements = - Markup.Elements(Markup.Command_Indent.name) - - private val semantic_completion_elements = - Markup.Elements(Markup.COMPLETION, Markup.NO_COMPLETION) - - private val language_context_elements = - Markup.Elements(Markup.STRING, Markup.ALT_STRING, Markup.VERBATIM, - Markup.CARTOUCHE, Markup.COMMENT, Markup.LANGUAGE, - Markup.ML_STRING, Markup.ML_COMMENT) - - private val language_elements = Markup.Elements(Markup.LANGUAGE) - - private val citation_elements = Markup.Elements(Markup.CITATION) - - private val breakpoint_elements = Markup.Elements(Markup.ML_BREAKPOINT) - - private val caret_focus_elements = Markup.Elements(Markup.ENTITY) - - private val highlight_elements = - Markup.Elements(Markup.EXPRESSION, Markup.CITATION, Markup.LANGUAGE, Markup.ML_TYPING, - Markup.TOKEN_RANGE, Markup.ENTITY, Markup.PATH, Markup.DOC, Markup.URL, Markup.SORTING, - Markup.TYPING, Markup.CLASS_PARAMETER, Markup.FREE, Markup.SKOLEM, Markup.BOUND, - Markup.VAR, Markup.TFREE, Markup.TVAR, Markup.ML_BREAKPOINT, - Markup.MARKDOWN_PARAGRAPH, Markup.Markdown_List.name) - - private val hyperlink_elements = - Markup.Elements(Markup.ENTITY, Markup.PATH, Markup.DOC, Markup.POSITION, - Markup.CITATION, Markup.URL) - - private val active_elements = - Markup.Elements(Markup.DIALOG, Markup.BROWSER, Markup.GRAPHVIEW, - Markup.SENDBACK, Markup.JEDIT_ACTION, Markup.SIMP_TRACE_PANEL) - - private val tooltip_message_elements = - Markup.Elements(Markup.WRITELN, Markup.INFORMATION, Markup.WARNING, Markup.LEGACY, Markup.ERROR, - Markup.BAD) - - private val tooltip_descriptions = - Map( - Markup.CITATION -> "citation", - Markup.TOKEN_RANGE -> "inner syntax token", - Markup.FREE -> "free variable", - Markup.SKOLEM -> "skolem variable", - Markup.BOUND -> "bound variable", - Markup.VAR -> "schematic variable", - Markup.TFREE -> "free type variable", - Markup.TVAR -> "schematic type variable") - - private val tooltip_elements = - Markup.Elements(Markup.LANGUAGE, Markup.EXPRESSION, Markup.TIMING, Markup.ENTITY, - Markup.SORTING, Markup.TYPING, Markup.CLASS_PARAMETER, Markup.ML_TYPING, - Markup.ML_BREAKPOINT, Markup.PATH, Markup.DOC, Markup.URL, Markup.MARKDOWN_PARAGRAPH, - Markup.Markdown_List.name) ++ Markup.Elements(tooltip_descriptions.keySet) - - private val gutter_elements = - Markup.Elements(Markup.WRITELN, Markup.INFORMATION, Markup.WARNING, Markup.LEGACY, Markup.ERROR) - - private val squiggly_elements = - Markup.Elements(Markup.WRITELN, Markup.INFORMATION, Markup.WARNING, Markup.LEGACY, Markup.ERROR) - - private val line_background_elements = - Markup.Elements(Markup.WRITELN_MESSAGE, Markup.STATE_MESSAGE, Markup.INFORMATION_MESSAGE, - Markup.TRACING_MESSAGE, Markup.WARNING_MESSAGE, Markup.LEGACY_MESSAGE, - Markup.ERROR_MESSAGE) - - private val separator_elements = - Markup.Elements(Markup.SEPARATOR) - - private val background_elements = - Protocol.proper_status_elements + Markup.WRITELN_MESSAGE + - Markup.STATE_MESSAGE + Markup.INFORMATION_MESSAGE + - Markup.TRACING_MESSAGE + Markup.WARNING_MESSAGE + - Markup.LEGACY_MESSAGE + Markup.ERROR_MESSAGE + - Markup.BAD + Markup.INTENSIFY + Markup.ENTITY + - Markup.Markdown_Item.name ++ active_elements - - private val foreground_elements = - Markup.Elements(Markup.STRING, Markup.ALT_STRING, Markup.VERBATIM, - Markup.CARTOUCHE, Markup.ANTIQUOTED) - - private val bullet_elements = - Markup.Elements(Markup.BULLET, Markup.ML_BREAKPOINT) - - private val fold_depth_elements = - Markup.Elements(Markup.TEXT_FOLD, Markup.GOAL, Markup.SUBGOAL) -} - - -class Rendering private(val snapshot: Document.Snapshot, val options: Options) -{ - override def toString: String = "Rendering(" + snapshot.toString + ")" - - - /* colors */ - - def color_value(s: String): Color = Color_Value(options.string(s)) - - val outdated_color = color_value("outdated_color") - val unprocessed_color = color_value("unprocessed_color") - val unprocessed1_color = color_value("unprocessed1_color") - val running_color = color_value("running_color") - val running1_color = color_value("running1_color") - val bullet_color = color_value("bullet_color") - val tooltip_color = color_value("tooltip_color") - val writeln_color = color_value("writeln_color") - val information_color = color_value("information_color") - val warning_color = color_value("warning_color") - val legacy_color = color_value("legacy_color") - val error_color = color_value("error_color") - val writeln_message_color = color_value("writeln_message_color") - val information_message_color = color_value("information_message_color") - val tracing_message_color = color_value("tracing_message_color") - val warning_message_color = color_value("warning_message_color") - val legacy_message_color = color_value("legacy_message_color") - val error_message_color = color_value("error_message_color") - val spell_checker_color = color_value("spell_checker_color") - val bad_color = color_value("bad_color") - val intensify_color = color_value("intensify_color") - val entity_color = color_value("entity_color") - val entity_ref_color = color_value("entity_ref_color") - val breakpoint_disabled_color = color_value("breakpoint_disabled_color") - val breakpoint_enabled_color = color_value("breakpoint_enabled_color") - val caret_debugger_color = color_value("caret_debugger_color") - val quoted_color = color_value("quoted_color") - val antiquoted_color = color_value("antiquoted_color") - val antiquote_color = color_value("antiquote_color") - val highlight_color = color_value("highlight_color") - val hyperlink_color = color_value("hyperlink_color") - val active_color = color_value("active_color") - val active_hover_color = color_value("active_hover_color") - val active_result_color = color_value("active_result_color") - val keyword1_color = color_value("keyword1_color") - val keyword2_color = color_value("keyword2_color") - val keyword3_color = color_value("keyword3_color") - val quasi_keyword_color = color_value("quasi_keyword_color") - val improper_color = color_value("improper_color") - val operator_color = color_value("operator_color") - val caret_invisible_color = color_value("caret_invisible_color") - val completion_color = color_value("completion_color") - val search_color = color_value("search_color") - - val tfree_color = color_value("tfree_color") - val tvar_color = color_value("tvar_color") - val free_color = color_value("free_color") - val skolem_color = color_value("skolem_color") - val bound_color = color_value("bound_color") - val var_color = color_value("var_color") - val inner_numeral_color = color_value("inner_numeral_color") - val inner_quoted_color = color_value("inner_quoted_color") - val inner_cartouche_color = color_value("inner_cartouche_color") - val inner_comment_color = color_value("inner_comment_color") - val dynamic_color = color_value("dynamic_color") - val class_parameter_color = color_value("class_parameter_color") - - val markdown_item_color1 = color_value("markdown_item_color1") - val markdown_item_color2 = color_value("markdown_item_color2") - val markdown_item_color3 = color_value("markdown_item_color3") - val markdown_item_color4 = color_value("markdown_item_color4") - - - /* indentation */ - - def indentation(range: Text.Range): Int = - snapshot.select(range, Rendering.indentation_elements, _ => - { - case Text.Info(_, XML.Elem(Markup.Command_Indent(i), _)) => Some(i) - case _ => None - }).headOption.map(_.info).getOrElse(0) - - - /* completion */ - - def semantic_completion(completed_range: Option[Text.Range], range: Text.Range) - : Option[Text.Info[Completion.Semantic]] = - if (snapshot.is_outdated) None - else { - snapshot.select(range, Rendering.semantic_completion_elements, _ => - { - case Completion.Semantic.Info(info) => - completed_range match { - case Some(range0) if range0.contains(info.range) && range0 != info.range => None - case _ => Some(info) - } - case _ => None - }).headOption.map(_.info) - } - - def language_context(range: Text.Range): Option[Completion.Language_Context] = - snapshot.select(range, Rendering.language_context_elements, _ => - { - case Text.Info(_, XML.Elem(Markup.Language(language, symbols, antiquotes, delimited), _)) => - if (delimited) Some(Completion.Language_Context(language, symbols, antiquotes)) - else None - case Text.Info(_, elem) - if elem.name == Markup.ML_STRING || elem.name == Markup.ML_COMMENT => - Some(Completion.Language_Context.ML_inner) - case Text.Info(_, _) => - Some(Completion.Language_Context.inner) - }).headOption.map(_.info) - - def language_path(range: Text.Range): Option[Text.Range] = - snapshot.select(range, Rendering.language_elements, _ => - { - case Text.Info(info_range, XML.Elem(Markup.Language(Markup.Language.PATH, _, _, _), _)) => - Some(snapshot.convert(info_range)) - case _ => None - }).headOption.map(_.info) - - def citation(range: Text.Range): Option[Text.Info[String]] = - snapshot.select(range, Rendering.citation_elements, _ => - { - case Text.Info(info_range, XML.Elem(Markup.Citation(name), _)) => - Some(Text.Info(snapshot.convert(info_range), name)) - case _ => None - }).headOption.map(_.info) - - - /* spell checker */ - - private lazy val spell_checker_elements = - Markup.Elements(space_explode(',', options.string("spell_checker_elements")): _*) - - def spell_checker_ranges(range: Text.Range): List[Text.Range] = - snapshot.select(range, spell_checker_elements, _ => _ => Some(())).map(_.range) - - def spell_checker_point(range: Text.Range): Option[Text.Range] = - snapshot.select(range, spell_checker_elements, _ => - { - case info => Some(snapshot.convert(info.range)) - }).headOption.map(_.info) - - - /* breakpoints */ - - def breakpoint(range: Text.Range): Option[(Command, Long)] = - if (snapshot.is_outdated) None - else - snapshot.select(range, Rendering.breakpoint_elements, command_states => - { - case Text.Info(_, Protocol.ML_Breakpoint(breakpoint)) => - command_states match { - case st :: _ => Some((st.command, breakpoint)) - case _ => None - } - case _ => None - }).headOption.map(_.info) - - - /* command status overview */ - - def overview_color(range: Text.Range): Option[Color] = - { - if (snapshot.is_outdated) None - else { - val results = - snapshot.cumulate[List[Markup]](range, Nil, Protocol.liberal_status_elements, _ => - { - case (status, Text.Info(_, elem)) => Some(elem.markup :: status) - }, status = true) - if (results.isEmpty) None - else { - val status = Protocol.Status.make(results.iterator.flatMap(_.info)) - - if (status.is_running) Some(running_color) - else if (status.is_failed) Some(error_color) - else if (status.is_warned) Some(warning_color) - else if (status.is_unprocessed) Some(unprocessed_color) - else None - } - } - } - - - /* caret focus */ - - def entity_focus(range: Text.Range, - check: (Boolean, Long) => Boolean = (is_def: Boolean, i: Long) => is_def): Set[Long] = - { - val results = - snapshot.cumulate[Set[Long]](range, Set.empty, Rendering.caret_focus_elements, _ => - { - case (serials, Text.Info(_, XML.Elem(Markup(Markup.ENTITY, props), _))) => - props match { - case Markup.Entity.Def(i) if check(true, i) => Some(serials + i) - case Markup.Entity.Ref(i) if check(false, i) => Some(serials + i) - case _ => None - } - case _ => None - }) - (Set.empty[Long] /: results){ case (s1, Text.Info(_, s2)) => s1 ++ s2 } - } - - def caret_focus(caret_range: Text.Range, visible_range: Text.Range): Set[Long] = - { - val focus_defs = entity_focus(caret_range) - if (focus_defs.nonEmpty) focus_defs - else { - val visible_defs = entity_focus(visible_range) - entity_focus(caret_range, (is_def: Boolean, i: Long) => !is_def && visible_defs.contains(i)) - } - } - - def caret_focus_ranges(caret_range: Text.Range, visible_range: Text.Range): List[Text.Range] = - { - val focus = caret_focus(caret_range, visible_range) - if (focus.nonEmpty) { - val results = - snapshot.cumulate[Boolean](visible_range, false, Rendering.caret_focus_elements, _ => - { - case (_, Text.Info(_, XML.Elem(Markup(Markup.ENTITY, props), _))) => - props match { - case Markup.Entity.Def(i) if focus(i) => Some(true) - case Markup.Entity.Ref(i) if focus(i) => Some(true) - case _ => None - } - }) - for (info <- results if info.info) yield info.range - } - else Nil - } - - def entity_ref(range: Text.Range, focus: Set[Long]): List[Text.Info[Color]] = - snapshot.select(range, Rendering.caret_focus_elements, _ => - { - case Text.Info(_, XML.Elem(Markup(Markup.ENTITY, Markup.Entity.Ref(i)), _)) if focus(i) => - Some(entity_ref_color) - case _ => None - }) - - - /* highlighted area */ - - def highlight(range: Text.Range): Option[Text.Info[Color]] = - snapshot.select(range, Rendering.highlight_elements, _ => - { - case info => Some(Text.Info(snapshot.convert(info.range), highlight_color)) - }).headOption.map(_.info) - - - /* hyperlinks */ - - private def jedit_file(name: String): String = - if (Path.is_valid(name)) - PIDE.resources.append(snapshot.node_name.master_dir, Path.explode(name)) - else name - - def hyperlink(range: Text.Range): Option[Text.Info[PIDE.editor.Hyperlink]] = - { - snapshot.cumulate[Vector[Text.Info[PIDE.editor.Hyperlink]]]( - range, Vector.empty, Rendering.hyperlink_elements, _ => - { - case (links, Text.Info(info_range, XML.Elem(Markup.Path(name), _))) => - val link = PIDE.editor.hyperlink_file(true, jedit_file(name)) - Some(links :+ Text.Info(snapshot.convert(info_range), link)) - - case (links, Text.Info(info_range, XML.Elem(Markup.Doc(name), _))) => - PIDE.editor.hyperlink_doc(name).map(link => - (links :+ Text.Info(snapshot.convert(info_range), link))) - - case (links, Text.Info(info_range, XML.Elem(Markup.Url(name), _))) => - val link = PIDE.editor.hyperlink_url(name) - Some(links :+ Text.Info(snapshot.convert(info_range), link)) - - case (links, Text.Info(info_range, XML.Elem(Markup(Markup.ENTITY, props), _))) - if !props.exists( - { case (Markup.KIND, Markup.ML_OPEN) => true - case (Markup.KIND, Markup.ML_STRUCTURE) => true - case _ => false }) => - val opt_link = PIDE.editor.hyperlink_def_position(true, snapshot, props) - opt_link.map(link => links :+ Text.Info(snapshot.convert(info_range), link)) - - case (links, Text.Info(info_range, XML.Elem(Markup(Markup.POSITION, props), _))) => - val opt_link = PIDE.editor.hyperlink_position(true, snapshot, props) - opt_link.map(link => links :+ Text.Info(snapshot.convert(info_range), link)) - - case (links, Text.Info(info_range, XML.Elem(Markup.Citation(name), _))) => - val opt_link = - Bibtex_JEdit.entries_iterator.collectFirst( - { case (a, buffer, offset) if a == name => - PIDE.editor.hyperlink_buffer(true, buffer, offset) }) - opt_link.map(link => links :+ Text.Info(snapshot.convert(info_range), link)) - - case _ => None - }) match { case Text.Info(_, _ :+ info) :: _ => Some(info) case _ => None } - } - - - /* active elements */ - - def active(range: Text.Range): Option[Text.Info[XML.Elem]] = - snapshot.select(range, Rendering.active_elements, command_states => - { - case Text.Info(info_range, elem) => - if (elem.name == Markup.DIALOG) { - elem match { - case Protocol.Dialog(_, serial, _) - if !command_states.exists(st => st.results.defined(serial)) => - Some(Text.Info(snapshot.convert(info_range), elem)) - case _ => None - } - } - else Some(Text.Info(snapshot.convert(info_range), elem)) - }).headOption.map(_.info) - - def command_results(range: Text.Range): Command.Results = - Command.State.merge_results( - snapshot.select[List[Command.State]](range, Markup.Elements.full, command_states => - { case _ => Some(command_states) }).flatMap(_.info)) - - - /* tooltip messages */ - - def tooltip_message(range: Text.Range): Option[Text.Info[XML.Body]] = - { - val results = - snapshot.cumulate[List[Text.Info[Command.Results.Entry]]]( - range, Nil, Rendering.tooltip_message_elements, _ => - { - case (msgs, Text.Info(info_range, msg @ XML.Elem(Markup(Markup.BAD, _), body))) - if body.nonEmpty => - val entry: Command.Results.Entry = (Document_ID.make(), msg) - Some(Text.Info(snapshot.convert(info_range), entry) :: msgs) - - case (msgs, Text.Info(info_range, - XML.Elem(Markup(name, props @ Markup.Serial(serial)), body))) => - val entry: Command.Results.Entry = - serial -> XML.Elem(Markup(Markup.message(name), props), body) - Some(Text.Info(snapshot.convert(info_range), entry) :: msgs) - - case _ => None - }).flatMap(_.info) - if (results.isEmpty) None - else { - val r = Text.Range(results.head.range.start, results.last.range.stop) - val msgs = Command.Results.make(results.map(_.info)) - Some(Text.Info(r, Pretty.separate(msgs.iterator.map(_._2).toList))) - } - } - - - /* tooltips */ - - private def pretty_typing(kind: String, body: XML.Body): XML.Tree = - Pretty.block(XML.Text(kind) :: Pretty.brk(1) :: body) - - private def timing_threshold: Double = options.real("jedit_timing_threshold") - - def tooltip(range: Text.Range): Option[Text.Info[XML.Body]] = - { - def add(prev: Text.Info[(Timing, Vector[(Boolean, XML.Tree)])], - r0: Text.Range, p: (Boolean, XML.Tree)): Text.Info[(Timing, Vector[(Boolean, XML.Tree)])] = - { - val r = snapshot.convert(r0) - val (t, info) = prev.info - if (prev.range == r) - Text.Info(r, (t, info :+ p)) - else Text.Info(r, (t, Vector(p))) - } - - val results = - snapshot.cumulate[Text.Info[(Timing, Vector[(Boolean, XML.Tree)])]]( - range, Text.Info(range, (Timing.zero, Vector.empty)), Rendering.tooltip_elements, _ => - { - case (Text.Info(r, (t1, info)), Text.Info(_, XML.Elem(Markup.Timing(t2), _))) => - Some(Text.Info(r, (t1 + t2, info))) - - case (prev, Text.Info(r, XML.Elem(Markup.Entity(kind, name), _))) - if kind != "" && - kind != Markup.ML_DEF && - kind != Markup.ML_OPEN && - kind != Markup.ML_STRUCTURE => - val kind1 = Word.implode(Word.explode('_', kind)) - val txt1 = - if (name == "") kind1 - else if (kind1 == "") quote(name) - else kind1 + " " + quote(name) - val t = prev.info._1 - val txt2 = - if (kind == Markup.COMMAND && t.elapsed.seconds >= timing_threshold) - "\n" + t.message - else "" - Some(add(prev, r, (true, XML.Text(txt1 + txt2)))) - - case (prev, Text.Info(r, XML.Elem(Markup.Path(name), _))) => - val file = jedit_file(name) - val text = - if (name == file) "file " + quote(file) - else "path " + quote(name) + "\nfile " + quote(file) - Some(add(prev, r, (true, XML.Text(text)))) - - case (prev, Text.Info(r, XML.Elem(Markup.Doc(name), _))) => - val text = "doc " + quote(name) - Some(add(prev, r, (true, XML.Text(text)))) - - case (prev, Text.Info(r, XML.Elem(Markup.Url(name), _))) => - Some(add(prev, r, (true, XML.Text("URL " + quote(name))))) - - case (prev, Text.Info(r, XML.Elem(Markup(name, _), body))) - if name == Markup.SORTING || name == Markup.TYPING => - Some(add(prev, r, (true, pretty_typing("::", body)))) - - case (prev, Text.Info(r, XML.Elem(Markup(Markup.CLASS_PARAMETER, _), body))) => - Some(add(prev, r, (true, Pretty.block(0, body)))) - - case (prev, Text.Info(r, XML.Elem(Markup(Markup.ML_TYPING, _), body))) => - Some(add(prev, r, (false, pretty_typing("ML:", body)))) - - case (prev, Text.Info(r, Protocol.ML_Breakpoint(breakpoint))) => - val text = - if (Debugger.breakpoint_state(breakpoint)) "breakpoint (enabled)" - else "breakpoint (disabled)" - Some(add(prev, r, (true, XML.Text(text)))) - - case (prev, Text.Info(r, XML.Elem(Markup.Language(language, _, _, _), _))) => - val lang = Word.implode(Word.explode('_', language)) - Some(add(prev, r, (true, XML.Text("language: " + lang)))) - - case (prev, Text.Info(r, XML.Elem(Markup.Expression(kind), _))) => - val descr = if (kind == "") "expression" else "expression: " + kind - Some(add(prev, r, (true, XML.Text(descr)))) - - case (prev, Text.Info(r, XML.Elem(Markup(Markup.MARKDOWN_PARAGRAPH, _), _))) => - Some(add(prev, r, (true, XML.Text("Markdown: paragraph")))) - case (prev, Text.Info(r, XML.Elem(Markup.Markdown_List(kind), _))) => - Some(add(prev, r, (true, XML.Text("Markdown: " + kind)))) - - case (prev, Text.Info(r, XML.Elem(Markup(name, _), _))) => - Rendering.tooltip_descriptions.get(name). - map(descr => add(prev, r, (true, XML.Text(descr)))) - }).map(_.info) - - results.map(_.info).flatMap(res => res._2.toList) match { - case Nil => None - case tips => - val r = Text.Range(results.head.range.start, results.last.range.stop) - val all_tips = (tips.filter(_._1) ++ tips.filter(!_._1).lastOption.toList).map(_._2) - Some(Text.Info(r, Library.separate(Pretty.fbrk, all_tips))) - } - } - - def tooltip_margin: Int = options.int("jedit_tooltip_margin") - - lazy val tooltip_close_icon = JEdit_Lib.load_icon(options.string("tooltip_close_icon")) - lazy val tooltip_detach_icon = JEdit_Lib.load_icon(options.string("tooltip_detach_icon")) - - - /* gutter */ - - private def gutter_message_pri(msg: XML.Tree): Int = - if (Protocol.is_error(msg)) Rendering.error_pri - else if (Protocol.is_legacy(msg)) Rendering.legacy_pri - else if (Protocol.is_warning(msg)) Rendering.warning_pri - else if (Protocol.is_information(msg)) Rendering.information_pri - else 0 - - private lazy val gutter_message_content = Map( - Rendering.information_pri -> - (JEdit_Lib.load_icon(options.string("gutter_information_icon")), information_message_color), - Rendering.warning_pri -> - (JEdit_Lib.load_icon(options.string("gutter_warning_icon")), warning_message_color), - Rendering.legacy_pri -> - (JEdit_Lib.load_icon(options.string("gutter_legacy_icon")), warning_message_color), - Rendering.error_pri -> - (JEdit_Lib.load_icon(options.string("gutter_error_icon")), error_message_color)) - - def gutter_content(range: Text.Range): Option[(Icon, Color)] = - { - val pris = - snapshot.cumulate[Int](range, 0, Rendering.gutter_elements, _ => - { - case (pri, Text.Info(_, msg @ XML.Elem(Markup(_, Markup.Serial(serial)), _))) => - Some(pri max gutter_message_pri(msg)) - case _ => None - }).map(_.info) - - gutter_message_content.get((0 /: pris)(_ max _)) - } - - - /* squiggly underline */ - - private lazy val squiggly_colors = Map( - Rendering.writeln_pri -> writeln_color, - Rendering.information_pri -> information_color, - Rendering.warning_pri -> warning_color, - Rendering.legacy_pri -> legacy_color, - Rendering.error_pri -> error_color) - - def squiggly_underline(range: Text.Range): List[Text.Info[Color]] = - { - val results = - snapshot.cumulate[Int](range, 0, Rendering.squiggly_elements, _ => - { - case (pri, Text.Info(_, elem)) => Some(pri max Rendering.message_pri(elem.name)) - }) - for { - Text.Info(r, pri) <- results - color <- squiggly_colors.get(pri) - } yield Text.Info(r, color) - } - - - /* message output */ - - private lazy val message_colors = Map( - Rendering.writeln_pri -> writeln_message_color, - Rendering.information_pri -> information_message_color, - Rendering.tracing_pri -> tracing_message_color, - Rendering.warning_pri -> warning_message_color, - Rendering.legacy_pri -> legacy_message_color, - Rendering.error_pri -> error_message_color) - - def line_background(range: Text.Range): Option[(Color, Boolean)] = - { - val results = - snapshot.cumulate[Int](range, 0, Rendering.line_background_elements, _ => - { - case (pri, Text.Info(_, elem)) => Some(pri max Rendering.message_pri(elem.name)) - }) - val pri = (0 /: results) { case (p1, Text.Info(_, p2)) => p1 max p2 } - - message_colors.get(pri).map(message_color => - { - val is_separator = - snapshot.cumulate[Boolean](range, false, Rendering.separator_elements, _ => - { - case _ => Some(true) - }).exists(_.info) - (message_color, is_separator) - }) - } - - def output_messages(results: Command.Results): List[XML.Tree] = - { - val (states, other) = - results.iterator.map(_._2).filterNot(Protocol.is_result(_)).toList - .partition(Protocol.is_state(_)) - states ::: other - } - - - /* text background */ - - def background(range: Text.Range, focus: Set[Long]): List[Text.Info[Color]] = - { - for { - Text.Info(r, result) <- - snapshot.cumulate[(List[Markup], Option[Color])]( - range, (List(Markup.Empty), None), Rendering.background_elements, - command_states => - { - case (((status, color), Text.Info(_, XML.Elem(markup, _)))) - if status.nonEmpty && Protocol.proper_status_elements(markup.name) => - Some((markup :: status, color)) - case (_, Text.Info(_, XML.Elem(Markup(Markup.BAD, _), _))) => - Some((Nil, Some(bad_color))) - case (_, Text.Info(_, XML.Elem(Markup(Markup.INTENSIFY, _), _))) => - Some((Nil, Some(intensify_color))) - case (_, Text.Info(_, XML.Elem(Markup(Markup.ENTITY, props), _))) => - props match { - case Markup.Entity.Def(i) if focus(i) => Some((Nil, Some(entity_color))) - case Markup.Entity.Ref(i) if focus(i) => Some((Nil, Some(entity_color))) - case _ => None - } - case (_, Text.Info(_, XML.Elem(Markup.Markdown_Item(depth), _))) => - val color = - depth match { - case 1 => markdown_item_color1 - case 2 => markdown_item_color2 - case 3 => markdown_item_color3 - case _ => markdown_item_color4 - } - Some((Nil, Some(color))) - case (acc, Text.Info(_, Protocol.Dialog(_, serial, result))) => - command_states.collectFirst( - { case st if st.results.defined(serial) => st.results.get(serial).get }) match - { - case Some(Protocol.Dialog_Result(res)) if res == result => - Some((Nil, Some(active_result_color))) - case _ => - Some((Nil, Some(active_color))) - } - case (_, Text.Info(_, elem)) => - if (Rendering.active_elements(elem.name)) Some((Nil, Some(active_color))) - else None - }) - color <- - (result match { - case (markups, opt_color) if markups.nonEmpty => - val status = Protocol.Status.make(markups.iterator) - if (status.is_unprocessed) Some(unprocessed1_color) - else if (status.is_running) Some(running1_color) - else opt_color - case (_, opt_color) => opt_color - }) - } yield Text.Info(r, color) - } - - - /* text foreground */ - - def foreground(range: Text.Range): List[Text.Info[Color]] = - snapshot.select(range, Rendering.foreground_elements, _ => - { - case Text.Info(_, elem) => - if (elem.name == Markup.ANTIQUOTED) Some(antiquoted_color) else Some(quoted_color) - }) - - - /* text color */ - - val foreground_color = jEdit.getColorProperty("view.fgColor") - - private lazy val text_colors: Map[String, Color] = Map( - Markup.KEYWORD1 -> keyword1_color, - Markup.KEYWORD2 -> keyword2_color, - Markup.KEYWORD3 -> keyword3_color, - Markup.QUASI_KEYWORD -> quasi_keyword_color, - Markup.IMPROPER -> improper_color, - Markup.OPERATOR -> operator_color, - Markup.STRING -> foreground_color, - Markup.ALT_STRING -> foreground_color, - Markup.VERBATIM -> foreground_color, - Markup.CARTOUCHE -> foreground_color, - Markup.LITERAL -> keyword1_color, - Markup.DELIMITER -> foreground_color, - Markup.TFREE -> tfree_color, - Markup.TVAR -> tvar_color, - Markup.FREE -> free_color, - Markup.SKOLEM -> skolem_color, - Markup.BOUND -> bound_color, - Markup.VAR -> var_color, - Markup.INNER_STRING -> inner_quoted_color, - Markup.INNER_CARTOUCHE -> inner_cartouche_color, - Markup.INNER_COMMENT -> inner_comment_color, - Markup.DYNAMIC_FACT -> dynamic_color, - Markup.CLASS_PARAMETER -> class_parameter_color, - Markup.ANTIQUOTE -> antiquote_color, - Markup.ML_KEYWORD1 -> keyword1_color, - Markup.ML_KEYWORD2 -> keyword2_color, - Markup.ML_KEYWORD3 -> keyword3_color, - Markup.ML_DELIMITER -> foreground_color, - Markup.ML_NUMERAL -> inner_numeral_color, - Markup.ML_CHAR -> inner_quoted_color, - Markup.ML_STRING -> inner_quoted_color, - Markup.ML_COMMENT -> inner_comment_color, - Markup.SML_STRING -> inner_quoted_color, - Markup.SML_COMMENT -> inner_comment_color) - - private lazy val text_color_elements = - Markup.Elements(text_colors.keySet) - - def text_color(range: Text.Range, color: Color): List[Text.Info[Color]] = - { - if (color == Token_Markup.hidden_color) List(Text.Info(range, color)) - else - snapshot.cumulate(range, color, text_color_elements, _ => - { - case (_, Text.Info(_, elem)) => text_colors.get(elem.name) - }) - } - - - /* virtual bullets */ - - def bullet(range: Text.Range): List[Text.Info[Color]] = - snapshot.select(range, Rendering.bullet_elements, _ => - { - case Text.Info(_, Protocol.ML_Breakpoint(breakpoint)) => - Debugger.active_breakpoint_state(breakpoint).map(b => - if (b) breakpoint_enabled_color else breakpoint_disabled_color) - case _ => Some(bullet_color) - }) - - - /* text folds */ - - def fold_depth(range: Text.Range): List[Text.Info[Int]] = - snapshot.cumulate[Int](range, 0, Rendering.fold_depth_elements, _ => - { - case (depth, _) => Some(depth + 1) - }) -} diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/rich_text_area.scala --- a/src/Tools/jEdit/src/rich_text_area.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/rich_text_area.scala Wed Dec 21 11:14:55 2016 +0100 @@ -29,7 +29,7 @@ class Rich_Text_Area( view: View, text_area: TextArea, - get_rendering: () => Rendering, + get_rendering: () => JEdit_Rendering, close_action: () => Unit, get_search_pattern: () => Option[Regex], caret_update: () => Unit, @@ -72,7 +72,7 @@ /* common painter state */ - @volatile private var painter_rendering: Rendering = null + @volatile private var painter_rendering: JEdit_Rendering = null @volatile private var painter_clip: Shape = null @volatile private var caret_focus: Set[Long] = Set.empty @@ -105,7 +105,7 @@ } } - def robust_rendering(body: Rendering => Unit) + def robust_rendering(body: JEdit_Rendering => Unit) { robust_body(()) { body(painter_rendering) } } @@ -114,7 +114,7 @@ /* active areas within the text */ private class Active_Area[A]( - rendering: Rendering => Text.Range => Option[Text.Info[A]], + rendering: JEdit_Rendering => Text.Range => Option[Text.Info[A]], cursor: Option[Int]) { private var the_text_info: Option[(String, Text.Info[A])] = None @@ -147,7 +147,7 @@ } } - def update_rendering(r: Rendering, range: Text.Range) + def update_rendering(r: JEdit_Rendering, range: Text.Range) { update(rendering(r)(range)) } def reset { update(None) } @@ -157,15 +157,15 @@ private val highlight_area = new Active_Area[Color]( - (rendering: Rendering) => rendering.highlight _, None) + (rendering: JEdit_Rendering) => rendering.highlight _, None) private val hyperlink_area = new Active_Area[PIDE.editor.Hyperlink]( - (rendering: Rendering) => rendering.hyperlink _, Some(Cursor.HAND_CURSOR)) + (rendering: JEdit_Rendering) => rendering.hyperlink _, Some(Cursor.HAND_CURSOR)) private val active_area = new Active_Area[XML.Elem]( - (rendering: Rendering) => rendering.active _, Some(Cursor.DEFAULT_CURSOR)) + (rendering: JEdit_Rendering) => rendering.active _, Some(Cursor.DEFAULT_CURSOR)) private val active_areas = List((highlight_area, true), (hyperlink_area, true), (active_area, false)) @@ -362,7 +362,7 @@ private def caret_enabled: Boolean = caret_visible && (!text_area.hasFocus || text_area.isCaretVisible) - private def caret_color(rendering: Rendering, offset: Text.Offset): Color = + private def caret_color(rendering: JEdit_Rendering, offset: Text.Offset): Color = { if (text_area.isCaretVisible) text_area.getPainter.getCaretColor else { @@ -377,7 +377,7 @@ } } - private def paint_chunk_list(rendering: Rendering, + private def paint_chunk_list(rendering: JEdit_Rendering, gfx: Graphics2D, line_start: Text.Offset, head: Chunk, x: Float, y: Float): Float = { val clip_rect = gfx.getClipBounds diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/spell_checker.scala --- a/src/Tools/jEdit/src/spell_checker.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/spell_checker.scala Wed Dec 21 11:14:55 2016 +0100 @@ -61,7 +61,7 @@ result.toList } - def current_word(text_area: TextArea, rendering: Rendering, range: Text.Range) + def current_word(text_area: TextArea, rendering: JEdit_Rendering, range: Text.Range) : Option[Text.Info[String]] = { for { @@ -75,7 +75,7 @@ /** completion **/ - def completion(text_area: TextArea, explicit: Boolean, rendering: Rendering) + def completion(text_area: TextArea, explicit: Boolean, rendering: JEdit_Rendering) : Option[Completion.Result] = { for { diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/text_structure.scala --- a/src/Tools/jEdit/src/text_structure.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/text_structure.scala Wed Dec 21 11:14:55 2016 +0100 @@ -86,7 +86,7 @@ val script_indent: Text.Info[Token] => Int = { - val opt_rendering: Option[Rendering] = + val opt_rendering: Option[JEdit_Rendering] = if (PIDE.options.value.bool("jedit_indent_script")) GUI_Thread.now { (for { diff -r f3f457535fe2 -r c6330e16743f src/Tools/jEdit/src/token_markup.scala --- a/src/Tools/jEdit/src/token_markup.scala Wed Dec 21 11:14:37 2016 +0100 +++ b/src/Tools/jEdit/src/token_markup.scala Wed Dec 21 11:14:55 2016 +0100 @@ -401,14 +401,15 @@ (line_context.context, opt_syntax) match { case (Some(ctxt), _) if mode == "isabelle-ml" || mode == "sml" => val (tokens, ctxt1) = ML_Lex.tokenize_line(mode == "sml", line, ctxt) - val styled_tokens = tokens.map(tok => (Rendering.ml_token_markup(tok), tok.source)) + val styled_tokens = + tokens.map(tok => (JEdit_Rendering.ml_token_markup(tok), tok.source)) (styled_tokens, new Line_Context(line_context.mode, Some(ctxt1), structure)) case (Some(ctxt), Some(syntax)) if syntax.has_tokens => val (tokens, ctxt1) = Token.explode_line(syntax.keywords, line, ctxt) val structure1 = structure.update(syntax.keywords, tokens) val styled_tokens = - tokens.map(tok => (Rendering.token_markup(syntax, tok), tok.source)) + tokens.map(tok => (JEdit_Rendering.token_markup(syntax, tok), tok.source)) (styled_tokens, new Line_Context(line_context.mode, Some(ctxt1), structure1)) case _ =>