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) |