forked from nushell/nushell
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement LSP Text Document Synchronization (nushell#10941)
- Loading branch information
1 parent
27243a0
commit add2fc4
Showing
8 changed files
with
619 additions
and
146 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
use lsp_types::{ | ||
notification::{Notification, PublishDiagnostics}, | ||
Diagnostic, DiagnosticSeverity, PublishDiagnosticsParams, Url, | ||
}; | ||
use miette::{IntoDiagnostic, Result}; | ||
use nu_parser::parse; | ||
use nu_protocol::{ | ||
engine::{EngineState, StateWorkingSet}, | ||
eval_const::create_nu_constant, | ||
Span, Value, NU_VARIABLE_ID, | ||
}; | ||
|
||
use crate::LanguageServer; | ||
|
||
impl LanguageServer { | ||
pub(crate) fn publish_diagnostics_for_file( | ||
&self, | ||
uri: Url, | ||
engine_state: &mut EngineState, | ||
) -> Result<()> { | ||
let cwd = std::env::current_dir().expect("Could not get current working directory."); | ||
engine_state.add_env_var("PWD".into(), Value::test_string(cwd.to_string_lossy())); | ||
|
||
let Ok(nu_const) = create_nu_constant(engine_state, Span::unknown()) else { | ||
return Ok(()); | ||
}; | ||
engine_state.set_variable_const_val(NU_VARIABLE_ID, nu_const); | ||
|
||
let mut working_set = StateWorkingSet::new(engine_state); | ||
|
||
let Some((rope_of_file, file_path)) = self.rope(&uri) else { | ||
return Ok(()); | ||
}; | ||
|
||
let contents = rope_of_file.bytes().collect::<Vec<u8>>(); | ||
let offset = working_set.next_span_start(); | ||
parse( | ||
&mut working_set, | ||
Some(&file_path.to_string_lossy()), | ||
&contents, | ||
false, | ||
); | ||
|
||
let mut diagnostics = PublishDiagnosticsParams { | ||
uri, | ||
diagnostics: Vec::new(), | ||
version: None, | ||
}; | ||
|
||
for err in working_set.parse_errors.iter() { | ||
let message = err.to_string(); | ||
|
||
diagnostics.diagnostics.push(Diagnostic { | ||
range: Self::span_to_range(&err.span(), rope_of_file, offset), | ||
severity: Some(DiagnosticSeverity::ERROR), | ||
message, | ||
..Default::default() | ||
}); | ||
} | ||
|
||
self.connection | ||
.sender | ||
.send(lsp_server::Message::Notification( | ||
lsp_server::Notification::new(PublishDiagnostics::METHOD.to_string(), diagnostics), | ||
)) | ||
.into_diagnostic() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use assert_json_diff::assert_json_eq; | ||
use lsp_types::Url; | ||
use nu_test_support::fs::fixtures; | ||
|
||
use crate::tests::{initialize_language_server, open, update}; | ||
|
||
#[test] | ||
fn publish_diagnostics_variable_does_not_exists() { | ||
let (client_connection, _recv) = initialize_language_server(); | ||
|
||
let mut script = fixtures(); | ||
script.push("lsp"); | ||
script.push("diagnostics"); | ||
script.push("var.nu"); | ||
let script = Url::from_file_path(script).unwrap(); | ||
|
||
let notification = open(&client_connection, script.clone()); | ||
|
||
assert_json_eq!( | ||
notification, | ||
serde_json::json!({ | ||
"method": "textDocument/publishDiagnostics", | ||
"params": { | ||
"uri": script, | ||
"diagnostics": [{ | ||
"range": { | ||
"start": { "line": 0, "character": 6 }, | ||
"end": { "line": 0, "character": 30 } | ||
}, | ||
"message": "Variable not found.", | ||
"severity": 1 | ||
}] | ||
} | ||
}) | ||
); | ||
} | ||
|
||
#[test] | ||
fn publish_diagnostics_fixed_unknown_variable() { | ||
let (client_connection, _recv) = initialize_language_server(); | ||
|
||
let mut script = fixtures(); | ||
script.push("lsp"); | ||
script.push("diagnostics"); | ||
script.push("var.nu"); | ||
let script = Url::from_file_path(script).unwrap(); | ||
|
||
open(&client_connection, script.clone()); | ||
let notification = update( | ||
&client_connection, | ||
script.clone(), | ||
String::from("$env"), | ||
Some(lsp_types::Range { | ||
start: lsp_types::Position { | ||
line: 0, | ||
character: 6, | ||
}, | ||
end: lsp_types::Position { | ||
line: 0, | ||
character: 30, | ||
}, | ||
}), | ||
); | ||
|
||
assert_json_eq!( | ||
notification, | ||
serde_json::json!({ | ||
"method": "textDocument/publishDiagnostics", | ||
"params": { | ||
"uri": script, | ||
"diagnostics": [] | ||
} | ||
}) | ||
); | ||
} | ||
} |
Oops, something went wrong.