1#![allow(clippy::too_many_lines)]
2
3use std::fmt::Write;
4
5use crate::capabilities::STeXSemanticTokens;
6use crate::documents::LSPDocument;
7use crate::{
8 IsLSPRange, ProgressCallbackClient,
9 state::{DocData, LSPState, UrlOrFile},
10};
11use async_lsp::lsp_types as lsp;
12use flams_math_archives::LocalArchive;
13use flams_math_archives::backend::{GlobalBackend, LocalBackend};
14use flams_stex::quickparse::stex::rules::{IncludeProblemArg, SRefOptsA, SRefOptsB};
15use flams_stex::quickparse::{
16 latex::ParsedKeyValue,
17 stex::{
18 AnnotIter, DiagnosticLevel, STeXAnnot, STeXDiagnostic, STeXParseDataI,
19 rules::{
20 MathStructureArg, NotationArg, ParagraphArg, ProblemArg, SModuleArg, SymdeclArg,
21 SymdefArg, TextSymdeclArg, VardefArg,
22 },
23 structs::{
24 InlineMorphAssKind, InlineMorphAssign, ModuleOrStruct, MorphismKind, SymbolReference,
25 },
26 },
27};
28use flams_utils::sourcerefs::{ByteOffset, StringPosition};
29use flams_utils::{
30 prelude::TreeChildIter,
31 sourcerefs::{LSPLineCol, StringRange},
32};
33use ftml_ontology::narrative::elements::paragraphs::ParagraphKind;
34use ftml_uris::{
35 ArchiveId, ArchiveUri, IsDomainUri, IsNarrativeUri, ModuleUri, SymbolUri, Uri, UriWithArchive,
36 UriWithPath,
37};
38use futures::FutureExt;
39use smallvec::SmallVec;
40
41trait AnnotExt: Sized {
42 fn as_symbol(&self) -> Option<(lsp::DocumentSymbol, &[Self])>;
43 fn links(&self, top_archive: Option<&ArchiveUri>, f: impl FnMut(lsp::DocumentLink));
44 fn goto_definition(
45 &self,
46 in_doc: &UrlOrFile,
47 pos: LSPLineCol,
48 ) -> Option<lsp::GotoDefinitionResponse>;
49 fn semantic_tokens(&self, cont: &mut impl FnMut(StringRange<LSPLineCol>, u32));
50 fn hover(
51 &self,
52 top_archive: Option<&ArchiveUri>,
53 pos: LSPLineCol,
54 ) -> Option<either_of::Either<lsp::Hover, (lsp::Range, SymbolReference<LSPLineCol>)>>;
55 fn inlay_hint(&self) -> Option<lsp::InlayHint>;
56 fn code_action(&self, pos: LSPLineCol, url: &lsp::Url) -> lsp::CodeActionResponse;
57}
58
59pub(crate) fn uri_from_archive_relpath(id: &ArchiveId, relpath: &str) -> Option<lsp::Url> {
60 let path = GlobalBackend.with_local_archive(id, |a| a.map(LocalArchive::source_dir))?;
61 let path = relpath.split('/').fold(path, |p, s| p.join(s));
62 lsp::Url::from_file_path(path).ok()
63}
64
65#[allow(deprecated)]
66impl AnnotExt for STeXAnnot {
67 fn as_symbol(&self) -> Option<(lsp::DocumentSymbol, &[Self])> {
68 match self {
69 Self::Module {
70 uri,
71 full_range,
72 name_range,
73 children,
74 ..
75 } => Some((
76 lsp::DocumentSymbol {
77 name: uri.to_string(),
78 detail: None,
79 kind: lsp::SymbolKind::MODULE,
80 tags: None,
81 deprecated: None,
82 range: full_range.into_range(),
83 selection_range: name_range.into_range(),
84 children: None,
85 },
86 children,
87 )),
88 Self::MathStructure {
89 uri,
90 name_range,
91 full_range,
92 children,
93 ..
94 } => Some((
95 lsp::DocumentSymbol {
96 name: uri.uri.to_string(),
97 detail: None,
98 kind: lsp::SymbolKind::STRUCT,
99 tags: None,
100 deprecated: None,
101 range: full_range.into_range(),
102 selection_range: name_range.into_range(),
103 children: None,
104 },
105 children,
106 )),
107 Self::ConservativeExt {
108 uri,
109 full_range,
110 extstructure_range,
111 children,
112 ..
113 } => Some((
114 lsp::DocumentSymbol {
115 name: format!("{}_EXT", uri.uri),
116 detail: None,
117 kind: lsp::SymbolKind::STRUCT,
118 tags: None,
119 deprecated: None,
120 range: full_range.into_range(),
121 selection_range: extstructure_range.into_range(),
122 children: None,
123 },
124 children,
125 )),
126 Self::MorphismEnv {
127 full_range,
128 env_range,
129 uri,
130 children,
131 ..
132 } => Some((
133 lsp::DocumentSymbol {
134 name: uri.to_string(),
135 detail: None,
136 kind: lsp::SymbolKind::INTERFACE,
137 tags: None,
138 deprecated: None,
139 range: full_range.into_range(),
140 selection_range: env_range.into_range(),
141 children: None,
142 },
143 children,
144 )),
145 Self::InlineMorphism {
146 full_range,
147 uri,
148 token_range,
149 ..
150 } => Some((
151 lsp::DocumentSymbol {
152 name: uri.to_string(),
153 detail: None,
154 kind: lsp::SymbolKind::INTERFACE,
155 tags: None,
156 deprecated: None,
157 range: full_range.into_range(),
158 selection_range: token_range.into_range(),
159 children: None,
160 },
161 &[],
162 )),
163 Self::Paragraph {
164 kind,
165 full_range,
166 name_range,
167 children,
168 ..
169 }
170 | Self::InlineParagraph {
171 kind,
172 full_range,
173 token_range: name_range,
174 children,
175 ..
176 } => Some((
177 lsp::DocumentSymbol {
178 name: kind.to_string(),
179 detail: None,
180 kind: lsp::SymbolKind::PACKAGE,
181 tags: None,
182 deprecated: None,
183 range: full_range.into_range(),
184 selection_range: name_range.into_range(),
185 children: None,
186 },
187 children,
188 )),
189 Self::Problem {
190 full_range,
191 name_range,
192 children,
193 ..
194 } => Some((
195 lsp::DocumentSymbol {
196 name: "problem".to_string(),
197 detail: None,
198 kind: lsp::SymbolKind::PACKAGE,
199 tags: None,
200 deprecated: None,
201 range: full_range.into_range(),
202 selection_range: name_range.into_range(),
203 children: None,
204 },
205 children,
206 )),
207 Self::Symdecl {
208 uri,
209 main_name_range,
210 full_range,
211 ..
212 }
213 | Self::TextSymdecl {
214 uri,
215 main_name_range,
216 full_range,
217 ..
218 }
219 | Self::Symdef {
220 uri,
221 main_name_range,
222 full_range,
223 ..
224 } => Some((
225 lsp::DocumentSymbol {
226 name: uri.uri.to_string(),
227 detail: None,
228 kind: lsp::SymbolKind::OBJECT,
229 tags: None,
230 deprecated: None,
231 range: full_range.into_range(),
232 selection_range: main_name_range.into_range(),
233 children: None,
234 },
235 &[],
236 )),
237 Self::Vardef {
238 name,
239 main_name_range,
240 full_range,
241 ..
242 }
243 | Self::Varseq {
244 name,
245 main_name_range,
246 full_range,
247 ..
248 } => Some((
249 lsp::DocumentSymbol {
250 name: name.to_string(),
251 detail: None,
252 kind: lsp::SymbolKind::VARIABLE,
253 tags: None,
254 deprecated: None,
255 range: full_range.into_range(),
256 selection_range: main_name_range.into_range(),
257 children: None,
258 },
259 &[],
260 )),
261 Self::ImportModule {
262 module, full_range, ..
263 } => Some((
264 lsp::DocumentSymbol {
265 name: format!("import@{}", module.uri),
266 detail: Some(module.uri.to_string()),
267 kind: lsp::SymbolKind::PACKAGE,
268 tags: None,
269 deprecated: None,
270 range: full_range.into_range(),
271 selection_range: full_range.into_range(),
272 children: None,
273 },
274 &[],
275 )),
276 Self::UseModule {
277 module, full_range, ..
278 } => Some((
279 lsp::DocumentSymbol {
280 name: format!("usemodule@{}", module.uri),
281 detail: Some(module.uri.to_string()),
282 kind: lsp::SymbolKind::PACKAGE,
283 tags: None,
284 deprecated: None,
285 range: full_range.into_range(),
286 selection_range: full_range.into_range(),
287 children: None,
288 },
289 &[],
290 )),
291 Self::UseStructure {
292 structure,
293 full_range,
294 ..
295 } => Some((
296 lsp::DocumentSymbol {
297 name: format!("usestructure@{}", structure.uri),
298 detail: None,
299 kind: lsp::SymbolKind::PACKAGE,
300 tags: None,
301 deprecated: None,
302 range: full_range.into_range(),
303 selection_range: full_range.into_range(),
304 children: None,
305 },
306 &[],
307 )),
308 Self::SetMetatheory {
309 module, full_range, ..
310 } => Some((
311 lsp::DocumentSymbol {
312 name: format!("metatheory@{}", module.uri),
313 detail: Some(module.uri.to_string()),
314 kind: lsp::SymbolKind::NAMESPACE,
315 tags: None,
316 deprecated: None,
317 range: full_range.into_range(),
318 selection_range: full_range.into_range(),
319 children: None,
320 },
321 &[],
322 )),
323 Self::Inputref {
324 archive,
325 filepath,
326 full_range: range,
327 ..
328 }
329 | Self::IncludeProblem {
330 archive,
331 filepath,
332 full_range: range,
333 ..
334 } => Some((
335 lsp::DocumentSymbol {
336 name: archive.as_ref().map_or_else(
337 || format!("inputref@{}", filepath.0),
338 |(a, _)| format!("inputref@[{a}]{}", filepath.0),
339 ),
340 detail: None,
341 kind: lsp::SymbolKind::PACKAGE,
342 tags: None,
343 deprecated: None,
344 range: range.into_range(),
345 selection_range: range.into_range(),
346 children: None,
347 },
348 &[],
349 )),
350 Self::MHInput {
351 archive,
352 filepath,
353 full_range: range,
354 ..
355 } => Some((
356 lsp::DocumentSymbol {
357 name: archive.as_ref().map_or_else(
358 || format!("mhinput@{}", filepath.0),
359 |(a, _)| format!("mhinput@[{a}]{}", filepath.0),
360 ),
361 detail: None,
362 kind: lsp::SymbolKind::PACKAGE,
363 tags: None,
364 deprecated: None,
365 range: range.into_range(),
366 selection_range: range.into_range(),
367 children: None,
368 },
369 &[],
370 )),
371 Self::MHGraphics { .. }
372 | Self::SemanticMacro { .. }
373 | Self::VariableMacro { .. }
374 | Self::SymName { .. }
375 | Self::Symref { .. }
376 | Self::Notation { .. }
377 | Self::Svar { .. }
378 | Self::Symuse { .. }
379 | Self::Definiens { .. }
380 | Self::Defnotation { .. }
381 | Self::RenameDecl { .. }
382 | Self::Precondition { .. }
383 | Self::Objective { .. }
384 | Self::Assign { .. }
385 | Self::SRef { .. }
386 | Self::SnifySuggestion { .. } => None,
387 }
388 }
389
390 fn links(&self, top_archive: Option<&ArchiveUri>, mut cont: impl FnMut(lsp::DocumentLink)) {
391 match self {
392 Self::IncludeProblem {
393 archive, filepath, ..
394 } => {
395 let Some(a) = archive
396 .as_ref()
397 .map_or_else(|| top_archive.map(ArchiveUri::archive_id), |(a, _)| Some(a))
398 else {
399 return;
400 };
401 let Some(uri) = uri_from_archive_relpath(a, &filepath.0) else {
402 return;
403 };
404 cont(lsp::DocumentLink {
405 range: filepath.1.into_range(),
406 target: Some(uri),
407 tooltip: None,
408 data: None,
409 });
410 }
411 Self::SRef {
412 label_range,
413 opt_args,
414 in_opt_args,
415 target_path,
416 in_doc,
417 ..
418 } => {
419 if let Ok(url) = lsp::Url::from_file_path(target_path) {
420 for o in opt_args {
421 if let SRefOptsA::File(f) = o {
422 cont(lsp::DocumentLink {
423 range: f.val_range.into_range(),
424 target: Some(url.clone()),
425 tooltip: None,
426 data: None,
427 });
428 break;
429 }
430 }
431 cont(lsp::DocumentLink {
432 range: label_range.into_range(),
433 target: Some(url),
434 tooltip: None,
435 data: None,
436 });
437 }
438 if let Some((_, id)) = in_doc
439 && let Ok(url) = lsp::Url::from_file_path(id)
440 && let Some(rng) = in_opt_args.iter().find_map(|a| {
441 if let SRefOptsB::File(f) = a {
442 Some(f.val_range)
443 } else {
444 None
445 }
446 })
447 {
448 cont(lsp::DocumentLink {
449 range: rng.into_range(),
450 target: Some(url),
451 tooltip: None,
452 data: None,
453 });
454 }
455 }
456 Self::MHGraphics {
457 archive, filepath, ..
458 } => {
459 let Some(a) = archive.as_ref().map_or_else(
460 || top_archive.map(UriWithArchive::archive_id),
461 |(a, _)| Some(a),
462 ) else {
463 return;
464 };
465 let Some(uri) = uri_from_archive_relpath(a, &filepath.0) else {
466 return;
467 };
468 cont(lsp::DocumentLink {
469 range: filepath.1.into_range(),
470 target: Some(uri),
471 tooltip: None,
472 data: None,
473 });
474 }
475 Self::Inputref {
476 archive,
477 token_range,
478 filepath,
479 full_range: range,
480 ..
481 }
482 | Self::MHInput {
483 archive,
484 token_range,
485 filepath,
486 full_range: range,
487 ..
488 } => {
489 let Some(a) = archive.as_ref().map_or_else(
490 || top_archive.map(UriWithArchive::archive_id),
491 |(a, _)| Some(a),
492 ) else {
493 return;
494 };
495 let Some(uri) = uri_from_archive_relpath(a, &filepath.0) else {
496 return;
497 };
498 let mut range = *range;
499 range.start = token_range.end;
500 cont(lsp::DocumentLink {
501 range: range.into_range(),
502 target: Some(uri),
503 tooltip: None,
504 data: None,
505 });
506 }
507 Self::ImportModule { .. }
508 | Self::UseModule { .. }
509 | Self::SemanticMacro { .. }
510 | Self::VariableMacro { .. }
511 | Self::SetMetatheory { .. }
512 | Self::Module { .. }
513 | Self::MathStructure { .. }
514 | Self::Symdecl { .. }
515 | Self::TextSymdecl { .. }
516 | Self::SymName { .. }
517 | Self::Symref { .. }
518 | Self::Notation { .. }
519 | Self::Symdef { .. }
520 | Self::Vardef { .. }
521 | Self::Paragraph { .. }
522 | Self::Symuse { .. }
523 | Self::Svar { .. }
524 | Self::Varseq { .. }
525 | Self::Definiens { .. }
526 | Self::Defnotation { .. }
527 | Self::ConservativeExt { .. }
528 | Self::UseStructure { .. }
529 | Self::InlineParagraph { .. }
530 | Self::Problem { .. }
531 | Self::MorphismEnv { .. }
532 | Self::RenameDecl { .. }
533 | Self::Precondition { .. }
534 | Self::Objective { .. }
535 | Self::Assign { .. }
536 | Self::InlineMorphism { .. }
537 | Self::SnifySuggestion { .. } => (),
538 }
539 }
540
541 fn semantic_tokens(&self, cont: &mut impl FnMut(StringRange<LSPLineCol>, u32)) {
542 match self {
543 Self::SRef {
544 token_range,
545 opt_args,
546 in_opt_args,
547 ..
548 } => {
549 use SRefOptsA as A;
550 use SRefOptsB as B;
551 cont(*token_range, STeXSemanticTokens::REF_MACRO);
552 for o in opt_args {
553 match o {
554 A::Archive(a) | A::File(a) => {
555 cont(a.key_range, STeXSemanticTokens::KEYWORD);
556 }
557 A::Fallback(a) => {
558 cont(a.key_range, STeXSemanticTokens::KEYWORD);
559 for e in &a.val {
560 e.semantic_tokens(cont);
561 }
562 }
563 A::Pre(a) | A::Post(a) => {
564 cont(a.key_range, STeXSemanticTokens::KEYWORD);
565 }
566 }
567 }
568 for o in in_opt_args {
569 match o {
570 B::Archive(a) | B::File(a) => {
571 cont(a.key_range, STeXSemanticTokens::KEYWORD);
572 }
573 B::Title(a) => {
574 cont(a.key_range, STeXSemanticTokens::KEYWORD);
575 for e in &a.val {
576 e.semantic_tokens(cont);
577 }
578 }
579 }
580 }
581 }
582 Self::Module {
583 name_range,
584 full_range,
585 smodule_range,
586 opts,
587 children,
588 ..
589 } => {
590 cont(*smodule_range, STeXSemanticTokens::DECLARATION);
591 for o in opts {
592 match o {
593 SModuleArg::Title(v) => {
594 cont(v.key_range, STeXSemanticTokens::KEYWORD);
595 for e in &v.val {
596 e.semantic_tokens(cont);
597 }
598 }
599 SModuleArg::Sig(ParsedKeyValue {
600 key_range,
601 val_range,
602 ..
603 }) => {
604 cont(*key_range, STeXSemanticTokens::KEYWORD);
605 cont(*val_range, STeXSemanticTokens::KEYWORD);
606 }
607 SModuleArg::Meta(ParsedKeyValue { key_range, .. }) => {
610 cont(*key_range, STeXSemanticTokens::KEYWORD);
611 }
612 }
613 }
614 cont(*name_range, STeXSemanticTokens::NAME);
615 for c in children {
616 c.semantic_tokens(cont);
617 }
618 let mut end_range = *full_range;
619 end_range.end.col -= 1;
620 end_range.start.line = end_range.end.line;
621 #[allow(clippy::cast_possible_truncation)]
622 {
623 end_range.start.col = end_range.end.col - const { "smodule".len() as u32 };
624 }
625 cont(end_range, STeXSemanticTokens::DECLARATION);
626 }
627 Self::MathStructure {
628 extends,
629 name_range,
630 opts,
631 full_range,
632 children,
633 mathstructure_range,
634 ..
635 } => {
636 cont(*mathstructure_range, STeXSemanticTokens::DECLARATION);
637 cont(*name_range, STeXSemanticTokens::NAME);
638 for o in opts {
639 match o {
640 MathStructureArg::This(ParsedKeyValue { key_range, val, .. }) => {
641 cont(*key_range, STeXSemanticTokens::KEYWORD);
642 for e in val {
643 e.semantic_tokens(cont);
644 }
645 }
646 MathStructureArg::Name(range, _) => {
647 cont(*range, STeXSemanticTokens::NAME);
648 }
649 }
650 }
651 for (_, r) in extends {
652 cont(*r, STeXSemanticTokens::SYMBOL);
653 }
654 for c in children {
655 c.semantic_tokens(cont);
656 }
657 let mut end_range = *full_range;
658 end_range.end.col -= 1;
659 end_range.start.line = end_range.end.line;
660 let s = if extends.is_empty() {
661 "mathstructure"
662 } else {
663 "extstructure"
664 };
665 end_range.start.col = end_range.end.col - s.len() as u32;
666 cont(end_range, STeXSemanticTokens::DECLARATION);
667 }
668 Self::ConservativeExt {
669 ext_range,
670 full_range,
671 extstructure_range,
672 children,
673 ..
674 } => {
675 cont(*extstructure_range, STeXSemanticTokens::DECLARATION);
676 cont(*ext_range, STeXSemanticTokens::SYMBOL);
677 for c in children {
678 c.semantic_tokens(cont);
679 }
680 let mut end_range = *full_range;
681 end_range.end.col -= 1;
682 end_range.start.line = end_range.end.line;
683 end_range.start.col = end_range.end.col - "extstructure*".len() as u32;
684 cont(end_range, STeXSemanticTokens::DECLARATION);
685 }
686 Self::MorphismEnv {
687 env_range,
688 star,
689 kind,
690 name_range,
691 domain_range,
692 full_range,
693 domain,
694 children,
695 ..
696 } => {
697 cont(*env_range, STeXSemanticTokens::DECLARATION);
698 cont(*name_range, STeXSemanticTokens::NAME);
699 match domain {
700 ModuleOrStruct::Struct(_) => cont(*domain_range, STeXSemanticTokens::SYMBOL),
701 _ => (),
702 }
703 for c in children {
704 c.semantic_tokens(cont);
705 }
706
707 let mut end_range = *full_range;
708 end_range.end.col -= 1;
709 end_range.start.line = end_range.end.line;
710 let len = match kind {
711 MorphismKind::CopyModule => "copymodule".len(),
712 MorphismKind::InterpretModule => "interpretmodule".len(),
713 };
714 let len = if *star { len + 1 } else { len };
715 end_range.start.col = end_range.end.col - len as u32;
716 cont(end_range, STeXSemanticTokens::DECLARATION);
717 }
718 Self::InlineMorphism {
719 token_range,
720 name_range,
721 domain_range,
722 domain,
723 assignments,
724 ..
725 } => {
726 cont(*token_range, STeXSemanticTokens::DECLARATION);
727 cont(*name_range, STeXSemanticTokens::NAME);
728 match domain {
729 ModuleOrStruct::Struct(_) => cont(*domain_range, STeXSemanticTokens::SYMBOL),
730 _ => (),
731 }
732 for InlineMorphAssign {
733 first,
734 second,
735 symbol_range,
736 ..
737 } in assignments
738 {
739 cont(*symbol_range, STeXSemanticTokens::SYMBOL);
740 if let Some((e, knd)) = first {
741 let end = LSPLineCol::new(e.line, e.col + 1);
742 let range = StringRange { start: *e, end };
743 cont(range, STeXSemanticTokens::KEYWORD);
744 match knd {
745 InlineMorphAssKind::Df(v) => {
746 for c in v {
747 c.semantic_tokens(cont);
748 }
749 }
750 InlineMorphAssKind::Rename(mn, _, n) => {
751 if let Some((_, mn)) = mn {
752 cont(*mn, STeXSemanticTokens::NAME);
753 }
754 cont(*n, STeXSemanticTokens::NAME);
755 }
756 }
757 }
758 if let Some((e, knd)) = second {
759 let end = LSPLineCol::new(e.line, e.col + 1);
760 let range = StringRange { start: *e, end };
761 cont(range, STeXSemanticTokens::KEYWORD);
762 match knd {
763 InlineMorphAssKind::Df(v) => {
764 for c in v {
765 c.semantic_tokens(cont);
766 }
767 }
768 InlineMorphAssKind::Rename(mn, _, n) => {
769 if let Some((_, mn)) = mn {
770 cont(*mn, STeXSemanticTokens::NAME);
771 }
772 cont(*n, STeXSemanticTokens::NAME);
773 }
774 }
775 }
776 }
777 }
778 Self::UseModule { token_range, .. } => cont(*token_range, STeXSemanticTokens::LOCAL),
779 Self::UseStructure {
780 token_range,
781 structure_range,
782 ..
783 } => {
784 cont(*token_range, STeXSemanticTokens::LOCAL);
785 cont(*structure_range, STeXSemanticTokens::SYMBOL);
786 }
787 Self::IncludeProblem {
788 token_range, args, ..
789 } => {
790 cont(*token_range, STeXSemanticTokens::REF_MACRO);
791 for a in args {
792 let r = match a {
793 IncludeProblemArg::Min(m) => m.key_range,
794 IncludeProblemArg::Pts(m) => m.key_range,
795 IncludeProblemArg::Archive(m) => m.key_range,
796 };
797 cont(r, STeXSemanticTokens::KEYWORD);
798 }
799 }
800 Self::Inputref {
801 token_range: range, ..
802 }
803 | Self::MHInput {
804 token_range: range, ..
805 }
806 | Self::MHGraphics {
807 token_range: range, ..
808 }
809 | Self::Defnotation { full_range: range } => {
810 cont(*range, STeXSemanticTokens::REF_MACRO)
811 }
812 Self::SetMetatheory { token_range, .. } | Self::ImportModule { token_range, .. } => {
813 cont(*token_range, STeXSemanticTokens::DECLARATION)
814 }
815 Self::SemanticMacro { token_range, .. } => {
816 cont(*token_range, STeXSemanticTokens::SYMBOL)
817 }
818 Self::VariableMacro { token_range, .. } => {
819 cont(*token_range, STeXSemanticTokens::VARIABLE)
820 }
821 Self::Problem {
822 full_range,
823 name_range,
824 parsed_args,
825 children,
826 ..
827 } => {
828 cont(*name_range, STeXSemanticTokens::REF_MACRO);
829 for e in parsed_args {
830 match e {
831 ProblemArg::Autogradable(ParsedKeyValue {
836 key_range,
837 val_range,
838 ..
839 }) => {
840 cont(*key_range, STeXSemanticTokens::KEYWORD);
841 cont(*val_range, STeXSemanticTokens::KEYWORD);
842 }
843 ProblemArg::Style(ParsedKeyValue { key_range, .. })
844 | ProblemArg::Pts(ParsedKeyValue { key_range, .. })
845 | ProblemArg::Min(ParsedKeyValue { key_range, .. })
846 | ProblemArg::Id(ParsedKeyValue { key_range, .. }) => {
847 cont(*key_range, STeXSemanticTokens::KEYWORD)
848 }
849 ProblemArg::Title(ParsedKeyValue { key_range, val, .. }) => {
850 cont(*key_range, STeXSemanticTokens::KEYWORD);
851 for c in val {
852 c.semantic_tokens(cont);
853 }
854 }
855 }
856 }
857 for c in children {
858 c.semantic_tokens(cont);
859 }
860 let mut end_range = *full_range;
861 end_range.end.col -= 1;
862 end_range.start.line = end_range.end.line;
863 cont(end_range, STeXSemanticTokens::REF_MACRO);
864 }
865 Self::Paragraph {
866 kind,
867 symbol,
868 name_range,
869 parsed_args,
870 children,
871 full_range,
872 ..
873 } => {
874 if symbol.is_some() {
875 cont(*name_range, STeXSemanticTokens::DECLARATION);
876 } else {
877 cont(*name_range, STeXSemanticTokens::REF_MACRO);
878 }
879 for e in parsed_args {
880 match e {
881 ParagraphArg::Tp(ParsedKeyValue { key_range, val, .. })
882 | ParagraphArg::Df(ParsedKeyValue { key_range, val, .. })
883 | ParagraphArg::Return(ParsedKeyValue { key_range, val, .. })
884 | ParagraphArg::Argtypes(ParsedKeyValue { key_range, val, .. })
885 | ParagraphArg::Title(ParsedKeyValue { key_range, val, .. }) => {
886 cont(*key_range, STeXSemanticTokens::KEYWORD);
887 for c in val {
888 c.semantic_tokens(cont);
889 }
890 }
891 ParagraphArg::Args(ParsedKeyValue {
892 key_range,
893 val_range,
894 ..
895 }) => {
896 cont(*key_range, STeXSemanticTokens::KEYWORD);
897 cont(*val_range, STeXSemanticTokens::KEYWORD);
898 }
899 ParagraphArg::Name(ParsedKeyValue {
900 key_range,
901 val_range,
902 ..
903 })
904 | ParagraphArg::MacroName(ParsedKeyValue {
905 key_range,
906 val_range,
907 ..
908 }) => {
909 cont(*key_range, STeXSemanticTokens::KEYWORD);
910 cont(*val_range, STeXSemanticTokens::NAME);
911 }
912 ParagraphArg::Style(ParsedKeyValue { key_range, .. })
913 | ParagraphArg::Assoc(ParsedKeyValue { key_range, .. })
914 | ParagraphArg::Role(ParsedKeyValue { key_range, .. })
915 | ParagraphArg::Reorder(ParsedKeyValue { key_range, .. })
916 | ParagraphArg::From(ParsedKeyValue { key_range, .. })
917 | ParagraphArg::To(ParsedKeyValue { key_range, .. })
918 | ParagraphArg::Judgment(ParsedKeyValue { key_range, .. })
919 | ParagraphArg::Id(ParsedKeyValue { key_range, .. }) => {
920 cont(*key_range, STeXSemanticTokens::KEYWORD)
921 }
922 ParagraphArg::Fors(ParsedKeyValue { key_range, val, .. }) => {
923 cont(*key_range, STeXSemanticTokens::KEYWORD);
924 for (_, f) in val {
925 cont(*f, STeXSemanticTokens::SYMBOL);
926 }
927 }
928 }
929 }
930 for c in children {
931 c.semantic_tokens(cont);
932 }
933 let mut end_range = *full_range;
934 end_range.end.col -= 1;
935 end_range.start.line = end_range.end.line;
936 let parname = match kind {
937 ParagraphKind::Definition => "sdefinition".len(),
938 ParagraphKind::Paragraph => "sparagraph".len(),
939 ParagraphKind::Proof => "sproof".len(),
940 ParagraphKind::Example => "sexample".len(),
941 ParagraphKind::Assertion => "sassertion".len(),
942 _ => return,
943 };
944 end_range.start.col = end_range.end.col - parname as u32;
945 if symbol.is_some() {
946 cont(end_range, STeXSemanticTokens::DECLARATION);
947 } else {
948 cont(end_range, STeXSemanticTokens::REF_MACRO);
949 }
950 }
951 Self::InlineParagraph {
952 symbol,
953 token_range,
954 parsed_args,
955 children,
956 ..
957 } => {
958 if symbol.is_some() {
959 cont(*token_range, STeXSemanticTokens::DECLARATION);
960 } else {
961 cont(*token_range, STeXSemanticTokens::REF_MACRO);
962 }
963 for e in parsed_args {
964 match e {
965 ParagraphArg::Tp(ParsedKeyValue { key_range, val, .. })
966 | ParagraphArg::Df(ParsedKeyValue { key_range, val, .. })
967 | ParagraphArg::Return(ParsedKeyValue { key_range, val, .. })
968 | ParagraphArg::Argtypes(ParsedKeyValue { key_range, val, .. })
969 | ParagraphArg::Title(ParsedKeyValue { key_range, val, .. }) => {
970 cont(*key_range, STeXSemanticTokens::KEYWORD);
971 for c in val {
972 c.semantic_tokens(cont);
973 }
974 }
975 ParagraphArg::Args(ParsedKeyValue {
976 key_range,
977 val_range,
978 ..
979 }) => {
980 cont(*key_range, STeXSemanticTokens::KEYWORD);
981 cont(*val_range, STeXSemanticTokens::KEYWORD);
982 }
983 ParagraphArg::Name(ParsedKeyValue {
984 key_range,
985 val_range,
986 ..
987 })
988 | ParagraphArg::MacroName(ParsedKeyValue {
989 key_range,
990 val_range,
991 ..
992 }) => {
993 cont(*key_range, STeXSemanticTokens::KEYWORD);
994 cont(*val_range, STeXSemanticTokens::NAME);
995 }
996 ParagraphArg::Style(ParsedKeyValue { key_range, .. })
997 | ParagraphArg::Assoc(ParsedKeyValue { key_range, .. })
998 | ParagraphArg::Role(ParsedKeyValue { key_range, .. })
999 | ParagraphArg::Reorder(ParsedKeyValue { key_range, .. })
1000 | ParagraphArg::Judgment(ParsedKeyValue { key_range, .. })
1001 | ParagraphArg::From(ParsedKeyValue { key_range, .. })
1002 | ParagraphArg::To(ParsedKeyValue { key_range, .. })
1003 | ParagraphArg::Id(ParsedKeyValue { key_range, .. }) => {
1004 cont(*key_range, STeXSemanticTokens::KEYWORD)
1005 }
1006 ParagraphArg::Fors(ParsedKeyValue { key_range, val, .. }) => {
1007 cont(*key_range, STeXSemanticTokens::KEYWORD);
1008 for (_, f) in val {
1009 cont(*f, STeXSemanticTokens::SYMBOL);
1010 }
1011 }
1012 }
1013 }
1014 for c in children {
1015 c.semantic_tokens(cont);
1016 }
1017 }
1018 Self::Symdecl {
1019 main_name_range,
1020 token_range,
1021 parsed_args,
1022 ..
1023 } => {
1024 cont(*token_range, STeXSemanticTokens::DECLARATION);
1025 cont(*main_name_range, STeXSemanticTokens::NAME);
1026
1027 for e in parsed_args {
1028 match e {
1029 SymdeclArg::Tp(ParsedKeyValue { key_range, val, .. })
1030 | SymdeclArg::Df(ParsedKeyValue { key_range, val, .. })
1031 | SymdeclArg::Return(ParsedKeyValue { key_range, val, .. })
1032 | SymdeclArg::Argtypes(ParsedKeyValue { key_range, val, .. }) => {
1033 cont(*key_range, STeXSemanticTokens::KEYWORD);
1034 for c in val {
1035 c.semantic_tokens(cont);
1036 }
1037 }
1038 SymdeclArg::Args(ParsedKeyValue {
1039 key_range,
1040 val_range,
1041 ..
1042 }) => {
1043 cont(*key_range, STeXSemanticTokens::KEYWORD);
1044 cont(*val_range, STeXSemanticTokens::KEYWORD);
1045 }
1046 SymdeclArg::Name(ParsedKeyValue {
1047 key_range,
1048 val_range,
1049 ..
1050 }) => {
1051 cont(*key_range, STeXSemanticTokens::KEYWORD);
1052 cont(*val_range, STeXSemanticTokens::NAME);
1053 }
1054 SymdeclArg::Style(ParsedKeyValue { key_range, .. })
1055 | SymdeclArg::Assoc(ParsedKeyValue { key_range, .. })
1056 | SymdeclArg::Role(ParsedKeyValue { key_range, .. })
1057 | SymdeclArg::Reorder(ParsedKeyValue { key_range, .. }) => {
1058 cont(*key_range, STeXSemanticTokens::KEYWORD)
1059 }
1060 }
1061 }
1062 }
1063 Self::TextSymdecl {
1064 main_name_range,
1065 token_range,
1066 parsed_args,
1067 ..
1068 } => {
1069 cont(*token_range, STeXSemanticTokens::DECLARATION);
1070 cont(*main_name_range, STeXSemanticTokens::NAME);
1071
1072 for e in parsed_args {
1073 match e {
1074 TextSymdeclArg::Tp(ParsedKeyValue { key_range, val, .. })
1075 | TextSymdeclArg::Df(ParsedKeyValue { key_range, val, .. }) => {
1076 cont(*key_range, STeXSemanticTokens::KEYWORD);
1077 for c in val {
1078 c.semantic_tokens(cont);
1079 }
1080 }
1081 TextSymdeclArg::Name(ParsedKeyValue {
1082 key_range,
1083 val_range,
1084 ..
1085 }) => {
1086 cont(*key_range, STeXSemanticTokens::KEYWORD);
1087 cont(*val_range, STeXSemanticTokens::NAME);
1088 }
1089 TextSymdeclArg::Style(ParsedKeyValue { key_range, .. }) => {
1090 cont(*key_range, STeXSemanticTokens::KEYWORD)
1091 }
1092 }
1093 }
1094 }
1095 Self::Symdef {
1096 main_name_range,
1097 token_range,
1098 parsed_args,
1099 ..
1100 } => {
1101 cont(*token_range, STeXSemanticTokens::DECLARATION);
1102 cont(*main_name_range, STeXSemanticTokens::NAME);
1103
1104 for e in parsed_args {
1105 match e {
1106 SymdefArg::Tp(ParsedKeyValue { key_range, val, .. })
1107 | SymdefArg::Df(ParsedKeyValue { key_range, val, .. })
1108 | SymdefArg::Return(ParsedKeyValue { key_range, val, .. })
1109 | SymdefArg::Op(ParsedKeyValue { key_range, val, .. })
1110 | SymdefArg::Argtypes(ParsedKeyValue { key_range, val, .. }) => {
1111 cont(*key_range, STeXSemanticTokens::KEYWORD);
1112 for c in val {
1113 c.semantic_tokens(cont);
1114 }
1115 }
1116 SymdefArg::Args(ParsedKeyValue {
1117 key_range,
1118 val_range,
1119 ..
1120 }) => {
1121 cont(*key_range, STeXSemanticTokens::KEYWORD);
1122 cont(*val_range, STeXSemanticTokens::KEYWORD);
1123 }
1124 SymdefArg::Name(ParsedKeyValue {
1125 key_range,
1126 val_range,
1127 ..
1128 }) => {
1129 cont(*key_range, STeXSemanticTokens::KEYWORD);
1130 cont(*val_range, STeXSemanticTokens::NAME);
1131 }
1132 SymdefArg::Id(v, _) => cont(*v, STeXSemanticTokens::NAME),
1133 SymdefArg::Style(ParsedKeyValue { key_range, .. })
1134 | SymdefArg::Assoc(ParsedKeyValue { key_range, .. })
1135 | SymdefArg::Role(ParsedKeyValue { key_range, .. })
1136 | SymdefArg::Prec(ParsedKeyValue { key_range, .. })
1137 | SymdefArg::Reorder(ParsedKeyValue { key_range, .. }) => {
1138 cont(*key_range, STeXSemanticTokens::KEYWORD)
1139 }
1140 }
1141 }
1142 }
1143 Self::RenameDecl {
1144 token_range,
1145 orig_range,
1146 name_range,
1147 macroname_range,
1148 ..
1149 } => {
1150 cont(*token_range, STeXSemanticTokens::DECLARATION);
1151 cont(*orig_range, STeXSemanticTokens::SYMBOL);
1152 if let Some(n) = name_range {
1153 cont(*n, STeXSemanticTokens::NAME);
1154 }
1155 cont(*macroname_range, STeXSemanticTokens::NAME);
1156 }
1157 Self::Assign {
1158 token_range,
1159 orig_range,
1160 ..
1161 } => {
1162 cont(*token_range, STeXSemanticTokens::DECLARATION);
1163 cont(*orig_range, STeXSemanticTokens::SYMBOL);
1164 }
1165 Self::Svar { full_range, .. } => cont(*full_range, STeXSemanticTokens::VARIABLE),
1166 Self::Vardef {
1167 main_name_range,
1168 token_range,
1169 parsed_args,
1170 ..
1171 }
1172 | Self::Varseq {
1173 main_name_range,
1174 token_range,
1175 parsed_args,
1176 ..
1177 } => {
1178 cont(*token_range, STeXSemanticTokens::LOCAL);
1179 cont(*main_name_range, STeXSemanticTokens::NAME);
1180
1181 for e in parsed_args {
1182 match e {
1183 VardefArg::Tp(ParsedKeyValue { key_range, val, .. })
1184 | VardefArg::Df(ParsedKeyValue { key_range, val, .. })
1185 | VardefArg::Return(ParsedKeyValue { key_range, val, .. })
1186 | VardefArg::Op(ParsedKeyValue { key_range, val, .. })
1187 | VardefArg::Argtypes(ParsedKeyValue { key_range, val, .. }) => {
1188 cont(*key_range, STeXSemanticTokens::KEYWORD);
1189 for c in val {
1190 c.semantic_tokens(cont);
1191 }
1192 }
1193 VardefArg::Args(ParsedKeyValue {
1194 key_range,
1195 val_range,
1196 ..
1197 }) => {
1198 cont(*key_range, STeXSemanticTokens::KEYWORD);
1199 cont(*val_range, STeXSemanticTokens::KEYWORD);
1200 }
1201 VardefArg::Name(ParsedKeyValue {
1202 key_range,
1203 val_range,
1204 ..
1205 }) => {
1206 cont(*key_range, STeXSemanticTokens::KEYWORD);
1207 cont(*val_range, STeXSemanticTokens::NAME);
1208 }
1209 VardefArg::Id(v, _) => cont(*v, STeXSemanticTokens::NAME),
1210 VardefArg::Style(ParsedKeyValue { key_range, .. })
1211 | VardefArg::Assoc(ParsedKeyValue { key_range, .. })
1212 | VardefArg::Role(ParsedKeyValue { key_range, .. })
1213 | VardefArg::Prec(ParsedKeyValue { key_range, .. })
1214 | VardefArg::Bind(ParsedKeyValue { key_range, .. })
1215 | VardefArg::Reorder(ParsedKeyValue { key_range, .. }) => {
1216 cont(*key_range, STeXSemanticTokens::KEYWORD)
1217 }
1218 }
1219 }
1220 }
1221 Self::Notation {
1222 token_range,
1223 name_range,
1224 notation_args,
1225 ..
1226 } => {
1227 cont(*token_range, STeXSemanticTokens::DECLARATION);
1228 cont(*name_range, STeXSemanticTokens::SYMBOL);
1229 for e in notation_args {
1230 match e {
1231 NotationArg::Op(ParsedKeyValue { key_range, val, .. }) => {
1232 cont(*key_range, STeXSemanticTokens::KEYWORD);
1233 for c in val {
1234 c.semantic_tokens(cont);
1235 }
1236 }
1237 NotationArg::Id(v, _) => cont(*v, STeXSemanticTokens::NAME),
1238 NotationArg::Prec(ParsedKeyValue { key_range, .. }) => {
1239 cont(*key_range, STeXSemanticTokens::KEYWORD)
1240 }
1241 }
1242 }
1243 }
1244 Self::SymName {
1245 token_range,
1246 name_range,
1247 ..
1248 }
1249 | Self::Symref {
1250 token_range,
1251 name_range,
1252 ..
1253 }
1254 | Self::Symuse {
1255 token_range,
1256 name_range,
1257 ..
1258 } => {
1259 cont(*token_range, STeXSemanticTokens::REF_MACRO);
1260 cont(*name_range, STeXSemanticTokens::SYMBOL);
1261 }
1262 Self::Precondition {
1263 token_range,
1264 dim_range,
1265 symbol_range,
1266 ..
1267 }
1268 | Self::Objective {
1269 token_range,
1270 dim_range,
1271 symbol_range,
1272 ..
1273 } => {
1274 cont(*token_range, STeXSemanticTokens::REF_MACRO);
1275 cont(*dim_range, STeXSemanticTokens::KEYWORD);
1276 cont(*symbol_range, STeXSemanticTokens::SYMBOL);
1277 }
1278 Self::Definiens {
1279 token_range,
1280 name_range,
1281 ..
1282 } => {
1283 cont(*token_range, STeXSemanticTokens::REF_MACRO);
1284 if let Some(r) = name_range {
1285 cont(*r, STeXSemanticTokens::SYMBOL);
1286 }
1287 }
1288 Self::SnifySuggestion { .. } => (),
1289 }
1290 }
1291
1292 fn hover(
1293 &self,
1294 top_archive: Option<&ArchiveUri>,
1295 pos: LSPLineCol,
1296 ) -> Option<either_of::Either<lsp::Hover, (lsp::Range, SymbolReference<LSPLineCol>)>> {
1297 fn uriname(pre: &str, d: &impl std::fmt::Display) -> String {
1298 format!("{pre}<sup>`{d}`</sup>")
1299 }
1300 match self {
1302 Self::SymName {
1303 uri,
1304 name_range: range,
1305 ..
1306 }
1307 | Self::Symref {
1308 uri,
1309 name_range: range,
1310 ..
1311 }
1312 | Self::Notation {
1313 uri,
1314 name_range: range,
1315 ..
1316 }
1317 | Self::Symuse {
1318 uri,
1319 name_range: range,
1320 ..
1321 }
1322 | Self::Precondition {
1323 uri,
1324 symbol_range: range,
1325 ..
1326 }
1327 | Self::Objective {
1328 uri,
1329 symbol_range: range,
1330 ..
1331 }
1332 | Self::Definiens {
1333 uri,
1334 name_range: Some(range),
1335 ..
1336 } => Some(
1337 either_of::Either::Right((
1338 StringRange::into_range(*range),
1339 uri.first().unwrap_or_else(|| unreachable!()).clone(),
1340 )), ),
1348 Self::SemanticMacro {
1349 uri,
1350 full_range: range,
1351 ..
1352 }
1353 | Self::ConservativeExt {
1354 uri,
1355 ext_range: range,
1356 ..
1357 }
1358 | Self::UseStructure {
1359 structure: uri,
1360 structure_range: range,
1361 ..
1362 }
1363 | Self::MorphismEnv {
1364 domain: ModuleOrStruct::Struct(uri),
1365 domain_range: range,
1366 ..
1367 }
1368 | Self::RenameDecl {
1369 uri,
1370 orig_range: range,
1371 ..
1372 }
1373 | Self::Assign {
1374 uri,
1375 orig_range: range,
1376 ..
1377 } => Some(
1378 either_of::Either::Right((StringRange::into_range(*range), uri.clone())), ),
1386 Self::InlineMorphism {
1387 domain_range,
1388 domain,
1389 assignments,
1390 ..
1391 } => {
1392 if domain_range.contains(pos) {
1393 let uri = match domain {
1394 ModuleOrStruct::Struct(sym) => sym,
1395 _ => return None,
1396 };
1397 return Some(
1398 either_of::Either::Right((
1399 StringRange::into_range(*domain_range),
1400 uri.clone(),
1401 )), );
1409 }
1410 for a in assignments {
1411 if a.symbol_range.contains(pos) {
1412 return Some(
1413 either_of::Either::Right((
1414 StringRange::into_range(a.symbol_range),
1415 a.symbol.clone(),
1416 )), );
1424 }
1425 }
1426 None
1427 }
1428 Self::Svar {
1429 full_range, name, ..
1430 }
1431 | Self::VariableMacro {
1432 name, full_range, ..
1433 } => Some(either_of::Either::Left(lsp::Hover {
1434 range: Some(StringRange::into_range(*full_range)),
1435 contents: lsp::HoverContents::Markup(lsp::MarkupContent {
1436 kind: lsp::MarkupKind::Markdown,
1437 value: uriname("Variable ", name),
1438 }),
1439 })),
1440 Self::MathStructure { extends, .. } => extends.iter().find_map(|(s, r)| {
1441 if r.contains(pos) {
1442 Some(
1443 either_of::Either::Right((StringRange::into_range(*r), s.clone())), )
1451 } else {
1452 None
1453 }
1454 }),
1455 Self::Paragraph { parsed_args, .. } | Self::InlineParagraph { parsed_args, .. } => {
1456 for p in parsed_args {
1457 if let ParagraphArg::Fors(ParsedKeyValue { val_range, val, .. }) = p {
1458 if val_range.contains(pos) {
1459 for (s, r) in val {
1460 if r.contains(pos) {
1461 return Some(
1462 either_of::Either::Right((
1463 StringRange::into_range(*r),
1464 s.first().unwrap_or_else(|| unreachable!()).clone(),
1465 )), );
1476 }
1477 }
1478 }
1479 return None;
1480 }
1481 }
1482 None
1483 }
1484 Self::MHGraphics {
1485 filepath,
1486 archive,
1487 full_range,
1488 ..
1489 } => {
1490 let Some(a) = archive.as_ref().map_or_else(
1491 || top_archive.map(UriWithArchive::archive_id),
1492 |(a, _)| Some(a),
1493 ) else {
1494 return None;
1495 };
1496 let Some(uri) = uri_from_archive_relpath(a, &filepath.0) else {
1497 return None;
1498 };
1499 Some(either_of::Either::Left(lsp::Hover {
1500 range: Some(StringRange::into_range(*full_range)),
1501 contents: lsp::HoverContents::Markup(lsp::MarkupContent {
1502 kind: lsp::MarkupKind::Markdown,
1503 value: format!(""),
1504 }),
1505 }))
1506 }
1507 Self::Module {
1508 uri,
1509 name_range,
1510 full_range,
1511 ..
1512 } => {
1513 let range = StringRange {
1514 start: full_range.start,
1515 end: name_range.end,
1516 };
1517 Some(either_of::Either::Left(lsp::Hover {
1518 range: Some(StringRange::into_range(range)),
1519 contents: lsp::HoverContents::Markup(lsp::MarkupContent {
1520 kind: lsp::MarkupKind::Markdown,
1521 value: uri.to_string(),
1522 }),
1523 }))
1524 }
1525 Self::ImportModule { .. }
1526 | Self::UseModule { .. }
1527 | Self::SetMetatheory { .. }
1528 | Self::Inputref { .. }
1529 | Self::IncludeProblem { .. }
1530 | Self::MHInput { .. }
1531 | Self::Symdecl { .. }
1532 | Self::Symdef { .. }
1533 | Self::Vardef { .. }
1534 | Self::Varseq { .. }
1535 | Self::Definiens { .. }
1536 | Self::TextSymdecl { .. }
1537 | Self::Problem { .. }
1538 | Self::Defnotation { .. }
1539 | Self::MorphismEnv { .. }
1540 | Self::SnifySuggestion { .. }
1541 | Self::SRef { .. } => None,
1542 }
1543 }
1544 fn inlay_hint(&self) -> Option<lsp::InlayHint> {
1545 match self {
1546 Self::SymName {
1547 uri,
1548 full_range,
1549 mode: mod_,
1550 ..
1551 } => {
1552 let name = uri
1553 .first()
1554 .unwrap_or_else(|| unreachable!())
1555 .uri
1556 .name()
1557 .last();
1558 let name = format!("={}", mod_.apply(name));
1559 Some(lsp::InlayHint {
1560 position: StringRange::into_range(*full_range).end,
1561 label: lsp::InlayHintLabel::String(name),
1562 kind: Some(lsp::InlayHintKind::PARAMETER),
1563 text_edits: None,
1564 tooltip: None,
1565 padding_left: None,
1566 padding_right: None,
1567 data: None,
1568 })
1569 }
1570 Self::Definiens {
1571 uri,
1572 name_range: None,
1573 full_range,
1574 ..
1575 } => Some(lsp::InlayHint {
1576 position: StringRange::into_range(*full_range).end,
1577 label: lsp::InlayHintLabel::String(format!(
1578 "[{}]",
1579 uri.first().unwrap_or_else(|| unreachable!()).uri.name()
1580 )),
1581 kind: Some(lsp::InlayHintKind::PARAMETER),
1582 text_edits: None,
1583 tooltip: None,
1584 padding_left: None,
1585 padding_right: None,
1586 data: None,
1587 }),
1588 _ => None,
1589 }
1590 }
1591 fn code_action(&self, pos: LSPLineCol, url: &lsp::Url) -> lsp::CodeActionResponse {
1592 fn from_syms(
1593 url: &lsp::Url,
1594 v: &[SymbolReference<LSPLineCol>],
1595 r: StringRange<LSPLineCol>,
1596 ) -> lsp::CodeActionResponse {
1597 use std::fmt::Write;
1598 let all_strs: SmallVec<_, 2> = v
1599 .iter()
1600 .map(|u| {
1601 let mut ret = u.uri.archive_id().to_string();
1602 if let Some(p) = u.uri.path() {
1603 ret.push('/');
1604 ret.push_str(p.as_ref());
1605 }
1606 let _ = write!(ret, "?{}?{}", u.uri.module_name(), u.uri.name());
1607 ret
1608 })
1609 .collect();
1610 v.iter()
1611 .map(|u| {
1612 let disam = disamb(&u.uri, &all_strs);
1613 let mut edits = std::collections::HashMap::default();
1614 edits.insert(
1615 url.clone(),
1616 vec![lsp::TextEdit {
1617 range: StringRange::into_range(r),
1618 new_text: disam.clone(),
1619 }],
1620 );
1621 lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction {
1622 title: disam,
1623 kind: Some(lsp::CodeActionKind::QUICKFIX),
1624 diagnostics: None,
1625 edit: Some(lsp::WorkspaceEdit {
1626 document_changes: None,
1627 changes: Some(edits),
1628 change_annotations: None,
1629 }),
1630 command: None,
1631 is_preferred: None,
1632 disabled: None,
1633 data: None,
1634 })
1635 })
1636 .collect()
1637 }
1638 match self {
1639 Self::Notation {
1640 uri, name_range, ..
1641 }
1642 | Self::SymName {
1643 uri, name_range, ..
1644 }
1645 | Self::Symuse {
1646 uri, name_range, ..
1647 }
1648 | Self::Symref {
1649 uri, name_range, ..
1650 }
1651 | Self::Precondition {
1652 uri,
1653 symbol_range: name_range,
1654 ..
1655 }
1656 | Self::Objective {
1657 uri,
1658 symbol_range: name_range,
1659 ..
1660 }
1661 | Self::Definiens {
1662 uri,
1663 name_range: Some(name_range),
1664 ..
1665 } => {
1666 if !name_range.contains(pos) {
1667 return Vec::new();
1668 }
1669 if uri.len() > 1 {
1670 from_syms(url, uri, *name_range)
1671 } else {
1672 Vec::new()
1673 }
1674 }
1675
1676 Self::Paragraph { parsed_args, .. } | Self::InlineParagraph { parsed_args, .. } => {
1677 let fors = parsed_args.iter().find_map(|a| {
1678 if let ParagraphArg::Fors(ls) = a {
1679 Some(ls)
1680 } else {
1681 None
1682 }
1683 });
1684 if let Some(fors) = fors {
1685 for (s, r) in &fors.val {
1686 if !r.contains(pos) {
1687 continue;
1688 }
1689 if s.len() > 1 {
1690 return from_syms(url, s, *r);
1691 }
1692 return Vec::new();
1693 }
1694 }
1695 Vec::new()
1696 }
1697 Self::SnifySuggestion { range, symbols } => {
1698 if range.contains(pos) {
1699 let mut ret: Vec<lsp::CodeActionOrCommand> = symbols
1700 .iter()
1701 .map(|(s, needs_usemodule)| {
1702 lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction {
1703 title: s.to_string(),
1704 kind: Some(lsp::CodeActionKind::QUICKFIX), diagnostics: None,
1706 edit: None,
1707 command: Some(lsp::Command {
1708 title: "insert".to_string(),
1709 command: "snify/annotate".to_string(),
1710 arguments: Some(vec![
1711 s.to_string().into(),
1712 (*needs_usemodule).into(),
1713 url.to_string().into(),
1714 ::serde_json::to_value(*range).expect("wut"),
1715 ]),
1716 }),
1717 is_preferred: None,
1718 disabled: None,
1719 data: None,
1720 })
1721 })
1722 .collect();
1723 ret.push(lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction {
1724 title: "(ignore)".to_string(),
1725 kind: Some(lsp::CodeActionKind::QUICKFIX), diagnostics: None,
1727 edit: None,
1728 command: Some(lsp::Command {
1729 title: "insert".to_string(),
1730 command: "snify/annotate".to_string(),
1731 arguments: Some(vec![
1732 String::new().into(),
1733 false.into(),
1734 url.to_string().into(),
1735 ::serde_json::to_value(*range).expect("wut"),
1736 ]),
1737 }),
1738 is_preferred: None,
1739 disabled: None,
1740 data: None,
1741 }));
1742 ret
1743 } else {
1744 Vec::new()
1745 }
1746 }
1747 Self::Problem { .. }
1748 | Self::Module { .. }
1749 | Self::MathStructure { .. }
1750 | Self::ConservativeExt { .. }
1751 | Self::MorphismEnv { .. }
1752 | Self::InlineMorphism { .. }
1753 | Self::SemanticMacro { .. }
1754 | Self::VariableMacro { .. }
1755 | Self::Svar { .. }
1756 | Self::ImportModule { .. }
1757 | Self::UseModule { .. }
1758 | Self::UseStructure { .. }
1759 | Self::SetMetatheory { .. }
1760 | Self::Inputref { .. }
1761 | Self::IncludeProblem { .. }
1762 | Self::MHGraphics { .. }
1763 | Self::MHInput { .. }
1764 | Self::Symdecl { .. }
1765 | Self::TextSymdecl { .. }
1766 | Self::RenameDecl { .. }
1767 | Self::Symdef { .. }
1768 | Self::Vardef { .. }
1769 | Self::Varseq { .. }
1770 | Self::Defnotation { .. }
1771 | Self::Definiens { .. }
1772 | Self::Assign { .. }
1773 | Self::SRef { .. } => Vec::new(),
1774 }
1775 }
1776
1777 fn goto_definition(
1778 &self,
1779 in_doc: &UrlOrFile,
1780 pos: LSPLineCol,
1781 ) -> Option<lsp::GotoDefinitionResponse> {
1782 macro_rules! here {
1783 ($r:expr) => {
1784 Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
1785 uri: in_doc.clone().into(),
1786 range: StringRange::into_range($r),
1787 }))
1788 };
1789 }
1790 match self {
1791 Self::Module { name_range, .. } => {
1792 if !name_range.contains(pos) {
1793 return None;
1794 };
1795 here!(*name_range)
1796 }
1797 Self::MathStructure {
1798 extends,
1799 name_range,
1800 opts,
1801 ..
1802 } => {
1803 if name_range.contains(pos) {
1804 return here!(*name_range);
1805 }
1806 for o in opts {
1807 if let MathStructureArg::Name(range, _) = o {
1808 if range.contains(pos) {
1809 return here!(*range);
1810 }
1811 }
1812 }
1813 extends.iter().find_map(|(uri, r)| {
1814 if r.contains(pos) {
1815 let Some(p) = &uri.filepath else { return None };
1816 let Ok(url) = lsp::Url::from_file_path(p) else {
1817 return None;
1818 };
1819 Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
1821 uri: url,
1822 range: StringRange::into_range(uri.range),
1823 }))
1824 } else {
1825 None
1826 }
1827 })
1828 }
1829 Self::MorphismEnv {
1830 domain_range,
1831 name_range,
1832 domain,
1833 ..
1834 } => {
1835 if name_range.contains(pos) {
1836 return here!(*name_range);
1837 }
1838 if domain_range.contains(pos) {
1839 let Some((p, range)) = (match domain {
1840 ModuleOrStruct::Module(uri) => {
1841 uri.full_path.as_ref().map(|r| (r, StringRange::default()))
1842 }
1843 ModuleOrStruct::Struct(uri) => {
1844 uri.filepath.as_ref().map(|r| (r, uri.range))
1845 }
1846 }) else {
1847 return None;
1848 };
1849 let Ok(url) = lsp::Url::from_file_path(p) else {
1850 return None;
1851 };
1852 return Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
1853 uri: url,
1854 range: StringRange::into_range(range),
1855 }));
1856 } else {
1857 None
1858 }
1859 }
1860 Self::InlineMorphism {
1861 domain_range,
1862 domain,
1863 assignments,
1864 name_range,
1865 ..
1866 } => {
1867 if name_range.contains(pos) {
1868 return here!(*name_range);
1869 }
1870 if domain_range.contains(pos) {
1871 let Some((p, range)) = (match domain {
1872 ModuleOrStruct::Module(uri) => {
1873 uri.full_path.as_ref().map(|r| (r, StringRange::default()))
1874 }
1875 ModuleOrStruct::Struct(uri) => {
1876 uri.filepath.as_ref().map(|r| (r, uri.range))
1877 }
1878 }) else {
1879 return None;
1880 };
1881 let Ok(url) = lsp::Url::from_file_path(p) else {
1882 return None;
1883 };
1884 return Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
1885 uri: url,
1886 range: StringRange::into_range(range),
1887 }));
1888 }
1889 for a in assignments {
1890 if a.symbol_range.contains(pos) {
1891 let Some(p) = &a.symbol.filepath else {
1892 return None;
1893 };
1894 let Ok(url) = lsp::Url::from_file_path(p) else {
1895 return None;
1896 };
1897 return Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
1898 uri: url,
1899 range: StringRange::into_range(a.symbol_range),
1900 }));
1901 }
1902 if let Some((_, InlineMorphAssKind::Rename(_, _, r))) = &a.first {
1903 if r.contains(pos) {
1904 return here!(*r);
1905 }
1906 }
1907 if let Some((_, InlineMorphAssKind::Rename(_, _, r))) = &a.second {
1908 if r.contains(pos) {
1909 return here!(*r);
1910 }
1911 }
1912 }
1913 None
1914 }
1915 Self::Paragraph { parsed_args, .. } | Self::InlineParagraph { parsed_args, .. } => {
1916 for p in parsed_args {
1917 match p {
1918 ParagraphArg::Fors(ParsedKeyValue { val_range, val, .. }) => {
1919 if val_range.contains(pos) {
1920 for (s, r) in val {
1921 if r.contains(pos) {
1922 let Some(p) =
1923 &s.first().unwrap_or_else(|| unreachable!()).filepath
1924 else {
1925 return None;
1926 };
1927 let Ok(url) = lsp::Url::from_file_path(p) else {
1928 return None;
1929 };
1930 return Some(lsp::GotoDefinitionResponse::Scalar(
1932 lsp::Location {
1933 uri: url,
1934 range: StringRange::into_range(
1935 s.first()
1936 .unwrap_or_else(|| unreachable!())
1937 .range,
1938 ),
1939 },
1940 ));
1941 }
1942 }
1943 }
1944 return None;
1945 }
1946 ParagraphArg::Name(ParsedKeyValue { val_range, .. })
1947 | ParagraphArg::MacroName(ParsedKeyValue { val_range, .. })
1948 if val_range.contains(pos) =>
1949 {
1950 return here!(*val_range);
1951 }
1952 _ => (),
1953 }
1954 }
1955 None
1956 }
1957 Self::Symdecl {
1958 main_name_range,
1959 parsed_args,
1960 ..
1961 } => {
1962 if main_name_range.contains(pos) {
1963 return here!(*main_name_range);
1964 }
1965 for a in parsed_args {
1966 if let SymdeclArg::Name(ParsedKeyValue { val_range, .. }) = a {
1967 if val_range.contains(pos) {
1968 return here!(*val_range);
1969 }
1970 }
1971 }
1972 None
1973 }
1974 Self::TextSymdecl {
1975 main_name_range,
1976 parsed_args,
1977 ..
1978 } => {
1979 if main_name_range.contains(pos) {
1980 return here!(*main_name_range);
1981 }
1982 for a in parsed_args {
1983 if let TextSymdeclArg::Name(ParsedKeyValue { val_range, .. }) = a {
1984 if val_range.contains(pos) {
1985 return here!(*val_range);
1986 }
1987 }
1988 }
1989 None
1990 }
1991 Self::Symdef {
1992 main_name_range,
1993 parsed_args,
1994 ..
1995 } => {
1996 if main_name_range.contains(pos) {
1997 return here!(*main_name_range);
1998 }
1999 for a in parsed_args {
2000 if let SymdefArg::Name(ParsedKeyValue { val_range, .. }) = a {
2001 if val_range.contains(pos) {
2002 return here!(*val_range);
2003 }
2004 }
2005 }
2006 None
2007 }
2008 Self::RenameDecl {
2009 uri,
2010 orig_range,
2011 name_range,
2012 macroname_range,
2013 ..
2014 } => {
2015 if let Some(name_range) = name_range {
2016 if name_range.contains(pos) {
2017 return here!(*name_range);
2018 }
2019 }
2020 if macroname_range.contains(pos) {
2021 return here!(*macroname_range);
2022 }
2023 if !orig_range.contains(pos) {
2024 return None;
2025 };
2026 let Some(p) = &uri.filepath else { return None };
2027 let Ok(url) = lsp::Url::from_file_path(p) else {
2028 return None;
2029 };
2030 Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
2032 uri: url,
2033 range: StringRange::into_range(uri.range),
2034 }))
2035 }
2036 Self::Vardef {
2037 main_name_range,
2038 parsed_args,
2039 ..
2040 }
2041 | Self::Varseq {
2042 main_name_range,
2043 parsed_args,
2044 ..
2045 } => {
2046 if main_name_range.contains(pos) {
2047 return here!(*main_name_range);
2048 }
2049 for a in parsed_args {
2050 if let VardefArg::Name(ParsedKeyValue { val_range, .. }) = a {
2051 if val_range.contains(pos) {
2052 return here!(*val_range);
2053 }
2054 }
2055 }
2056 None
2057 }
2058
2059 Self::ImportModule {
2060 module,
2061 archive_range,
2062 path_range,
2063 ..
2064 }
2065 | Self::UseModule {
2066 module,
2067 archive_range,
2068 path_range,
2069 ..
2070 }
2071 | Self::SetMetatheory {
2072 archive_range,
2073 path_range,
2074 module,
2075 ..
2076 } => {
2077 let range = archive_range.map_or(*path_range, |a| StringRange {
2078 start: a.start,
2079 end: path_range.end,
2080 });
2081 if !range.contains(pos) {
2082 return None;
2083 };
2084 let Some(p) = module.full_path.as_ref() else {
2085 return None;
2086 };
2087 let Ok(uri) = lsp::Url::from_file_path(p) else {
2088 return None;
2089 };
2090 Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
2091 uri,
2092 range: lsp::Range::default(),
2093 }))
2094 }
2095 Self::ConservativeExt { ext_range, uri, .. } => {
2096 if !ext_range.contains(pos) {
2097 return None;
2098 };
2099 let Some(p) = &uri.filepath else { return None };
2100 let Ok(url) = lsp::Url::from_file_path(p) else {
2101 return None;
2102 };
2103 Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
2105 uri: url,
2106 range: StringRange::into_range(uri.range),
2107 }))
2108 }
2109 Self::SymName {
2110 uri,
2111 name_range: range,
2112 ..
2113 }
2114 | Self::Symref {
2115 uri,
2116 name_range: range,
2117 ..
2118 }
2119 | Self::Notation {
2120 uri,
2121 name_range: range,
2122 ..
2123 }
2124 | Self::Symuse {
2125 uri,
2126 name_range: range,
2127 ..
2128 }
2129 | Self::Precondition {
2130 uri,
2131 symbol_range: range,
2132 ..
2133 }
2134 | Self::Objective {
2135 uri,
2136 symbol_range: range,
2137 ..
2138 }
2139 | Self::Definiens {
2140 uri,
2141 name_range: Some(range),
2142 ..
2143 } => {
2144 if !range.contains(pos) {
2145 return None;
2146 };
2147 let Some(p) = &uri.first().unwrap_or_else(|| unreachable!()).filepath else {
2148 return None;
2149 };
2150 let Ok(url) = lsp::Url::from_file_path(p) else {
2151 return None;
2152 };
2153 Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
2155 uri: url,
2156 range: StringRange::into_range(
2157 uri.first().unwrap_or_else(|| unreachable!()).range,
2158 ),
2159 }))
2160 }
2161 Self::SemanticMacro {
2162 uri,
2163 token_range: range,
2164 ..
2165 }
2166 | Self::UseStructure {
2167 structure: uri,
2168 structure_range: range,
2169 ..
2170 }
2171 | Self::Assign {
2172 uri,
2173 orig_range: range,
2174 ..
2175 } => {
2176 if !range.contains(pos) {
2177 return None;
2178 };
2179 let Some(p) = &uri.filepath else { return None };
2180 let Ok(url) = lsp::Url::from_file_path(p) else {
2181 return None;
2182 };
2183 Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
2185 uri: url,
2186 range: StringRange::into_range(uri.range),
2187 }))
2188 }
2189 Self::VariableMacro {
2190 orig, full_range, ..
2191 } => {
2192 if !full_range.contains(pos) {
2193 return None;
2194 };
2195 Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
2196 uri: in_doc.clone().into(),
2197 range: StringRange::into_range(*orig),
2198 }))
2199 }
2200 Self::Svar { .. }
2201 | Self::Inputref { .. }
2202 | Self::IncludeProblem { .. }
2203 | Self::MHGraphics { .. }
2204 | Self::MHInput { .. }
2205 | Self::Problem { .. }
2206 | Self::Definiens { .. }
2207 | Self::Defnotation { .. }
2208 | Self::SnifySuggestion { .. }
2209 | Self::SRef { .. } => None,
2210 }
2211 }
2212}
2213
2214impl LSPState {
2215 #[must_use]
2216 pub fn get_diagnostics(
2217 &self,
2218 uri: &UrlOrFile,
2219 progress: Option<ProgressCallbackClient>,
2220 ) -> Option<impl std::future::Future<Output = lsp::DocumentDiagnosticReportResult> + use<>>
2221 {
2222 fn default() -> lsp::DocumentDiagnosticReportResult {
2223 lsp::DocumentDiagnosticReportResult::Report(lsp::DocumentDiagnosticReport::Full(
2224 lsp::RelatedFullDocumentDiagnosticReport::default(),
2225 ))
2226 }
2227 let d = self.get(uri)?;
2228 let slf = self.clone();
2229 Some(async move {
2230 d.with_annots(slf, false, |data| {
2231 let diags = &data.diagnostics;
2232 let r = lsp::DocumentDiagnosticReportResult::Report(
2233 lsp::DocumentDiagnosticReport::Full(lsp::RelatedFullDocumentDiagnosticReport {
2234 related_documents: None,
2235 full_document_diagnostic_report: lsp::FullDocumentDiagnosticReport {
2236 result_id: None,
2237 items: diags.iter().map(to_diagnostic).collect(),
2238 },
2239 }),
2240 );
2241 tracing::trace!("diagnostics: {:?}", r);
2242 if let Some(p) = progress {
2243 p.finish()
2244 }
2245 r
2246 })
2247 .await
2248 .unwrap_or_else(default)
2249 })
2250 }
2251
2252 #[must_use]
2253 pub fn get_symbols(
2254 &self,
2255 uri: &UrlOrFile,
2256 progress: Option<ProgressCallbackClient>,
2257 ) -> Option<impl std::future::Future<Output = Option<lsp::DocumentSymbolResponse>> + use<>>
2258 {
2259 #[allow(deprecated)]
2260 fn to_symbols(v: &[STeXAnnot]) -> Vec<lsp::DocumentSymbol> {
2261 let mut curr = v.iter();
2262 let mut ret = Vec::new();
2263 let mut stack = Vec::new();
2264 loop {
2266 if let Some(e) = curr.next() {
2267 if let Some((mut symbol, children)) = e.as_symbol() {
2268 if children.is_empty() {
2269 ret.push(symbol)
2270 } else {
2271 let old = std::mem::replace(&mut curr, children.iter());
2272 symbol.children = Some(std::mem::take(&mut ret));
2273 stack.push((old, symbol));
2274 }
2275 }
2276 } else if let Some((i, mut s)) = stack.pop() {
2277 curr = i;
2278 std::mem::swap(
2279 &mut ret,
2280 s.children.as_mut().unwrap_or_else(|| unreachable!()),
2281 );
2282 ret.push(s);
2283 } else {
2284 break;
2285 }
2286 }
2287 ret
2289 }
2290
2291 let d = self.get(uri)?;
2292 let slf = self.clone();
2293 Some(d.with_annots(slf, false, |data| {
2294 let r = lsp::DocumentSymbolResponse::Nested(to_symbols(&data.annotations));
2295 tracing::trace!("document symbols: {:?}", r);
2296 if let Some(p) = progress {
2297 p.finish()
2298 }
2299 r
2300 }))
2301 }
2302
2303 #[must_use]
2304 pub fn get_links(
2305 &self,
2306 uri: &UrlOrFile,
2307 progress: Option<ProgressCallbackClient>,
2308 ) -> Option<impl std::future::Future<Output = Option<Vec<lsp::DocumentLink>>> + use<>> {
2309 let d = self.get(uri)?;
2310 let da = d.archive().cloned();
2311 let slf = self.clone();
2312 Some(d.with_annots(slf, false, move |data| {
2313 let mut ret = Vec::new();
2314 let iter: AnnotIter = data.annotations.iter().into();
2315 for e in <AnnotIter as TreeChildIter<STeXAnnot>>::dfs(iter) {
2316 e.links(da.as_ref(), |l| ret.push(l));
2317 }
2318 if let Some(p) = progress {
2320 p.finish()
2321 }
2322 ret
2323 }))
2324 }
2325
2326 pub fn prepare_module_hierarchy(
2327 &self,
2328 uri: UrlOrFile,
2329 _: Option<ProgressCallbackClient>,
2330 ) -> Option<impl std::future::Future<Output = Option<Vec<lsp::CallHierarchyItem>>> + use<>>
2331 {
2332 let d = self.get(&uri)?;
2333 let url: lsp::Url = uri.into();
2334 d.document_uri().map(|doc| {
2335 std::future::ready(Some(vec![lsp::CallHierarchyItem {
2336 name: format!("{}.{}", doc.document_name(), doc.language()),
2337 kind: lsp::SymbolKind::FILE,
2338 tags: None,
2339 detail: None,
2340 uri: url.clone(),
2341 range: lsp::Range::default(), selection_range: lsp::Range::default(),
2343 data: Some(doc.to_string().into()),
2344 }]))
2345 })
2346 }
2347
2348 pub fn module_hierarchy_imports(
2349 &self,
2350 url: lsp::Url,
2351 kind: lsp::SymbolKind,
2352 uri: Uri,
2353 _: Option<ProgressCallbackClient>,
2354 ) -> Option<
2355 impl std::future::Future<Output = Option<Vec<lsp::CallHierarchyIncomingCall>>> + use<>,
2356 > {
2357 Some(std::future::ready({
2358 let url = url.into();
2359 let d = self.documents.read().get(&url).cloned()?;
2360 let annots = match d {
2361 DocData::Doc(d) => d.annotations,
2362 DocData::Data(d, _) => d,
2363 };
2364 let data = annots.lock();
2365 let mut rets = Vec::new();
2366 let (chs, usemods) = if kind == lsp::SymbolKind::FILE {
2367 (&*data.annotations, true)
2368 } else {
2369 let mut iter: AnnotIter = data.annotations.iter().into();
2370 (
2371 iter.find_map(|e| match e {
2372 STeXAnnot::Module {
2373 uri: muri,
2374 children,
2375 ..
2376 } if matches!(&uri,Uri::Module(u) if u == muri) => Some(&**children),
2377 STeXAnnot::MathStructure {
2378 uri: suri,
2379 children,
2380 extends,
2381 ..
2382 } if matches!(&uri,Uri::Symbol(u) if u == &suri.uri) => {
2383 for (sym, range) in extends {
2384 if let Some(p) = sym.filepath.as_ref() {
2385 let Ok(url) = lsp::Url::from_file_path(p) else {
2386 continue;
2387 };
2388 rets.push(lsp::CallHierarchyIncomingCall {
2389 from_ranges: vec![IsLSPRange::into_range(*range)],
2390 from: lsp::CallHierarchyItem {
2391 name: sym.uri.name().to_string(),
2392 detail: Some(
2393 sym.uri
2394 .to_string()
2395 .split_once("a=")
2396 .unwrap_or_else(|| unreachable!())
2397 .1
2398 .to_string(),
2399 ),
2400 kind: lsp::SymbolKind::STRUCT,
2401 tags: None,
2402 uri: url,
2403 range: lsp::Range::default(),
2404 selection_range: lsp::Range::default(),
2405 data: Some(sym.uri.to_string().into()),
2406 },
2407 });
2408 }
2409 }
2410 Some(&**children)
2411 }
2412 _ => None,
2413 })?,
2414 false,
2415 )
2416 };
2417 let iter: AnnotIter = chs.iter().into();
2418 for e in <AnnotIter as TreeChildIter<STeXAnnot>>::dfs(iter) {
2419 match e {
2420 STeXAnnot::ImportModule {
2421 module, full_range, ..
2422 } if !usemods => {
2423 let Some(p) = module.full_path.as_ref() else {
2424 continue;
2425 };
2426 let Ok(url) = lsp::Url::from_file_path(p) else {
2427 continue;
2428 };
2429 rets.push(lsp::CallHierarchyIncomingCall {
2430 from_ranges: vec![lsp::Range::default()],
2431 from: lsp::CallHierarchyItem {
2432 detail: Some(
2433 module
2434 .uri
2435 .to_string()
2436 .split_once("a=")
2437 .unwrap_or_else(|| unreachable!())
2438 .1
2439 .to_string(),
2440 ),
2441 name: module.uri.module_name().to_string(),
2442 kind: lsp::SymbolKind::CLASS,
2443 tags: None,
2444 uri: url,
2445 range: IsLSPRange::into_range(*full_range),
2446 selection_range: IsLSPRange::into_range(*full_range),
2447 data: Some(module.uri.to_string().into()),
2448 },
2449 })
2450 }
2451 STeXAnnot::Module {
2452 uri,
2453 name_range,
2454 full_range,
2455 ..
2456 } if usemods => rets.push(lsp::CallHierarchyIncomingCall {
2457 from_ranges: vec![IsLSPRange::into_range(*full_range)],
2458 from: lsp::CallHierarchyItem {
2459 detail: Some(
2460 uri.to_string()
2461 .split_once("a=")
2462 .unwrap_or_else(|| unreachable!())
2463 .1
2464 .to_string(),
2465 ),
2466 name: uri.module_name().to_string(),
2467 kind: lsp::SymbolKind::MODULE,
2468 tags: None,
2469 uri: url.clone().into(),
2470 range: IsLSPRange::into_range(*full_range),
2471 selection_range: IsLSPRange::into_range(*name_range),
2472 data: Some(uri.to_string().into()),
2473 },
2474 }),
2475 STeXAnnot::UseModule {
2476 module, full_range, ..
2477 } if usemods => {
2478 let Some(p) = module.full_path.as_ref() else {
2479 continue;
2480 };
2481 let Ok(url) = lsp::Url::from_file_path(p) else {
2482 continue;
2483 };
2484 rets.push(lsp::CallHierarchyIncomingCall {
2485 from_ranges: vec![lsp::Range::default()],
2486 from: lsp::CallHierarchyItem {
2487 detail: Some(
2488 module
2489 .uri
2490 .to_string()
2491 .split_once("a=")
2492 .unwrap_or_else(|| unreachable!())
2493 .1
2494 .to_string(),
2495 ),
2496 name: module.uri.module_name().to_string(),
2497 kind: lsp::SymbolKind::METHOD,
2498 tags: None,
2499 uri: url,
2500 range: IsLSPRange::into_range(*full_range),
2501 selection_range: IsLSPRange::into_range(*full_range),
2502 data: Some(module.uri.to_string().into()),
2503 },
2504 })
2505 }
2506 _ => (),
2507 }
2508 }
2509 Some(rets)
2510 }))
2511 }
2512
2513 #[must_use]
2514 pub fn get_references(
2515 &self,
2516 uri: UrlOrFile,
2517 position: lsp::Position,
2518 _: Option<ProgressCallbackClient>,
2519 ) -> Option<impl std::future::Future<Output = Option<Vec<lsp::Location>>> + use<>> {
2520 let d = self.get(&uri)?;
2521 let pos = LSPLineCol::new(position.line, position.character);
2522 let slf = self.clone();
2523 enum Target {
2524 Module(ModuleUri),
2525 Structure(SymbolUri),
2526 Symbol(SymbolUri),
2527 Morphism(SymbolUri),
2528 }
2529 Some(async move {
2530 let e = d
2531 .with_annots(slf.clone(), false, move |data| {
2532 match at_position(data, pos)? {
2533 STeXAnnot::Module { uri, .. } => Some(Target::Module(uri.clone())),
2534 STeXAnnot::MathStructure { uri, .. } => {
2535 Some(Target::Structure(uri.uri.clone()))
2536 }
2537 STeXAnnot::MorphismEnv { uri, .. }
2538 | STeXAnnot::InlineMorphism { uri, .. } => {
2539 Some(Target::Morphism(uri.clone()))
2540 }
2541 STeXAnnot::Symdecl { uri, .. }
2542 | STeXAnnot::TextSymdecl { uri, .. }
2543 | STeXAnnot::Paragraph {
2544 symbol: Some(uri), ..
2545 }
2546 | STeXAnnot::InlineParagraph {
2547 symbol: Some(uri), ..
2548 }
2549 | STeXAnnot::Symdef { uri, .. } => Some(Target::Symbol(uri.uri.clone())),
2550 STeXAnnot::RenameDecl { .. } => None, STeXAnnot::Vardef { .. } | STeXAnnot::Varseq { .. } => {
2552 None
2554 }
2555 _ => None,
2556 }
2557 })
2558 .await??;
2559 tokio::task::spawn_blocking(move || {
2560 let all = slf.documents.read();
2561 macro_rules! iter {
2562 ($annot:ident => $then:expr) => {
2563 for (k,v) in all.iter() {
2564 let data = match v {
2565 DocData::Data(d,_ ) => d,
2566 DocData::Doc(d) => &d.annotations
2567 };
2568 let data = data.lock();
2569 let iter : AnnotIter = data.annotations.iter().into();
2570 macro_rules! here {
2571 ($e:expr) => {
2572 lsp::Location {
2573 uri:k.clone().into(),
2574 range: StringRange::into_range($e)
2575 }
2576 }
2577 }
2578 for $annot in <AnnotIter as TreeChildIter<STeXAnnot>>::dfs(iter) { $then }
2579 drop(data);
2580 }
2581 }
2582 }
2583 let mut ret = Vec::new();
2584 match e {
2585 Target::Module(muri) => {
2586 iter!(a => match a {
2587 STeXAnnot::ImportModule{module,full_range,..} | STeXAnnot::UseModule{module,full_range,..} if module.uri == muri => {
2588 ret.push(here!(*full_range))
2589 }
2590 STeXAnnot::MorphismEnv{domain:ModuleOrStruct::Module(rf),domain_range,..} |
2591 STeXAnnot::InlineMorphism{domain:ModuleOrStruct::Module(rf),domain_range,..}
2592 if rf.uri == muri => ret.push(here!(*domain_range)),
2593 _ => ()
2594 })
2595 }
2596 Target::Structure(suri) | Target::Morphism(suri) | Target::Symbol(suri) => {
2597 iter!(a => match a {
2598 STeXAnnot::MathStructure{extends,..} => for (s,r) in extends {
2599 if s.uri == suri { ret.push(here!(*r)); }
2600 }
2601 STeXAnnot::ConservativeExt{uri,extstructure_range:range,..} |
2602 STeXAnnot::MorphismEnv{domain:ModuleOrStruct::Struct(uri),domain_range:range,..} |
2603 STeXAnnot::InlineMorphism{domain:ModuleOrStruct::Struct(uri),domain_range:range,..} |
2604 STeXAnnot::SemanticMacro{uri,token_range:range,..} |
2605 STeXAnnot::UseStructure{structure:uri,structure_range:range,..} |
2606 STeXAnnot::RenameDecl{uri,orig_range:range,..} |
2607 STeXAnnot::Assign{uri,orig_range:range,..}
2608 if uri.uri == suri => ret.push(here!(*range)),
2609 STeXAnnot::Notation{uri,name_range:range,..} |
2610 STeXAnnot::SymName{uri,name_range:range,..} |
2611 STeXAnnot::Symuse{uri,name_range:range,..} |
2612 STeXAnnot::Symref{uri,name_range:range,..} |
2613 STeXAnnot::Precondition{uri,symbol_range:range,.. } |
2614 STeXAnnot::Objective{uri,symbol_range:range,.. } |
2615 STeXAnnot::Definiens{uri,full_range:range,..} => {
2616 for u in uri {
2617 if u.uri == suri { ret.push(here!(*range)) }
2618 }
2619 }
2620 STeXAnnot::Paragraph{parsed_args,..} | STeXAnnot::InlineParagraph{parsed_args,..} => {
2621 for a in parsed_args {
2622 if let ParagraphArg::Fors(ParsedKeyValue{val,..}) = a {
2623 for (uri,range) in val {
2624 for u in uri {
2625 if u.uri == suri { ret.push(here!(*range)) }
2626 }
2627 }
2628 }
2629 }
2630 }
2631 _ => ()
2632 })
2633 }
2634 }
2635 ret
2636 }).await.ok()
2637 })
2638 }
2639
2640 #[must_use]
2641 pub fn get_hover(
2642 &self,
2643 uri: &UrlOrFile,
2644 position: lsp::Position,
2645 _: Option<ProgressCallbackClient>,
2646 ) -> Option<impl std::future::Future<Output = Option<lsp::Hover>> + use<>> {
2647 fn get_comment(txt: &str, pos: LSPLineCol, out: &mut String) {
2648 let off = pos.into_other::<ByteOffset>(txt).0;
2649 let mut lines = txt[..off].trim_end().lines();
2650 let mut ret = Vec::new();
2651 while let Some(l) = lines.next_back()
2652 && let l = l.trim_start()
2653 && l.starts_with("%%")
2654 {
2655 let l = l[2..].trim();
2656 ret.push(l);
2657 }
2658 if !ret.is_empty() {
2659 out.push_str("\n_____\n");
2660 for s in ret.into_iter().rev() {
2661 out.push_str(s);
2662 out.push('\n');
2663 }
2664 }
2665 }
2666 let d = self.get(uri)?;
2667 let da = d.archive().cloned();
2668 let pos = LSPLineCol::new(position.line, position.character);
2669 let slf = self.clone();
2670 let fut = d.with_annots(self.clone(), false, move |data| {
2671 at_position(data, pos).and_then(|e| e.hover(da.as_ref(), pos))
2672 });
2673 Some(async move {
2674 let o = fut.await.flatten()?;
2675 let (range, s) = match o {
2676 either_of::Either::Left(a) => return Some(a),
2677 either_of::Either::Right((range, s)) => (range, s),
2678 };
2679 let mut ret = format!("<sup>`{}`</sup>", s.uri);
2680 if let Some(fp) = s.filepath.as_ref()
2681 && let Ok(url) = lsp::Url::from_file_path(fp)
2682 {
2683 let url = url.into();
2684 let src = if let Some(src) = slf.get(&url) {
2685 Some(src)
2686 } else if let Ok(txt) = tokio::fs::read_to_string(fp).await {
2687 slf.insert(url.clone(), txt);
2688 slf.get(&url)
2689 } else {
2690 None
2691 };
2692
2693 if let Some(src) = src.as_ref()
2694 && !src.with_text(|txt| {
2695 if txt.is_empty() {
2696 false
2697 } else {
2698 get_comment(txt, s.range.start, &mut ret);
2699 true
2700 }
2701 })
2702 && let Some(p) = src.path()
2703 && let Ok(txt) = tokio::fs::read_to_string(p).await
2704 {
2705 get_comment(&txt, s.range.start, &mut ret);
2706 src.set_text(txt);
2707 }
2708
2709 if let Some(src) = src {
2710 slf.hover_metadata(src, s, &mut ret).await;
2711 }
2712 }
2713
2714 Some(lsp::Hover {
2715 range: Some(range),
2716 contents: lsp::HoverContents::Markup(lsp::MarkupContent {
2717 kind: lsp::MarkupKind::Markdown,
2718 value: ret,
2719 }),
2720 })
2721 })
2722 }
2723
2724 #[must_use]
2725 pub fn get_codeaction(
2726 &self,
2727 uri: UrlOrFile,
2728 range: lsp::Range,
2729 _context: lsp::CodeActionContext,
2730 _: Option<ProgressCallbackClient>,
2731 ) -> Option<impl std::future::Future<Output = Option<lsp::CodeActionResponse>> + use<>> {
2732 let d = self.get(&uri)?;
2733 let pos = LSPLineCol::new(range.start.line, range.start.character);
2734 let url = uri.into();
2735 Some(
2736 d.with_annots(self.clone(), false, move |data| {
2737 at_position(data, pos).map(|e| e.code_action(pos, &url))
2738 })
2739 .map(|o| o.flatten()),
2740 )
2741 }
2742
2743 #[must_use]
2744 pub fn get_goto_definition(
2745 &self,
2746 uri: UrlOrFile,
2747 position: lsp::Position,
2748 _: Option<ProgressCallbackClient>,
2749 ) -> Option<impl std::future::Future<Output = Option<lsp::GotoDefinitionResponse>> + use<>>
2750 {
2751 let d = self.get(&uri)?;
2752 let pos = LSPLineCol::new(position.line, position.character);
2753 Some(
2754 d.with_annots(self.clone(), false, move |data| {
2755 at_position(data, pos).and_then(|e| e.goto_definition(&uri, pos))
2756 })
2757 .map(|o| o.flatten()),
2758 )
2759 }
2760
2761 #[must_use]
2762 pub fn get_inlay_hints(
2763 &self,
2764 uri: &UrlOrFile,
2765 _: Option<ProgressCallbackClient>,
2766 ) -> Option<impl std::future::Future<Output = Option<Vec<lsp::InlayHint>>> + use<>> {
2767 let d = self.get(uri)?;
2768 Some(d.with_annots(self.clone(), false, move |data| {
2769 let iter: AnnotIter = data.annotations.iter().into();
2770 <AnnotIter as TreeChildIter<STeXAnnot>>::dfs(iter)
2771 .filter_map(|e| e.inlay_hint())
2772 .collect()
2773 }))
2774 }
2775
2776 pub fn get_semantic_tokens(
2777 &self,
2778 uri: &UrlOrFile,
2779 progress: Option<ProgressCallbackClient>,
2780 _range: Option<lsp::Range>,
2781 ) -> Option<impl std::future::Future<Output = Option<lsp::SemanticTokens>> + use<>> {
2782 let d = self.get(uri)?;
2784 Some(d.with_annots(self.clone(), false, |data| {
2785 let mut ret = Vec::new();
2786 let mut curr = (0u32, 0u32);
2787 for e in data.annotations.iter() {
2788 e.semantic_tokens(&mut |range, tp| {
2789 if range.start.line < curr.0 {
2790 return;
2791 }
2792 let delta_line = range.start.line - curr.0;
2793 let delta_start = if delta_line == 0 {
2794 if range.start.col > curr.1 {
2795 range.start.col - curr.1
2796 } else {
2797 return;
2798 }
2799 } else {
2800 range.start.col
2801 };
2802 curr = (range.start.line, range.start.col);
2803 if range.start.line == range.end.line {
2804 let length = if range.end.col < range.start.col {
2805 999
2806 } else {
2807 range.end.col - range.start.col
2808 };
2809 ret.push(lsp::SemanticToken {
2810 delta_line,
2811 delta_start,
2812 length,
2813 token_type: tp,
2814 token_modifiers_bitset: 0,
2815 });
2816 } else {
2817 ret.push(lsp::SemanticToken {
2818 delta_line,
2819 delta_start,
2820 length: 999,
2821 token_type: tp,
2822 token_modifiers_bitset: 0,
2823 });
2824 }
2826 });
2827 }
2828
2829 if let Some(p) = progress {
2830 p.finish()
2831 }
2832 lsp::SemanticTokens {
2833 result_id: None,
2834 data: ret,
2835 }
2836 }))
2837 }
2838
2839 async fn hover_metadata(
2840 self,
2841 src: LSPDocument,
2842 s: SymbolReference<LSPLineCol>,
2843 out: &mut String,
2844 ) {
2845 #[derive(Clone, Copy, Default)]
2846 struct SymbolData {
2847 macro_name: Option<StringRange<LSPLineCol>>,
2848 args: Option<StringRange<LSPLineCol>>,
2849 tp: Option<StringRange<LSPLineCol>>,
2850 df: Option<StringRange<LSPLineCol>>,
2851 returns: Option<StringRange<LSPLineCol>>,
2852 }
2853 impl SymbolData {
2854 const fn is_empty(self) -> bool {
2855 self.macro_name.is_none()
2856 && self.args.is_none()
2857 && self.tp.is_none()
2858 && self.df.is_none()
2859 && self.returns.is_none()
2860 }
2861 fn write(self, sym_text: &str, start: LSPLineCol, out: &mut String) {
2862 out.push_str("| | |\n| --- | --- |\n");
2863 if let Some(m) = self.macro_name {
2864 let m = &sym_text[m - start];
2865 let _ = writeln!(out, "| *macro* | `\\{m}`|");
2866 }
2867 if let Some(a) = self.args {
2868 let a = &sym_text[a - start];
2870 let _ = writeln!(out, "| *arguments* | {a} |");
2871 }
2872 if let Some(r) = self.returns {
2873 let r = &sym_text[r - start];
2875 let _ = writeln!(out, "| *returns* | `{}` |", r.replace('\n', ""));
2876 }
2877 if let Some(t) = self.tp {
2878 let t = &sym_text[t - start];
2880 let _ = writeln!(out, "| *type* | `{}` |", t.replace('\n', ""));
2881 }
2882 if let Some(d) = self.df {
2883 let d = &sym_text[d - start];
2885 let _ = writeln!(out, "| *definiens* | `{}` |", d.replace('\n', ""));
2886 }
2887 }
2888 }
2889 struct Assignment {}
2890 enum Data {
2891 Symbol(SymbolData),
2892 Structure {
2893 extensions: Vec<SymbolReference<LSPLineCol>>,
2894 fields: Vec<SymbolData>,
2895 },
2896 Morphism(Vec<Assignment>),
2897 }
2898
2899 match src
2900 .clone()
2901 .with_annots(self, false, move |data| {
2902 let iter: AnnotIter = data.annotations.iter().into();
2903 for a in <AnnotIter as TreeChildIter<STeXAnnot>>::dfs(iter) {
2904 match a {
2905 STeXAnnot::MathStructure {
2906 uri,
2907 extends,
2908 opts,
2909 children,
2910 ..
2911 } if uri.uri == s.uri => {
2912 ()
2914 }
2915 STeXAnnot::MorphismEnv {
2916 uri,
2917 star,
2918 domain,
2919 kind,
2920 children,
2921 ..
2922 } if *uri == s.uri => {
2923 ()
2925 }
2926 STeXAnnot::InlineMorphism {
2927 uri,
2928 domain,
2929 domain_range,
2930 kind,
2931 assignments,
2932 ..
2933 } if *uri == s.uri => {
2934 ()
2936 }
2937 STeXAnnot::Paragraph {
2938 symbol: Some(uri),
2939 parsed_args,
2940 children,
2941 full_range,
2942 ..
2943 }
2944 | STeXAnnot::InlineParagraph {
2945 symbol: Some(uri),
2946 parsed_args,
2947 children,
2948 full_range,
2949 ..
2950 } if uri.uri == s.uri => {
2951 let mut data = SymbolData::default();
2952 for l in parsed_args {
2953 match l {
2954 ParagraphArg::Args(v) => data.args = Some(v.val_range),
2955 ParagraphArg::Tp(t) => data.tp = Some(t.val_range),
2956 ParagraphArg::Df(d) => data.df = Some(d.val_range),
2957 ParagraphArg::Return(r) => data.returns = Some(r.val_range),
2958 ParagraphArg::MacroName(r) => {
2959 data.macro_name = Some(r.val_range);
2960 }
2961 _ => (),
2962 }
2963 }
2964 return Some((*full_range, Data::Symbol(data)));
2965 }
2966 STeXAnnot::Symdecl {
2967 uri,
2968 parsed_args,
2969 starred,
2970 main_name_range,
2971 full_range,
2972 ..
2973 } if uri.uri == s.uri => {
2974 let mut data = SymbolData::default();
2975 if !starred {
2976 data.macro_name = Some(*main_name_range);
2977 }
2978 for l in parsed_args {
2979 match l {
2980 SymdeclArg::Args(v) => data.args = Some(v.val_range),
2981 SymdeclArg::Tp(t) => data.tp = Some(t.val_range),
2982 SymdeclArg::Df(d) => data.df = Some(d.val_range),
2983 SymdeclArg::Return(r) => data.returns = Some(r.val_range),
2984 _ => (),
2985 }
2986 }
2987 return Some((*full_range, Data::Symbol(data)));
2988 }
2989 STeXAnnot::TextSymdecl {
2990 uri,
2991 parsed_args,
2992 main_name_range,
2993 full_range,
2994 ..
2995 } if uri.uri == s.uri => {
2996 let mut data = SymbolData::default();
2997 data.macro_name = Some(*main_name_range);
2998 for l in parsed_args {
2999 match l {
3000 TextSymdeclArg::Tp(t) => data.tp = Some(t.val_range),
3001 TextSymdeclArg::Df(d) => data.df = Some(d.val_range),
3002 _ => (),
3003 }
3004 }
3005 return Some((*full_range, Data::Symbol(data)));
3006 }
3007 STeXAnnot::Symdef {
3008 uri,
3009 parsed_args,
3010 main_name_range,
3011 full_range,
3012 ..
3013 } if uri.uri == s.uri => {
3014 let mut data = SymbolData::default();
3015 data.macro_name = Some(*main_name_range);
3016 for l in parsed_args {
3017 match l {
3018 SymdefArg::Args(v) => data.args = Some(v.val_range),
3019 SymdefArg::Tp(t) => data.tp = Some(t.val_range),
3020 SymdefArg::Df(d) => data.df = Some(d.val_range),
3021 SymdefArg::Return(r) => data.returns = Some(r.val_range),
3022 _ => (),
3023 }
3024 }
3025 return Some((*full_range, Data::Symbol(data)));
3026 }
3027 _ => (),
3028 }
3029 }
3030 None
3031 })
3032 .await
3033 .flatten()
3034 {
3035 Some((r, Data::Symbol(s))) if !s.is_empty() => src.with_text(|txt| {
3036 out.push_str("\n______\n");
3037 let start = r.start.into_other::<ByteOffset>(txt);
3038 let txt = &txt[start.0..];
3039 s.write(txt, r.start, out);
3040 }),
3041 Some((r, Data::Structure { extensions, fields })) => (),
3042 Some((r, Data::Morphism(_))) => (),
3043 _ => (),
3044 }
3045 }
3046}
3047
3048fn at_position(data: &STeXParseDataI, position: LSPLineCol) -> Option<&STeXAnnot> {
3049 let mut ret = None;
3050 let iter: AnnotIter = data.annotations.iter().into();
3051 for e in <AnnotIter as TreeChildIter<STeXAnnot>>::dfs(iter) {
3052 let range = e.range();
3053 if range.contains(position) {
3054 ret = Some(e);
3055 } else if range.start > position {
3056 if ret.is_some() {
3057 break;
3058 }
3059 }
3060 }
3061 ret
3062}
3063
3064#[must_use]
3065pub fn to_diagnostic(diag: &STeXDiagnostic) -> lsp::Diagnostic {
3066 lsp::Diagnostic {
3067 range: diag.range.into_range(),
3068 severity: Some(match diag.level {
3069 DiagnosticLevel::Error => lsp::DiagnosticSeverity::ERROR,
3070 DiagnosticLevel::Info => lsp::DiagnosticSeverity::INFORMATION,
3071 DiagnosticLevel::Warning => lsp::DiagnosticSeverity::WARNING,
3072 DiagnosticLevel::Hint => lsp::DiagnosticSeverity::HINT,
3073 }),
3074 code: None,
3075 code_description: None,
3076 source: None,
3077 message: diag.message.clone(),
3078 related_information: None,
3079 tags: None,
3080 data: None,
3081 }
3082}
3083#[must_use]
3084pub fn into_diagnostic(diag: STeXDiagnostic) -> lsp::Diagnostic {
3085 lsp::Diagnostic {
3086 range: diag.range.into_range(),
3087 severity: Some(match diag.level {
3088 DiagnosticLevel::Error => lsp::DiagnosticSeverity::ERROR,
3089 DiagnosticLevel::Info => lsp::DiagnosticSeverity::INFORMATION,
3090 DiagnosticLevel::Warning => lsp::DiagnosticSeverity::WARNING,
3091 DiagnosticLevel::Hint => lsp::DiagnosticSeverity::HINT,
3092 }),
3093 code: None,
3094 code_description: None,
3095 source: None,
3096 message: diag.message,
3097 related_information: None,
3098 tags: None,
3099 data: None,
3100 }
3101}
3102
3103fn disamb(uri: &SymbolUri, all: &[String]) -> String {
3104 let mut ret = format!("?{}", uri.name());
3105 if all.iter().filter(|s| s.ends_with(&ret)).count() == 1 {
3106 return ret;
3107 }
3108 ret = format!("?{}{ret}", uri.module_name());
3109 if all.iter().filter(|s| s.ends_with(&ret)).count() == 1 {
3110 return ret;
3111 }
3112 if let Some(path) = uri.path() {
3113 let mut had_path = false;
3114 for s in path.steps().rev() {
3115 if had_path {
3116 ret = format!("{s}/{ret}");
3117 } else {
3118 had_path = true;
3119 ret = format!("{s}{ret}");
3120 }
3121 if all.iter().filter(|s| s.ends_with(&ret)).count() == 1 {
3122 return ret;
3123 }
3124 }
3125 }
3126 for i in uri.archive_id().steps().rev() {
3127 ret = format!("{i}/{ret}");
3128 if all.iter().filter(|s| s.ends_with(&ret)).count() == 1 {
3129 return ret;
3130 }
3131 }
3132 ret
3133}