273 snapshot.select_markup[Command.Results](range, None, command_state => |
273 snapshot.select_markup[Command.Results](range, None, command_state => |
274 { case _ => command_state.results }).map(_.info) |
274 { case _ => command_state.results }).map(_.info) |
275 (Command.Results.empty /: results)(_ ++ _) |
275 (Command.Results.empty /: results)(_ ++ _) |
276 } |
276 } |
277 |
277 |
278 def tooltip_message(range: Text.Range): XML.Body = |
278 def tooltip_message(range: Text.Range): Option[Text.Info[XML.Body]] = |
279 { |
279 { |
280 val msgs = |
280 val results = |
281 Command.Results.merge( |
281 snapshot.cumulate_markup[List[Text.Info[Command.Results.Entry]]](range, Nil, |
282 snapshot.cumulate_markup[Command.Results](range, Command.Results.empty, |
282 Some(Set(Markup.WRITELN, Markup.WARNING, Markup.ERROR, Markup.BAD)), _ => |
283 Some(Set(Markup.WRITELN, Markup.WARNING, Markup.ERROR, Markup.BAD)), _ => |
283 { |
284 { |
284 case (msgs, Text.Info(info_range, |
285 case (msgs, Text.Info(_, XML.Elem(Markup(name, props @ Markup.Serial(serial)), body))) |
285 XML.Elem(Markup(name, props @ Markup.Serial(serial)), body))) |
286 if name == Markup.WRITELN || |
286 if name == Markup.WRITELN || name == Markup.WARNING || name == Markup.ERROR => |
287 name == Markup.WARNING || |
287 val entry: Command.Results.Entry = |
288 name == Markup.ERROR => |
288 (serial -> XML.Elem(Markup(Markup.message(name), props), body)) |
289 msgs + (serial -> XML.Elem(Markup(Markup.message(name), props), body)) |
289 Text.Info(snapshot.convert(info_range), entry) :: msgs |
290 case (msgs, Text.Info(_, msg @ XML.Elem(Markup(Markup.BAD, _), body))) |
290 |
291 if !body.isEmpty => msgs + (Document.new_id() -> msg) |
291 case (msgs, Text.Info(info_range, msg @ XML.Elem(Markup(Markup.BAD, _), body))) |
292 }).map(_.info)) |
292 if !body.isEmpty => |
293 Pretty.separate(msgs.entries.map(_._2).toList) |
293 val entry: Command.Results.Entry = (Document.new_id(), msg) |
|
294 Text.Info(snapshot.convert(info_range), entry) :: msgs |
|
295 }).toList.flatMap(_.info) |
|
296 if (results.isEmpty) None |
|
297 else { |
|
298 val r = Text.Range(results.head.range.start, results.last.range.stop) |
|
299 val msgs = Command.Results.make(results.map(_.info)) |
|
300 Some(Text.Info(r, Pretty.separate(msgs.entries.map(_._2).toList))) |
|
301 } |
294 } |
302 } |
295 |
303 |
296 |
304 |
297 private val tooltips: Map[String, String] = |
305 private val tooltips: Map[String, String] = |
298 Map( |
306 Map( |
315 tooltips.keys |
323 tooltips.keys |
316 |
324 |
317 private def pretty_typing(kind: String, body: XML.Body): XML.Tree = |
325 private def pretty_typing(kind: String, body: XML.Body): XML.Tree = |
318 Pretty.block(XML.Text(kind) :: Pretty.Break(1) :: body) |
326 Pretty.block(XML.Text(kind) :: Pretty.Break(1) :: body) |
319 |
327 |
320 def tooltip(range: Text.Range): XML.Body = |
328 def tooltip(range: Text.Range): Option[Text.Info[XML.Body]] = |
321 { |
329 { |
322 def add(prev: Text.Info[List[(Boolean, XML.Tree)]], r: Text.Range, p: (Boolean, XML.Tree)) = |
330 def add(prev: Text.Info[List[(Boolean, XML.Tree)]], r0: Text.Range, p: (Boolean, XML.Tree)) = |
|
331 { |
|
332 val r = snapshot.convert(r0) |
323 if (prev.range == r) Text.Info(r, p :: prev.info) else Text.Info(r, List(p)) |
333 if (prev.range == r) Text.Info(r, p :: prev.info) else Text.Info(r, List(p)) |
324 |
334 } |
325 val tips = |
335 |
|
336 val results = |
326 snapshot.cumulate_markup[Text.Info[(List[(Boolean, XML.Tree)])]]( |
337 snapshot.cumulate_markup[Text.Info[(List[(Boolean, XML.Tree)])]]( |
327 range, Text.Info(range, Nil), Some(tooltip_elements), _ => |
338 range, Text.Info(range, Nil), Some(tooltip_elements), _ => |
328 { |
339 { |
329 case (prev, Text.Info(r, XML.Elem(Markup.Entity(kind, name), _))) => |
340 case (prev, Text.Info(r, XML.Elem(Markup.Entity(kind, name), _))) => |
330 val kind1 = space_explode('_', kind).mkString(" ") |
341 val kind1 = space_explode('_', kind).mkString(" ") |
338 add(prev, r, (true, pretty_typing("::", body))) |
349 add(prev, r, (true, pretty_typing("::", body))) |
339 case (prev, Text.Info(r, XML.Elem(Markup(Markup.ML_TYPING, _), body))) => |
350 case (prev, Text.Info(r, XML.Elem(Markup(Markup.ML_TYPING, _), body))) => |
340 add(prev, r, (false, pretty_typing("ML:", body))) |
351 add(prev, r, (false, pretty_typing("ML:", body))) |
341 case (prev, Text.Info(r, XML.Elem(Markup(name, _), _))) |
352 case (prev, Text.Info(r, XML.Elem(Markup(name, _), _))) |
342 if tooltips.isDefinedAt(name) => add(prev, r, (true, XML.Text(tooltips(name)))) |
353 if tooltips.isDefinedAt(name) => add(prev, r, (true, XML.Text(tooltips(name)))) |
343 }).toList.flatMap(_.info.info) |
354 }).toList.map(_.info) |
344 |
355 |
345 val all_tips = |
356 results.flatMap(_.info) match { |
346 (tips.filter(_._1) ++ tips.filter(!_._1).lastOption.toList).map(_._2) |
357 case Nil => None |
347 Library.separate(Pretty.FBreak, all_tips.toList) |
358 case tips => |
|
359 val r = Text.Range(results.head.range.start, results.last.range.stop) |
|
360 val all_tips = (tips.filter(_._1) ++ tips.filter(!_._1).lastOption.toList).map(_._2) |
|
361 Some(Text.Info(r, Library.separate(Pretty.FBreak, all_tips))) |
|
362 } |
348 } |
363 } |
349 |
364 |
350 val tooltip_margin: Int = options.int("jedit_tooltip_margin") |
365 val tooltip_margin: Int = options.int("jedit_tooltip_margin") |
351 val tooltip_bounds: Double = (options.real("jedit_tooltip_bounds") max 0.2) min 0.8 |
366 val tooltip_bounds: Double = (options.real("jedit_tooltip_bounds") max 0.2) min 0.8 |
352 |
367 |