src/Tools/VSCode/src/vscode_rendering.scala
changeset 75393 87ebf5a50283
parent 75263 0a440e255a64
child 75419 be5aa2c9c9ad
equal deleted inserted replaced
75388:b3ca4a6ed74b 75393:87ebf5a50283
    13 import java.io.{File => JFile}
    13 import java.io.{File => JFile}
    14 
    14 
    15 import scala.annotation.tailrec
    15 import scala.annotation.tailrec
    16 
    16 
    17 
    17 
    18 object VSCode_Rendering
    18 object VSCode_Rendering {
    19 {
       
    20   /* decorations */
    19   /* decorations */
    21 
    20 
    22   private def color_decorations(prefix: String, types: Set[Rendering.Color.Value],
    21   private def color_decorations(
    23     colors: List[Text.Info[Rendering.Color.Value]]): List[VSCode_Model.Decoration] =
    22     prefix: String,
    24   {
    23     types: Set[Rendering.Color.Value],
       
    24     colors: List[Text.Info[Rendering.Color.Value]]
       
    25   ): List[VSCode_Model.Decoration] = {
    25     val color_ranges =
    26     val color_ranges =
    26       colors.foldLeft(Map.empty[Rendering.Color.Value, List[Text.Range]]) {
    27       colors.foldLeft(Map.empty[Rendering.Color.Value, List[Text.Range]]) {
    27         case (m, Text.Info(range, c)) => m + (c -> (range :: m.getOrElse(c, Nil)))
    28         case (m, Text.Info(range, c)) => m + (c -> (range :: m.getOrElse(c, Nil)))
    28       }
    29       }
    29     types.toList.map(c =>
    30     types.toList.map(c =>
    64   private val hyperlink_elements =
    65   private val hyperlink_elements =
    65     Markup.Elements(Markup.ENTITY, Markup.PATH, Markup.POSITION, Markup.CITATION)
    66     Markup.Elements(Markup.ENTITY, Markup.PATH, Markup.POSITION, Markup.CITATION)
    66 }
    67 }
    67 
    68 
    68 class VSCode_Rendering(snapshot: Document.Snapshot, val model: VSCode_Model)
    69 class VSCode_Rendering(snapshot: Document.Snapshot, val model: VSCode_Model)
    69   extends Rendering(snapshot, model.resources.options, model.session)
    70 extends Rendering(snapshot, model.resources.options, model.session) {
    70 {
       
    71   rendering =>
    71   rendering =>
    72 
    72 
    73   def resources: VSCode_Resources = model.resources
    73   def resources: VSCode_Resources = model.resources
    74 
    74 
    75   override def get_text(range: Text.Range): Option[String] = model.get_text(range)
    75   override def get_text(range: Text.Range): Option[String] = model.get_text(range)
    84     Bibtex.completion(history, rendering, caret, resources.get_models)
    84     Bibtex.completion(history, rendering, caret, resources.get_models)
    85 
    85 
    86 
    86 
    87   /* completion */
    87   /* completion */
    88 
    88 
    89   def completion(node_pos: Line.Node_Position, caret: Text.Offset): List[LSP.CompletionItem] =
    89   def completion(node_pos: Line.Node_Position, caret: Text.Offset): List[LSP.CompletionItem] = {
    90   {
       
    91     val doc = model.content.doc
    90     val doc = model.content.doc
    92     val line = node_pos.pos.line
    91     val line = node_pos.pos.line
    93     val unicode = node_pos.name.endsWith(".thy")
    92     val unicode = node_pos.name.endsWith(".thy")
    94     doc.offset(Line.Position(line)) match {
    93     doc.offset(Line.Position(line)) match {
    95       case None => Nil
    94       case None => Nil
   146               Command.State.get_result_proper(command_states, msg.markup.properties).map(res + _)
   145               Command.State.get_result_proper(command_states, msg.markup.properties).map(res + _)
   147 
   146 
   148             case _ => None
   147             case _ => None
   149           }).filterNot(info => info.info.is_empty)
   148           }).filterNot(info => info.info.is_empty)
   150 
   149 
   151   def diagnostics_output(results: List[Text.Info[Command.Results]]): List[LSP.Diagnostic] =
   150   def diagnostics_output(results: List[Text.Info[Command.Results]]): List[LSP.Diagnostic] = {
   152   {
       
   153     (for {
   151     (for {
   154       Text.Info(text_range, res) <- results.iterator
   152       Text.Info(text_range, res) <- results.iterator
   155       range = model.content.doc.range(text_range)
   153       range = model.content.doc.range(text_range)
   156       (_, XML.Elem(Markup(name, _), body)) <- res.iterator
   154       (_, XML.Elem(Markup(name, _), body)) <- res.iterator
   157     } yield {
   155     } yield {
   162   }
   160   }
   163 
   161 
   164 
   162 
   165   /* text color */
   163   /* text color */
   166 
   164 
   167   def text_color(range: Text.Range): List[Text.Info[Rendering.Color.Value]] =
   165   def text_color(range: Text.Range): List[Text.Info[Rendering.Color.Value]] = {
   168   {
       
   169     snapshot.select(range, Rendering.text_color_elements, _ =>
   166     snapshot.select(range, Rendering.text_color_elements, _ =>
   170       {
   167       {
   171         case Text.Info(_, XML.Elem(Markup(name, props), _)) =>
   168         case Text.Info(_, XML.Elem(Markup(name, props), _)) =>
   172           if (name != Markup.IMPROPER && props.contains((Markup.KIND, Markup.COMMAND))) None
   169           if (name != Markup.IMPROPER && props.contains((Markup.KIND, Markup.COMMAND))) None
   173           else Rendering.text_color.get(name)
   170           else Rendering.text_color.get(name)
   178   /* text overview color */
   175   /* text overview color */
   179 
   176 
   180   private sealed case class Color_Info(
   177   private sealed case class Color_Info(
   181     color: Rendering.Color.Value, offset: Text.Offset, end_offset: Text.Offset, end_line: Int)
   178     color: Rendering.Color.Value, offset: Text.Offset, end_offset: Text.Offset, end_line: Int)
   182 
   179 
   183   def text_overview_color: List[Text.Info[Rendering.Color.Value]] =
   180   def text_overview_color: List[Text.Info[Rendering.Color.Value]] = {
   184   {
   181     @tailrec def loop(
   185     @tailrec def loop(offset: Text.Offset, line: Int, lines: List[Line], colors: List[Color_Info])
   182       offset: Text.Offset,
   186       : List[Text.Info[Rendering.Color.Value]] =
   183       line: Int,
   187     {
   184       lines: List[Line],
       
   185       colors: List[Color_Info]
       
   186     ): List[Text.Info[Rendering.Color.Value]] = {
   188       if (lines.nonEmpty) {
   187       if (lines.nonEmpty) {
   189         val end_offset = offset + lines.head.text.length
   188         val end_offset = offset + lines.head.text.length
   190         val colors1 =
   189         val colors1 =
   191           (overview_color(Text.Range(offset, end_offset)), colors) match {
   190           (overview_color(Text.Range(offset, end_offset)), colors) match {
   192             case (Some(color), old :: rest) if color == old.color && line == old.end_line =>
   191             case (Some(color), old :: rest) if color == old.color && line == old.end_line =>
   233         () =>
   232         () =>
   234           VSCode_Rendering.color_decorations("dotted_", VSCode_Rendering.dotted_colors,
   233           VSCode_Rendering.color_decorations("dotted_", VSCode_Rendering.dotted_colors,
   235             dotted(model.content.text_range)))).flatten :::
   234             dotted(model.content.text_range)))).flatten :::
   236     List(VSCode_Spell_Checker.decoration(rendering))
   235     List(VSCode_Spell_Checker.decoration(rendering))
   237 
   236 
   238   def decoration_output(decoration: List[VSCode_Model.Decoration]): LSP.Decoration =
   237   def decoration_output(decoration: List[VSCode_Model.Decoration]): LSP.Decoration = {
   239   {
       
   240     val entries =
   238     val entries =
   241       for (deco <- decoration)
   239       for (deco <- decoration)
   242       yield {
   240       yield {
   243         val decopts = for(Text.Info(text_range, msgs) <- deco.content)
   241         val decopts = for(Text.Info(text_range, msgs) <- deco.content)
   244           yield {
   242           yield {
   258   override def timing_threshold: Double = options.real("vscode_timing_threshold")
   256   override def timing_threshold: Double = options.real("vscode_timing_threshold")
   259 
   257 
   260 
   258 
   261   /* hyperlinks */
   259   /* hyperlinks */
   262 
   260 
   263   def hyperlink_source_file(source_name: String, line1: Int, range: Symbol.Range)
   261   def hyperlink_source_file(
   264     : Option[Line.Node_Range] =
   262     source_name: String,
   265   {
   263     line1: Int,
       
   264     range: Symbol.Range
       
   265   ): Option[Line.Node_Range] = {
   266     for {
   266     for {
   267       platform_path <- resources.source_file(source_name)
   267       platform_path <- resources.source_file(source_name)
   268       file <-
   268       file <-
   269         (try { Some(File.absolute(new JFile(platform_path))) }
   269         (try { Some(File.absolute(new JFile(platform_path))) }
   270          catch { case ERROR(_) => None })
   270          catch { case ERROR(_) => None })
   283         }
   283         }
   284         else Line.Range(Line.Position((line1 - 1) max 0)))
   284         else Line.Range(Line.Position((line1 - 1) max 0)))
   285     }
   285     }
   286   }
   286   }
   287 
   287 
   288   def hyperlink_command(id: Document_ID.Generic, range: Symbol.Range): Option[Line.Node_Range] =
   288   def hyperlink_command(id: Document_ID.Generic, range: Symbol.Range): Option[Line.Node_Range] = {
   289   {
       
   290     if (snapshot.is_outdated) None
   289     if (snapshot.is_outdated) None
   291     else
   290     else
   292       for {
   291       for {
   293         start <- snapshot.find_command_position(id, range.start)
   292         start <- snapshot.find_command_position(id, range.start)
   294         stop <- snapshot.find_command_position(id, range.stop)
   293         stop <- snapshot.find_command_position(id, range.stop)
   307       case Position.Item_Def_File(name, line, range) => hyperlink_source_file(name, line, range)
   306       case Position.Item_Def_File(name, line, range) => hyperlink_source_file(name, line, range)
   308       case Position.Item_Def_Id(id, range) => hyperlink_command(id, range)
   307       case Position.Item_Def_Id(id, range) => hyperlink_command(id, range)
   309       case _ => None
   308       case _ => None
   310     }
   309     }
   311 
   310 
   312   def hyperlinks(range: Text.Range): List[Line.Node_Range] =
   311   def hyperlinks(range: Text.Range): List[Line.Node_Range] = {
   313   {
       
   314     snapshot.cumulate[List[Line.Node_Range]](
   312     snapshot.cumulate[List[Line.Node_Range]](
   315       range, Nil, VSCode_Rendering.hyperlink_elements, _ =>
   313       range, Nil, VSCode_Rendering.hyperlink_elements, _ =>
   316         {
   314         {
   317           case (links, Text.Info(_, XML.Elem(Markup.Path(name), _))) =>
   315           case (links, Text.Info(_, XML.Elem(Markup.Path(name), _))) =>
   318             val file = perhaps_append_file(snapshot.node_name, name)
   316             val file = perhaps_append_file(snapshot.node_name, name)