src/Tools/VSCode/src/server.scala
changeset 64622 529bbb8977c7
parent 64618 c81bd30839a6
child 64623 83f012ce2567
equal deleted inserted replaced
64621:7116f2634e32 64622:529bbb8977c7
   186       })
   186       })
   187     delay_flush.invoke()
   187     delay_flush.invoke()
   188   }
   188   }
   189 
   189 
   190 
   190 
   191   /* tooltips -- see $ISABELLE_HOME/src/Tools/jEdit/rendering.scala */
   191   /* hover */
   192 
   192 
   193   def hover(uri: String, pos: Line.Position): Option[(Line.Range, List[String])] =
   193   def hover(uri: String, pos: Line.Position): Option[(Line.Range, List[String])] =
   194     for {
   194     for {
   195       model <- state.value.models.get(uri)
   195       model <- state.value.models.get(uri)
   196       snapshot = model.snapshot()
   196       rendering = model.rendering(options)
   197       offset <- model.doc.offset(pos, text_length)
   197       offset <- model.doc.offset(pos, text_length)
   198       info <- tooltip(snapshot, Text.Range(offset, offset + 1))
   198       info <- rendering.tooltip(Text.Range(offset, offset + 1))
   199     } yield {
   199     } yield {
   200       val start = model.doc.position(info.range.start, text_length)
   200       val start = model.doc.position(info.range.start, text_length)
   201       val stop = model.doc.position(info.range.stop, text_length)
   201       val stop = model.doc.position(info.range.stop, text_length)
   202       val s = Pretty.string_of(info.info, margin = tooltip_margin.toDouble)
   202       val s = Pretty.string_of(info.info, margin = rendering.tooltip_margin)
   203       (Line.Range(start, stop), List("```\n" + s + "\n```"))
   203       (Line.Range(start, stop), List("```\n" + s + "\n```"))
   204     }
   204     }
   205 
       
   206   private val tooltip_descriptions =
       
   207     Map(
       
   208       Markup.CITATION -> "citation",
       
   209       Markup.TOKEN_RANGE -> "inner syntax token",
       
   210       Markup.FREE -> "free variable",
       
   211       Markup.SKOLEM -> "skolem variable",
       
   212       Markup.BOUND -> "bound variable",
       
   213       Markup.VAR -> "schematic variable",
       
   214       Markup.TFREE -> "free type variable",
       
   215       Markup.TVAR -> "schematic type variable")
       
   216 
       
   217   private val tooltip_elements =
       
   218     Markup.Elements(Markup.LANGUAGE, Markup.EXPRESSION, Markup.TIMING, Markup.ENTITY,
       
   219       Markup.SORTING, Markup.TYPING, Markup.CLASS_PARAMETER, Markup.ML_TYPING,
       
   220       Markup.ML_BREAKPOINT, Markup.PATH, Markup.DOC, Markup.URL, Markup.MARKDOWN_PARAGRAPH,
       
   221       Markup.Markdown_List.name) ++ Markup.Elements(tooltip_descriptions.keySet)
       
   222 
       
   223   private def pretty_typing(kind: String, body: XML.Body): XML.Tree =
       
   224     Pretty.block(XML.Text(kind) :: Pretty.brk(1) :: body)
       
   225 
       
   226   private def timing_threshold: Double = options.real("jedit_timing_threshold")
       
   227 
       
   228   def tooltip(snapshot: Document.Snapshot, range: Text.Range): Option[Text.Info[XML.Body]] =
       
   229   {
       
   230     def add(prev: Text.Info[(Timing, Vector[(Boolean, XML.Tree)])],
       
   231       r0: Text.Range, p: (Boolean, XML.Tree)): Text.Info[(Timing, Vector[(Boolean, XML.Tree)])] =
       
   232     {
       
   233       val r = snapshot.convert(r0)
       
   234       val (t, info) = prev.info
       
   235       if (prev.range == r)
       
   236         Text.Info(r, (t, info :+ p))
       
   237       else Text.Info(r, (t, Vector(p)))
       
   238     }
       
   239 
       
   240     val results =
       
   241       snapshot.cumulate[Text.Info[(Timing, Vector[(Boolean, XML.Tree)])]](
       
   242         range, Text.Info(range, (Timing.zero, Vector.empty)), tooltip_elements, _ =>
       
   243         {
       
   244           case (Text.Info(r, (t1, info)), Text.Info(_, XML.Elem(Markup.Timing(t2), _))) =>
       
   245             Some(Text.Info(r, (t1 + t2, info)))
       
   246 
       
   247           case (prev, Text.Info(r, XML.Elem(Markup.Entity(kind, name), _)))
       
   248           if kind != "" &&
       
   249             kind != Markup.ML_DEF &&
       
   250             kind != Markup.ML_OPEN &&
       
   251             kind != Markup.ML_STRUCTURE =>
       
   252             val kind1 = Word.implode(Word.explode('_', kind))
       
   253             val txt1 =
       
   254               if (name == "") kind1
       
   255               else if (kind1 == "") quote(name)
       
   256               else kind1 + " " + quote(name)
       
   257             val t = prev.info._1
       
   258             val txt2 =
       
   259               if (kind == Markup.COMMAND && t.elapsed.seconds >= timing_threshold)
       
   260                 "\n" + t.message
       
   261               else ""
       
   262             Some(add(prev, r, (true, XML.Text(txt1 + txt2))))
       
   263 
       
   264           case (prev, Text.Info(r, XML.Elem(Markup.Doc(name), _))) =>
       
   265             val text = "doc " + quote(name)
       
   266             Some(add(prev, r, (true, XML.Text(text))))
       
   267 
       
   268           case (prev, Text.Info(r, XML.Elem(Markup.Url(name), _))) =>
       
   269             Some(add(prev, r, (true, XML.Text("URL " + quote(name)))))
       
   270 
       
   271           case (prev, Text.Info(r, XML.Elem(Markup(name, _), body)))
       
   272           if name == Markup.SORTING || name == Markup.TYPING =>
       
   273             Some(add(prev, r, (true, pretty_typing("::", body))))
       
   274 
       
   275           case (prev, Text.Info(r, XML.Elem(Markup(Markup.CLASS_PARAMETER, _), body))) =>
       
   276             Some(add(prev, r, (true, Pretty.block(0, body))))
       
   277 
       
   278           case (prev, Text.Info(r, XML.Elem(Markup(Markup.ML_TYPING, _), body))) =>
       
   279             Some(add(prev, r, (false, pretty_typing("ML:", body))))
       
   280 
       
   281           case (prev, Text.Info(r, XML.Elem(Markup.Language(language, _, _, _), _))) =>
       
   282             val lang = Word.implode(Word.explode('_', language))
       
   283             Some(add(prev, r, (true, XML.Text("language: " + lang))))
       
   284 
       
   285           case (prev, Text.Info(r, XML.Elem(Markup.Expression(kind), _))) =>
       
   286             val descr = if (kind == "") "expression" else "expression: " + kind
       
   287             Some(add(prev, r, (true, XML.Text(descr))))
       
   288 
       
   289           case (prev, Text.Info(r, XML.Elem(Markup(Markup.MARKDOWN_PARAGRAPH, _), _))) =>
       
   290             Some(add(prev, r, (true, XML.Text("Markdown: paragraph"))))
       
   291           case (prev, Text.Info(r, XML.Elem(Markup.Markdown_List(kind), _))) =>
       
   292             Some(add(prev, r, (true, XML.Text("Markdown: " + kind))))
       
   293 
       
   294           case (prev, Text.Info(r, XML.Elem(Markup(name, _), _))) =>
       
   295             tooltip_descriptions.get(name).
       
   296               map(descr => add(prev, r, (true, XML.Text(descr))))
       
   297         }).map(_.info)
       
   298 
       
   299     results.map(_.info).flatMap(res => res._2.toList) match {
       
   300       case Nil => None
       
   301       case tips =>
       
   302         val r = Text.Range(results.head.range.start, results.last.range.stop)
       
   303         val all_tips = (tips.filter(_._1) ++ tips.filter(!_._1).lastOption.toList).map(_._2)
       
   304         Some(Text.Info(r, Library.separate(Pretty.fbrk, all_tips)))
       
   305     }
       
   306   }
       
   307 
       
   308   def tooltip_margin: Int = options.int("jedit_tooltip_margin")
       
   309 
   205 
   310 
   206 
   311   /* main loop */
   207   /* main loop */
   312 
   208 
   313   def start()
   209   def start()