mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +00:00
259 lines
8 KiB
Rust
259 lines
8 KiB
Rust
use roc_region::all::{LineColumn, LineColumnRegion, LineInfo, Region};
|
|
use tower_lsp::lsp_types::{Position, Range};
|
|
|
|
pub(crate) trait ToRange {
|
|
type Feed;
|
|
|
|
fn to_range(&self, feed: &Self::Feed) -> Range;
|
|
}
|
|
|
|
impl ToRange for Region {
|
|
type Feed = LineInfo;
|
|
|
|
fn to_range(&self, line_info: &LineInfo) -> Range {
|
|
let LineColumnRegion { start, end } = line_info.convert_region(*self);
|
|
Range {
|
|
start: Position {
|
|
line: start.line,
|
|
character: start.column,
|
|
},
|
|
end: Position {
|
|
line: end.line,
|
|
character: end.column,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) trait ToRegion {
|
|
type Feed;
|
|
|
|
fn to_region(&self, feed: &Self::Feed) -> Region;
|
|
}
|
|
|
|
impl ToRegion for Range {
|
|
type Feed = LineInfo;
|
|
|
|
fn to_region(&self, line_info: &LineInfo) -> Region {
|
|
let lc_region = LineColumnRegion {
|
|
start: LineColumn {
|
|
line: self.start.line,
|
|
column: self.start.character,
|
|
},
|
|
end: LineColumn {
|
|
line: self.end.line,
|
|
column: self.end.line,
|
|
},
|
|
};
|
|
|
|
line_info.convert_line_column_region(lc_region)
|
|
}
|
|
}
|
|
|
|
pub(crate) trait ToRocPosition {
|
|
type Feed;
|
|
|
|
fn to_roc_position(&self, feed: &Self::Feed) -> roc_region::all::Position;
|
|
}
|
|
|
|
impl ToRocPosition for tower_lsp::lsp_types::Position {
|
|
type Feed = LineInfo;
|
|
|
|
fn to_roc_position(&self, line_info: &LineInfo) -> roc_region::all::Position {
|
|
let lc = LineColumn {
|
|
line: self.line,
|
|
column: self.character,
|
|
};
|
|
line_info.convert_line_column(lc)
|
|
}
|
|
}
|
|
|
|
pub(crate) mod diag {
|
|
use std::path::Path;
|
|
|
|
use roc_load::LoadingProblem;
|
|
use roc_region::all::{LineInfo, Region};
|
|
use roc_solve_problem::TypeError;
|
|
|
|
use roc_problem::Severity;
|
|
use roc_reporting::report::RocDocAllocator;
|
|
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
|
|
|
|
use super::ToRange;
|
|
|
|
pub trait IntoLspSeverity {
|
|
fn into_lsp_severity(self) -> DiagnosticSeverity;
|
|
}
|
|
|
|
impl IntoLspSeverity for Severity {
|
|
fn into_lsp_severity(self) -> DiagnosticSeverity {
|
|
match self {
|
|
Severity::RuntimeError => DiagnosticSeverity::ERROR,
|
|
Severity::Warning => DiagnosticSeverity::WARNING,
|
|
Severity::Fatal => DiagnosticSeverity::ERROR,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait IntoLspDiagnostic<'a> {
|
|
type Feed;
|
|
|
|
fn into_lsp_diagnostic(self, feed: &'a Self::Feed) -> Option<Diagnostic>;
|
|
}
|
|
|
|
impl IntoLspDiagnostic<'_> for &LoadingProblem<'_> {
|
|
type Feed = ();
|
|
|
|
fn into_lsp_diagnostic(self, _feed: &()) -> Option<Diagnostic> {
|
|
let range = Range {
|
|
start: Position {
|
|
line: 0,
|
|
character: 0,
|
|
},
|
|
end: Position {
|
|
line: 0,
|
|
character: 1,
|
|
},
|
|
};
|
|
|
|
let msg = match self {
|
|
LoadingProblem::FileProblem { filename, error } => {
|
|
format!(
|
|
"Failed to load {} due to an I/O error: {}",
|
|
filename.display(),
|
|
error
|
|
)
|
|
}
|
|
LoadingProblem::MultiplePlatformPackages { filename, .. } => {
|
|
format!(
|
|
"Multiple platform packages specified ({}). An app must specify exactly one platform.",
|
|
filename.display()
|
|
)
|
|
}
|
|
LoadingProblem::NoPlatformPackage { filename, .. } => {
|
|
format!(
|
|
"No platform package specified ({}). An app must specify exactly one platform.",
|
|
filename.display()
|
|
)
|
|
}
|
|
LoadingProblem::ParsingFailed(fe) => {
|
|
let problem = &fe.problem.problem;
|
|
format!("Failed to parse Roc source file: {problem:?}")
|
|
}
|
|
LoadingProblem::UnexpectedHeader(header) => {
|
|
format!("Unexpected header: {}", header)
|
|
}
|
|
LoadingProblem::ChannelProblem(_) => {
|
|
"Internal error: message channel died".to_string()
|
|
}
|
|
LoadingProblem::ErrJoiningWorkerThreads => {
|
|
"Internal error: analysis worker threads died".to_string()
|
|
}
|
|
LoadingProblem::TriedToImportAppModule => {
|
|
"Attempted to import app module".to_string()
|
|
}
|
|
LoadingProblem::FormattedReport(report) => report.clone(),
|
|
LoadingProblem::ImportCycle(_, _) => {
|
|
"Circular dependency between modules".to_string()
|
|
}
|
|
LoadingProblem::IncorrectModuleName(_) => "Incorrect module name".to_string(),
|
|
LoadingProblem::CouldNotFindCacheDir => {
|
|
format!(
|
|
"Could not find Roc cache directory {}",
|
|
roc_packaging::cache::roc_cache_dir().display()
|
|
)
|
|
}
|
|
LoadingProblem::UnrecognizedPackageShorthand { shorthand, .. } => {
|
|
format!("Unrecognized package shorthand: {}", shorthand)
|
|
}
|
|
};
|
|
|
|
Some(Diagnostic {
|
|
range,
|
|
severity: Some(DiagnosticSeverity::ERROR),
|
|
code: None,
|
|
code_description: None,
|
|
source: Some("load".to_owned()),
|
|
message: msg,
|
|
related_information: None,
|
|
tags: None,
|
|
data: None,
|
|
})
|
|
}
|
|
}
|
|
|
|
pub struct ProblemFmt<'a> {
|
|
pub alloc: &'a RocDocAllocator<'a>,
|
|
pub line_info: &'a LineInfo,
|
|
pub path: &'a Path,
|
|
}
|
|
|
|
impl<'a> IntoLspDiagnostic<'a> for roc_problem::can::Problem {
|
|
type Feed = ProblemFmt<'a>;
|
|
|
|
fn into_lsp_diagnostic(self, fmt: &'a ProblemFmt<'a>) -> Option<Diagnostic> {
|
|
let range = self
|
|
.region()
|
|
.unwrap_or_else(Region::zero)
|
|
.to_range(fmt.line_info);
|
|
|
|
let report = roc_reporting::report::can_problem(
|
|
fmt.alloc,
|
|
fmt.line_info,
|
|
fmt.path.to_path_buf(),
|
|
self,
|
|
);
|
|
|
|
let severity = report.severity.into_lsp_severity();
|
|
let mut msg = String::new();
|
|
report.render_language_server(&mut msg, fmt.alloc);
|
|
|
|
Some(Diagnostic {
|
|
range,
|
|
severity: Some(severity),
|
|
code: None,
|
|
code_description: None,
|
|
source: None,
|
|
message: msg,
|
|
related_information: None,
|
|
tags: None,
|
|
data: None,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<'a> IntoLspDiagnostic<'a> for TypeError {
|
|
type Feed = ProblemFmt<'a>;
|
|
|
|
fn into_lsp_diagnostic(self, fmt: &'a ProblemFmt<'a>) -> Option<Diagnostic> {
|
|
let range = self
|
|
.region()
|
|
.unwrap_or_else(Region::zero)
|
|
.to_range(fmt.line_info);
|
|
|
|
let report = roc_reporting::report::type_problem(
|
|
fmt.alloc,
|
|
fmt.line_info,
|
|
fmt.path.to_path_buf(),
|
|
self,
|
|
)?;
|
|
|
|
let severity = report.severity.into_lsp_severity();
|
|
|
|
let mut msg = String::new();
|
|
report.render_language_server(&mut msg, fmt.alloc);
|
|
|
|
Some(Diagnostic {
|
|
range,
|
|
severity: Some(severity),
|
|
code: None,
|
|
code_description: None,
|
|
source: None,
|
|
message: msg,
|
|
related_information: None,
|
|
tags: None,
|
|
data: None,
|
|
})
|
|
}
|
|
}
|
|
}
|