mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-11-24 21:19:37 +00:00
feat: create query crate
This commit is contained in:
parent
7e9bddb763
commit
9af8eb4b52
29 changed files with 1312 additions and 1341 deletions
143
crates/tinymist-query/src/diagnostics.rs
Normal file
143
crates/tinymist-query/src/diagnostics.rs
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
pub type DiagnosticsMap = HashMap<Url, Vec<LspDiagnostic>>;
|
||||
|
||||
pub fn convert_diagnostics<'a>(
|
||||
project: &TypstSystemWorld,
|
||||
errors: impl IntoIterator<Item = &'a TypstDiagnostic>,
|
||||
position_encoding: PositionEncoding,
|
||||
) -> DiagnosticsMap {
|
||||
errors
|
||||
.into_iter()
|
||||
.flat_map(|error| {
|
||||
convert_diagnostic(project, error, position_encoding)
|
||||
.map_err(move |conversion_err| {
|
||||
error!("could not convert Typst error to diagnostic: {conversion_err:?} error to convert: {error:?}");
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
.into_group_map()
|
||||
}
|
||||
|
||||
fn convert_diagnostic(
|
||||
project: &TypstSystemWorld,
|
||||
typst_diagnostic: &TypstDiagnostic,
|
||||
position_encoding: PositionEncoding,
|
||||
) -> anyhow::Result<(Url, LspDiagnostic)> {
|
||||
let uri;
|
||||
let lsp_range;
|
||||
if let Some((id, span)) = diagnostic_span_id(typst_diagnostic) {
|
||||
uri = Url::from_file_path(project.path_for_id(id)?).unwrap();
|
||||
let source = project.source(id)?;
|
||||
lsp_range = diagnostic_range(&source, span, position_encoding).raw_range;
|
||||
} else {
|
||||
uri = Url::from_file_path(project.root.clone()).unwrap();
|
||||
lsp_range = LspRawRange::default();
|
||||
};
|
||||
|
||||
let lsp_severity = diagnostic_severity(typst_diagnostic.severity);
|
||||
|
||||
let typst_message = &typst_diagnostic.message;
|
||||
let typst_hints = &typst_diagnostic.hints;
|
||||
let lsp_message = format!("{typst_message}{}", diagnostic_hints(typst_hints));
|
||||
|
||||
let tracepoints = diagnostic_related_information(project, typst_diagnostic, position_encoding)?;
|
||||
|
||||
let diagnostic = LspDiagnostic {
|
||||
range: lsp_range,
|
||||
severity: Some(lsp_severity),
|
||||
message: lsp_message,
|
||||
source: Some("typst".to_owned()),
|
||||
related_information: Some(tracepoints),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok((uri, diagnostic))
|
||||
}
|
||||
|
||||
fn tracepoint_to_relatedinformation(
|
||||
project: &TypstSystemWorld,
|
||||
tracepoint: &Spanned<Tracepoint>,
|
||||
position_encoding: PositionEncoding,
|
||||
) -> anyhow::Result<Option<DiagnosticRelatedInformation>> {
|
||||
if let Some(id) = tracepoint.span.id() {
|
||||
let uri = Url::from_file_path(project.path_for_id(id)?).unwrap();
|
||||
let source = project.source(id)?;
|
||||
|
||||
if let Some(typst_range) = source.range(tracepoint.span) {
|
||||
let lsp_range = typst_to_lsp::range(typst_range, &source, position_encoding);
|
||||
|
||||
return Ok(Some(DiagnosticRelatedInformation {
|
||||
location: LspLocation {
|
||||
uri,
|
||||
range: lsp_range.raw_range,
|
||||
},
|
||||
message: tracepoint.v.to_string(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn diagnostic_related_information(
|
||||
project: &TypstSystemWorld,
|
||||
typst_diagnostic: &TypstDiagnostic,
|
||||
position_encoding: PositionEncoding,
|
||||
) -> anyhow::Result<Vec<DiagnosticRelatedInformation>> {
|
||||
let mut tracepoints = vec![];
|
||||
|
||||
for tracepoint in &typst_diagnostic.trace {
|
||||
if let Some(info) =
|
||||
tracepoint_to_relatedinformation(project, tracepoint, position_encoding)?
|
||||
{
|
||||
tracepoints.push(info);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(tracepoints)
|
||||
}
|
||||
|
||||
fn diagnostic_span_id(typst_diagnostic: &TypstDiagnostic) -> Option<(FileId, TypstSpan)> {
|
||||
iter::once(typst_diagnostic.span)
|
||||
.chain(typst_diagnostic.trace.iter().map(|trace| trace.span))
|
||||
.find_map(|span| Some((span.id()?, span)))
|
||||
}
|
||||
|
||||
fn diagnostic_range(
|
||||
source: &Source,
|
||||
typst_span: TypstSpan,
|
||||
position_encoding: PositionEncoding,
|
||||
) -> LspRange {
|
||||
// Due to #241 and maybe typst/typst#2035, we sometimes fail to find the span.
|
||||
// In that case, we use a default span as a better alternative to
|
||||
// panicking.
|
||||
//
|
||||
// This may have been fixed after Typst 0.7.0, but it's still nice to avoid
|
||||
// panics in case something similar reappears.
|
||||
match source.find(typst_span) {
|
||||
Some(node) => {
|
||||
let typst_range = node.range();
|
||||
typst_to_lsp::range(typst_range, source, position_encoding)
|
||||
}
|
||||
None => LspRange::new(
|
||||
LspRawRange::new(LspPosition::new(0, 0), LspPosition::new(0, 0)),
|
||||
position_encoding,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn diagnostic_severity(typst_severity: TypstSeverity) -> LspSeverity {
|
||||
match typst_severity {
|
||||
TypstSeverity::Error => LspSeverity::ERROR,
|
||||
TypstSeverity::Warning => LspSeverity::WARNING,
|
||||
}
|
||||
}
|
||||
|
||||
fn diagnostic_hints(typst_hints: &[EcoString]) -> Format<impl Iterator<Item = EcoString> + '_> {
|
||||
iter::repeat(EcoString::from("\n\nHint: "))
|
||||
.take(typst_hints.len())
|
||||
.interleave(typst_hints.iter().cloned())
|
||||
.format("")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue