mirror of
https://github.com/nushell/nushell.git
synced 2025-05-30 14:50:02 +02:00
fix(lsp): more accurate PWD: from env -> parent dir of current file (#15470)
# Description Some editors like neovim will provide "workspace root" as PWD, which can mess up file completion results. # User-Facing Changes bug fix # Tests + Formatting adjusted # After Submitting
This commit is contained in:
parent
0cd90e2388
commit
210c6f1c43
@ -29,7 +29,7 @@ impl LanguageServer {
|
|||||||
.is_some_and(|c| c.is_whitespace() || "|(){}[]<>,:;".contains(c));
|
.is_some_and(|c| c.is_whitespace() || "|(){}[]<>,:;".contains(c));
|
||||||
|
|
||||||
self.need_parse |= need_fallback;
|
self.need_parse |= need_fallback;
|
||||||
let engine_state = Arc::new(self.new_engine_state());
|
let engine_state = Arc::new(self.new_engine_state(Some(&path_uri)));
|
||||||
let completer = NuCompleter::new(engine_state.clone(), Arc::new(Stack::new()));
|
let completer = NuCompleter::new(engine_state.clone(), Arc::new(Stack::new()));
|
||||||
let results = if need_fallback {
|
let results = if need_fallback {
|
||||||
completer.fetch_completions_at(&file_text[..location], location)
|
completer.fetch_completions_at(&file_text[..location], location)
|
||||||
@ -264,10 +264,10 @@ mod tests {
|
|||||||
let resp = send_complete_request(&client_connection, script.clone(), 2, 18);
|
let resp = send_complete_request(&client_connection, script.clone(), 2, 18);
|
||||||
assert!(result_from_message(resp).as_array().unwrap().contains(
|
assert!(result_from_message(resp).as_array().unwrap().contains(
|
||||||
&serde_json::json!({
|
&serde_json::json!({
|
||||||
"label": "LICENSE",
|
"label": "command.nu",
|
||||||
"labelDetails": { "description": "" },
|
"labelDetails": { "description": "" },
|
||||||
"textEdit": { "range": { "start": { "line": 2, "character": 17 }, "end": { "line": 2, "character": 18 }, },
|
"textEdit": { "range": { "start": { "line": 2, "character": 17 }, "end": { "line": 2, "character": 18 }, },
|
||||||
"newText": "LICENSE"
|
"newText": "command.nu"
|
||||||
},
|
},
|
||||||
"kind": 17
|
"kind": 17
|
||||||
})
|
})
|
||||||
@ -337,10 +337,10 @@ mod tests {
|
|||||||
let resp = send_complete_request(&client_connection, script, 5, 4);
|
let resp = send_complete_request(&client_connection, script, 5, 4);
|
||||||
assert!(result_from_message(resp).as_array().unwrap().contains(
|
assert!(result_from_message(resp).as_array().unwrap().contains(
|
||||||
&serde_json::json!({
|
&serde_json::json!({
|
||||||
"label": "LICENSE",
|
"label": "cell_path.nu",
|
||||||
"labelDetails": { "description": "" },
|
"labelDetails": { "description": "" },
|
||||||
"textEdit": { "range": { "start": { "line": 5, "character": 3 }, "end": { "line": 5, "character": 4 }, },
|
"textEdit": { "range": { "start": { "line": 5, "character": 3 }, "end": { "line": 5, "character": 4 }, },
|
||||||
"newText": "LICENSE"
|
"newText": "cell_path.nu"
|
||||||
},
|
},
|
||||||
"kind": 17
|
"kind": 17
|
||||||
})
|
})
|
||||||
|
@ -7,7 +7,7 @@ use miette::{miette, IntoDiagnostic, Result};
|
|||||||
|
|
||||||
impl LanguageServer {
|
impl LanguageServer {
|
||||||
pub(crate) fn publish_diagnostics_for_file(&mut self, uri: Uri) -> Result<()> {
|
pub(crate) fn publish_diagnostics_for_file(&mut self, uri: Uri) -> Result<()> {
|
||||||
let mut engine_state = self.new_engine_state();
|
let mut engine_state = self.new_engine_state(Some(&uri));
|
||||||
engine_state.generate_nu_constant();
|
engine_state.generate_nu_constant();
|
||||||
|
|
||||||
let Some((_, span, working_set)) = self.parse_file(&mut engine_state, &uri, true) else {
|
let Some((_, span, working_set)) = self.parse_file(&mut engine_state, &uri, true) else {
|
||||||
|
@ -77,13 +77,12 @@ impl LanguageServer {
|
|||||||
&mut self,
|
&mut self,
|
||||||
params: &GotoDefinitionParams,
|
params: &GotoDefinitionParams,
|
||||||
) -> Option<GotoDefinitionResponse> {
|
) -> Option<GotoDefinitionResponse> {
|
||||||
let mut engine_state = self.new_engine_state();
|
|
||||||
|
|
||||||
let path_uri = params
|
let path_uri = params
|
||||||
.text_document_position_params
|
.text_document_position_params
|
||||||
.text_document
|
.text_document
|
||||||
.uri
|
.uri
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
let mut engine_state = self.new_engine_state(Some(&path_uri));
|
||||||
let (working_set, id, _, _) = self
|
let (working_set, id, _, _) = self
|
||||||
.parse_and_find(
|
.parse_and_find(
|
||||||
&mut engine_state,
|
&mut engine_state,
|
||||||
|
@ -129,13 +129,12 @@ impl LanguageServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn hover(&mut self, params: &HoverParams) -> Option<Hover> {
|
pub(crate) fn hover(&mut self, params: &HoverParams) -> Option<Hover> {
|
||||||
let mut engine_state = self.new_engine_state();
|
|
||||||
|
|
||||||
let path_uri = params
|
let path_uri = params
|
||||||
.text_document_position_params
|
.text_document_position_params
|
||||||
.text_document
|
.text_document
|
||||||
.uri
|
.uri
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
let mut engine_state = self.new_engine_state(Some(&path_uri));
|
||||||
let (working_set, id, _, _) = self
|
let (working_set, id, _, _) = self
|
||||||
.parse_and_find(
|
.parse_and_find(
|
||||||
&mut engine_state,
|
&mut engine_state,
|
||||||
|
@ -13,7 +13,7 @@ use miette::{miette, IntoDiagnostic, Result};
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Block, PathMember},
|
ast::{Block, PathMember},
|
||||||
engine::{EngineState, StateDelta, StateWorkingSet},
|
engine::{EngineState, StateDelta, StateWorkingSet},
|
||||||
DeclId, ModuleId, Span, Type, VarId,
|
DeclId, ModuleId, Span, Type, Value, VarId,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
@ -315,13 +315,26 @@ impl LanguageServer {
|
|||||||
Ok(reset)
|
Ok(reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_engine_state(&self) -> EngineState {
|
/// Create a clone of the initial_engine_state with:
|
||||||
|
///
|
||||||
|
/// * PWD set to the parent directory of given uri. Fallback to `$env.PWD` if None.
|
||||||
|
/// * `StateDelta` cache merged
|
||||||
|
pub(crate) fn new_engine_state(&self, uri: Option<&Uri>) -> EngineState {
|
||||||
let mut engine_state = self.initial_engine_state.clone();
|
let mut engine_state = self.initial_engine_state.clone();
|
||||||
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
match uri {
|
||||||
engine_state.add_env_var(
|
Some(uri) => {
|
||||||
"PWD".into(),
|
let path = uri_to_path(uri);
|
||||||
nu_protocol::Value::test_string(cwd.to_string_lossy()),
|
if let Some(path) = path.parent() {
|
||||||
);
|
engine_state
|
||||||
|
.add_env_var("PWD".into(), Value::test_string(path.to_string_lossy()))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
// merge the cached `StateDelta` if text not changed
|
// merge the cached `StateDelta` if text not changed
|
||||||
if !self.need_parse {
|
if !self.need_parse {
|
||||||
engine_state
|
engine_state
|
||||||
@ -350,7 +363,7 @@ impl LanguageServer {
|
|||||||
engine_state: &'a mut EngineState,
|
engine_state: &'a mut EngineState,
|
||||||
uri: &Uri,
|
uri: &Uri,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<(StateWorkingSet<'a>, Id, Span, usize)> {
|
) -> Result<(StateWorkingSet<'a>, Id, Span, Span)> {
|
||||||
let (block, file_span, working_set) = self
|
let (block, file_span, working_set) = self
|
||||||
.parse_file(engine_state, uri, false)
|
.parse_file(engine_state, uri, false)
|
||||||
.ok_or_else(|| miette!("\nFailed to parse current file"))?;
|
.ok_or_else(|| miette!("\nFailed to parse current file"))?;
|
||||||
@ -365,7 +378,7 @@ impl LanguageServer {
|
|||||||
let location = file.offset_at(pos) as usize + file_span.start;
|
let location = file.offset_at(pos) as usize + file_span.start;
|
||||||
let (id, span) = ast::find_id(&block, &working_set, &location)
|
let (id, span) = ast::find_id(&block, &working_set, &location)
|
||||||
.ok_or_else(|| miette!("\nFailed to find current name"))?;
|
.ok_or_else(|| miette!("\nFailed to find current name"))?;
|
||||||
Ok((working_set, id, span, file_span.start))
|
Ok((working_set, id, span, file_span))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_file<'a>(
|
pub(crate) fn parse_file<'a>(
|
||||||
@ -458,10 +471,7 @@ mod tests {
|
|||||||
engine_state.generate_nu_constant();
|
engine_state.generate_nu_constant();
|
||||||
assert!(load_standard_library(&mut engine_state).is_ok());
|
assert!(load_standard_library(&mut engine_state).is_ok());
|
||||||
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
let cwd = std::env::current_dir().expect("Could not get current working directory.");
|
||||||
engine_state.add_env_var(
|
engine_state.add_env_var("PWD".into(), Value::test_string(cwd.to_string_lossy()));
|
||||||
"PWD".into(),
|
|
||||||
nu_protocol::Value::test_string(cwd.to_string_lossy()),
|
|
||||||
);
|
|
||||||
if let Some(code) = nu_config_code {
|
if let Some(code) = nu_config_code {
|
||||||
assert!(merge_input(code.as_bytes(), &mut engine_state, &mut Stack::new()).is_ok());
|
assert!(merge_input(code.as_bytes(), &mut engine_state, &mut Stack::new()).is_ok());
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ impl LanguageServer {
|
|||||||
let file_text = file.get_content(None).to_owned();
|
let file_text = file.get_content(None).to_owned();
|
||||||
drop(docs);
|
drop(docs);
|
||||||
|
|
||||||
let engine_state = self.new_engine_state();
|
let engine_state = self.new_engine_state(Some(&path_uri));
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
// NOTE: in case the cursor is at the end of the call expression
|
// NOTE: in case the cursor is at the end of the call expression
|
||||||
|
@ -270,8 +270,8 @@ impl LanguageServer {
|
|||||||
&mut self,
|
&mut self,
|
||||||
params: &DocumentSymbolParams,
|
params: &DocumentSymbolParams,
|
||||||
) -> Option<DocumentSymbolResponse> {
|
) -> Option<DocumentSymbolResponse> {
|
||||||
let engine_state = self.new_engine_state();
|
|
||||||
let uri = params.text_document.uri.to_owned();
|
let uri = params.text_document.uri.to_owned();
|
||||||
|
let engine_state = self.new_engine_state(Some(&uri));
|
||||||
let docs = self.docs.lock().ok()?;
|
let docs = self.docs.lock().ok()?;
|
||||||
self.symbol_cache.update(&uri, &engine_state, &docs);
|
self.symbol_cache.update(&uri, &engine_state, &docs);
|
||||||
self.symbol_cache
|
self.symbol_cache
|
||||||
@ -284,7 +284,7 @@ impl LanguageServer {
|
|||||||
params: &WorkspaceSymbolParams,
|
params: &WorkspaceSymbolParams,
|
||||||
) -> Option<WorkspaceSymbolResponse> {
|
) -> Option<WorkspaceSymbolResponse> {
|
||||||
if self.symbol_cache.any_dirty() {
|
if self.symbol_cache.any_dirty() {
|
||||||
let engine_state = self.new_engine_state();
|
let engine_state = self.new_engine_state(None);
|
||||||
let docs = self.docs.lock().ok()?;
|
let docs = self.docs.lock().ok()?;
|
||||||
self.symbol_cache.update_all(&engine_state, &docs);
|
self.symbol_cache.update_all(&engine_state, &docs);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::{find_id, find_reference_by_id},
|
ast::{self, find_id, find_reference_by_id},
|
||||||
path_to_uri, span_to_range, uri_to_path, Id, LanguageServer,
|
path_to_uri, span_to_range, uri_to_path, Id, LanguageServer,
|
||||||
};
|
};
|
||||||
use lsp_textdocument::FullTextDocument;
|
use lsp_textdocument::FullTextDocument;
|
||||||
@ -46,6 +46,26 @@ fn find_nu_scripts_in_folder(folder_uri: &Uri) -> Result<nu_glob::Paths> {
|
|||||||
nu_glob::glob(&pattern, Uninterruptible).into_diagnostic()
|
nu_glob::glob(&pattern, Uninterruptible).into_diagnostic()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// HACK: when current file is imported (use keyword) by others in the workspace,
|
||||||
|
/// it will get parsed a second time via `parse_module_block`, so that its definitions'
|
||||||
|
/// ids are renewed, making it harder to track the references.
|
||||||
|
///
|
||||||
|
/// FIXME: cross-file shadowing can still cause false-positive/false-negative cases
|
||||||
|
///
|
||||||
|
/// This is a workaround to track the new id
|
||||||
|
struct IDTracker {
|
||||||
|
/// ID to search, renewed on `parse_module_block`
|
||||||
|
pub id: Id,
|
||||||
|
/// Span of the original instance under the cursor
|
||||||
|
pub span: Span,
|
||||||
|
/// Name of the definition
|
||||||
|
pub name: String,
|
||||||
|
/// Span of the original file where the request comes from
|
||||||
|
pub file_span: Span,
|
||||||
|
/// The redundant parsing should only happen once
|
||||||
|
pub renewed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl LanguageServer {
|
impl LanguageServer {
|
||||||
/// Get initial workspace folders from initialization response
|
/// Get initial workspace folders from initialization response
|
||||||
pub(crate) fn initialize_workspace_folders(
|
pub(crate) fn initialize_workspace_folders(
|
||||||
@ -66,12 +86,12 @@ impl LanguageServer {
|
|||||||
&mut self,
|
&mut self,
|
||||||
params: &DocumentHighlightParams,
|
params: &DocumentHighlightParams,
|
||||||
) -> Option<Vec<DocumentHighlight>> {
|
) -> Option<Vec<DocumentHighlight>> {
|
||||||
let mut engine_state = self.new_engine_state();
|
|
||||||
let path_uri = params
|
let path_uri = params
|
||||||
.text_document_position_params
|
.text_document_position_params
|
||||||
.text_document
|
.text_document
|
||||||
.uri
|
.uri
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
let mut engine_state = self.new_engine_state(Some(&path_uri));
|
||||||
let (block, file_span, working_set) =
|
let (block, file_span, working_set) =
|
||||||
self.parse_file(&mut engine_state, &path_uri, false)?;
|
self.parse_file(&mut engine_state, &path_uri, false)?;
|
||||||
let docs = &self.docs.lock().ok()?;
|
let docs = &self.docs.lock().ok()?;
|
||||||
@ -137,31 +157,38 @@ impl LanguageServer {
|
|||||||
timeout: u128,
|
timeout: u128,
|
||||||
) -> Option<Vec<Location>> {
|
) -> Option<Vec<Location>> {
|
||||||
self.occurrences = BTreeMap::new();
|
self.occurrences = BTreeMap::new();
|
||||||
let mut engine_state = self.new_engine_state();
|
|
||||||
let path_uri = params.text_document_position.text_document.uri.to_owned();
|
let path_uri = params.text_document_position.text_document.uri.to_owned();
|
||||||
let (_, id, span, _) = self
|
let mut engine_state = self.new_engine_state(Some(&path_uri));
|
||||||
|
|
||||||
|
let (working_set, id, span, file_span) = self
|
||||||
.parse_and_find(
|
.parse_and_find(
|
||||||
&mut engine_state,
|
&mut engine_state,
|
||||||
&path_uri,
|
&path_uri,
|
||||||
params.text_document_position.position,
|
params.text_document_position.position,
|
||||||
)
|
)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
// have to clone it again in order to move to another thread
|
|
||||||
let engine_state = self.new_engine_state();
|
|
||||||
let current_workspace_folder = self.get_workspace_folder_by_uri(&path_uri)?;
|
let current_workspace_folder = self.get_workspace_folder_by_uri(&path_uri)?;
|
||||||
let token = params
|
let token = params
|
||||||
.work_done_progress_params
|
.work_done_progress_params
|
||||||
.work_done_token
|
.work_done_token
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.unwrap_or(ProgressToken::Number(1));
|
.unwrap_or(ProgressToken::Number(1));
|
||||||
|
|
||||||
|
let id_tracker = IDTracker {
|
||||||
|
id,
|
||||||
|
span,
|
||||||
|
file_span,
|
||||||
|
name: String::from_utf8_lossy(working_set.get_span_contents(span)).to_string(),
|
||||||
|
renewed: false,
|
||||||
|
};
|
||||||
|
|
||||||
self.channels = self
|
self.channels = self
|
||||||
.find_reference_in_workspace(
|
.find_reference_in_workspace(
|
||||||
engine_state,
|
engine_state,
|
||||||
current_workspace_folder,
|
current_workspace_folder,
|
||||||
id,
|
|
||||||
span,
|
|
||||||
token.clone(),
|
token.clone(),
|
||||||
"Finding references ...".to_string(),
|
"Finding references ...".to_string(),
|
||||||
|
id_tracker,
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
// TODO: WorkDoneProgress -> PartialResults for quicker response
|
// TODO: WorkDoneProgress -> PartialResults for quicker response
|
||||||
@ -200,10 +227,10 @@ impl LanguageServer {
|
|||||||
serde_json::from_value(request.params).into_diagnostic()?;
|
serde_json::from_value(request.params).into_diagnostic()?;
|
||||||
self.occurrences = BTreeMap::new();
|
self.occurrences = BTreeMap::new();
|
||||||
|
|
||||||
let mut engine_state = self.new_engine_state();
|
|
||||||
let path_uri = params.text_document.uri.to_owned();
|
let path_uri = params.text_document.uri.to_owned();
|
||||||
|
let mut engine_state = self.new_engine_state(Some(&path_uri));
|
||||||
|
|
||||||
let (working_set, id, span, file_offset) =
|
let (working_set, id, span, file_span) =
|
||||||
self.parse_and_find(&mut engine_state, &path_uri, params.position)?;
|
self.parse_and_find(&mut engine_state, &path_uri, params.position)?;
|
||||||
|
|
||||||
if let Id::Value(_) = id {
|
if let Id::Value(_) = id {
|
||||||
@ -222,7 +249,7 @@ impl LanguageServer {
|
|||||||
let file = docs
|
let file = docs
|
||||||
.get_document(&path_uri)
|
.get_document(&path_uri)
|
||||||
.ok_or_else(|| miette!("\nFailed to get document"))?;
|
.ok_or_else(|| miette!("\nFailed to get document"))?;
|
||||||
let range = span_to_range(&span, file, file_offset);
|
let range = span_to_range(&span, file, file_span.start);
|
||||||
let response = PrepareRenameResponse::Range(range);
|
let response = PrepareRenameResponse::Range(range);
|
||||||
self.connection
|
self.connection
|
||||||
.sender
|
.sender
|
||||||
@ -233,20 +260,24 @@ impl LanguageServer {
|
|||||||
}))
|
}))
|
||||||
.into_diagnostic()?;
|
.into_diagnostic()?;
|
||||||
|
|
||||||
// have to clone it again in order to move to another thread
|
|
||||||
let engine_state = self.new_engine_state();
|
|
||||||
let current_workspace_folder = self
|
let current_workspace_folder = self
|
||||||
.get_workspace_folder_by_uri(&path_uri)
|
.get_workspace_folder_by_uri(&path_uri)
|
||||||
.ok_or_else(|| miette!("\nCurrent file is not in any workspace"))?;
|
.ok_or_else(|| miette!("\nCurrent file is not in any workspace"))?;
|
||||||
// now continue parsing on other files in the workspace
|
// now continue parsing on other files in the workspace
|
||||||
|
let id_tracker = IDTracker {
|
||||||
|
id,
|
||||||
|
span,
|
||||||
|
file_span,
|
||||||
|
name: String::from_utf8_lossy(working_set.get_span_contents(span)).to_string(),
|
||||||
|
renewed: false,
|
||||||
|
};
|
||||||
self.channels = self
|
self.channels = self
|
||||||
.find_reference_in_workspace(
|
.find_reference_in_workspace(
|
||||||
engine_state,
|
engine_state,
|
||||||
current_workspace_folder,
|
current_workspace_folder,
|
||||||
id,
|
|
||||||
span,
|
|
||||||
ProgressToken::Number(0),
|
ProgressToken::Number(0),
|
||||||
"Preparing rename ...".to_string(),
|
"Preparing rename ...".to_string(),
|
||||||
|
id_tracker,
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -256,7 +287,7 @@ impl LanguageServer {
|
|||||||
working_set: &mut StateWorkingSet,
|
working_set: &mut StateWorkingSet,
|
||||||
file: &FullTextDocument,
|
file: &FullTextDocument,
|
||||||
fp: &Path,
|
fp: &Path,
|
||||||
id: &Id,
|
id_tracker: &mut IDTracker,
|
||||||
) -> Option<Vec<Span>> {
|
) -> Option<Vec<Span>> {
|
||||||
let block = nu_parser::parse(
|
let block = nu_parser::parse(
|
||||||
working_set,
|
working_set,
|
||||||
@ -264,7 +295,25 @@ impl LanguageServer {
|
|||||||
file.get_content(None).as_bytes(),
|
file.get_content(None).as_bytes(),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
let references: Vec<Span> = find_reference_by_id(&block, working_set, id);
|
// NOTE: Renew the id if there's a module with the same span as the original file.
|
||||||
|
// This requires that the initial parsing results get merged in the engine_state,
|
||||||
|
// typically they're cached with diagnostics before the prepare_rename/references requests,
|
||||||
|
// so that we don't need to clone and merge delta again.
|
||||||
|
if (!id_tracker.renewed)
|
||||||
|
&& working_set
|
||||||
|
.find_module_by_span(id_tracker.file_span)
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
if let Some(new_block) = working_set.find_block_by_span(id_tracker.file_span) {
|
||||||
|
if let Some((new_id, _)) =
|
||||||
|
ast::find_id(&new_block, working_set, &id_tracker.span.start)
|
||||||
|
{
|
||||||
|
id_tracker.id = new_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id_tracker.renewed = true;
|
||||||
|
}
|
||||||
|
let references: Vec<Span> = find_reference_by_id(&block, working_set, &id_tracker.id);
|
||||||
|
|
||||||
// add_block to avoid repeated parsing
|
// add_block to avoid repeated parsing
|
||||||
working_set.add_block(block);
|
working_set.add_block(block);
|
||||||
@ -304,10 +353,9 @@ impl LanguageServer {
|
|||||||
&self,
|
&self,
|
||||||
engine_state: EngineState,
|
engine_state: EngineState,
|
||||||
current_workspace_folder: WorkspaceFolder,
|
current_workspace_folder: WorkspaceFolder,
|
||||||
id: Id,
|
|
||||||
span: Span,
|
|
||||||
token: ProgressToken,
|
token: ProgressToken,
|
||||||
message: String,
|
message: String,
|
||||||
|
mut id_tracker: IDTracker,
|
||||||
) -> Result<(
|
) -> Result<(
|
||||||
crossbeam_channel::Sender<bool>,
|
crossbeam_channel::Sender<bool>,
|
||||||
Arc<crossbeam_channel::Receiver<InternalMessage>>,
|
Arc<crossbeam_channel::Receiver<InternalMessage>>,
|
||||||
@ -333,7 +381,7 @@ impl LanguageServer {
|
|||||||
.filter_map(|p| p.ok())
|
.filter_map(|p| p.ok())
|
||||||
.collect();
|
.collect();
|
||||||
let len = scripts.len();
|
let len = scripts.len();
|
||||||
let definition_span = Self::find_definition_span_by_id(&working_set, &id);
|
let definition_span = Self::find_definition_span_by_id(&working_set, &id_tracker.id);
|
||||||
|
|
||||||
for (i, fp) in scripts.iter().enumerate() {
|
for (i, fp) in scripts.iter().enumerate() {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -363,9 +411,7 @@ impl LanguageServer {
|
|||||||
};
|
};
|
||||||
// skip if the file does not contain what we're looking for
|
// skip if the file does not contain what we're looking for
|
||||||
let content_string = String::from_utf8_lossy(&bytes);
|
let content_string = String::from_utf8_lossy(&bytes);
|
||||||
let text_to_search =
|
if !content_string.contains(&id_tracker.name) {
|
||||||
String::from_utf8_lossy(working_set.get_span_contents(span));
|
|
||||||
if !content_string.contains(text_to_search.as_ref()) {
|
|
||||||
// progress without any data
|
// progress without any data
|
||||||
data_sender
|
data_sender
|
||||||
.send(InternalMessage::OnGoing(token.clone(), percentage))
|
.send(InternalMessage::OnGoing(token.clone(), percentage))
|
||||||
@ -374,17 +420,17 @@ impl LanguageServer {
|
|||||||
}
|
}
|
||||||
&FullTextDocument::new("nu".to_string(), 0, content_string.into())
|
&FullTextDocument::new("nu".to_string(), 0, content_string.into())
|
||||||
};
|
};
|
||||||
let _ = Self::find_reference_in_file(&mut working_set, file, fp, &id).map(
|
let _ = Self::find_reference_in_file(&mut working_set, file, fp, &mut id_tracker)
|
||||||
|mut refs| {
|
.map(|mut refs| {
|
||||||
let file_span = working_set
|
let file_span = working_set
|
||||||
.get_span_for_filename(fp.to_string_lossy().as_ref())
|
.get_span_for_filename(fp.to_string_lossy().as_ref())
|
||||||
.unwrap_or(Span::unknown());
|
.unwrap_or(Span::unknown());
|
||||||
if let Some(extra_span) = Self::reference_not_in_ast(
|
if let Some(extra_span) = Self::reference_not_in_ast(
|
||||||
&id,
|
&id_tracker.id,
|
||||||
&working_set,
|
&working_set,
|
||||||
definition_span,
|
definition_span,
|
||||||
file_span,
|
file_span,
|
||||||
span,
|
id_tracker.span,
|
||||||
) {
|
) {
|
||||||
if !refs.contains(&extra_span) {
|
if !refs.contains(&extra_span) {
|
||||||
refs.push(extra_span)
|
refs.push(extra_span)
|
||||||
@ -400,8 +446,7 @@ impl LanguageServer {
|
|||||||
data_sender
|
data_sender
|
||||||
.send(InternalMessage::OnGoing(token.clone(), percentage))
|
.send(InternalMessage::OnGoing(token.clone(), percentage))
|
||||||
.ok();
|
.ok();
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
data_sender
|
data_sender
|
||||||
.send(InternalMessage::Finished(token.clone()))
|
.send(InternalMessage::Finished(token.clone()))
|
||||||
|
2
tests/fixtures/lsp/completion/command.nu
vendored
2
tests/fixtures/lsp/completion/command.nu
vendored
@ -1,6 +1,6 @@
|
|||||||
config n
|
config n
|
||||||
config n foo bar -
|
config n foo bar -
|
||||||
config n foo bar l --l
|
config n foo bar c --l
|
||||||
|
|
||||||
# detail
|
# detail
|
||||||
def "config n foo bar" [
|
def "config n foo bar" [
|
||||||
|
2
tests/fixtures/lsp/completion/fallback.nu
vendored
2
tests/fixtures/lsp/completion/fallback.nu
vendored
@ -3,6 +3,6 @@ let greeting = "Hello"
|
|||||||
echo $gre
|
echo $gre
|
||||||
| st
|
| st
|
||||||
|
|
||||||
ls l
|
ls c
|
||||||
|
|
||||||
$greeting not-h
|
$greeting not-h
|
||||||
|
Loading…
x
Reference in New Issue
Block a user