Repository: nushell/nushell
File: crates/nu-lsp/src/workspace.rs (Rust)

Code before:

/// Message sent from background thread to main
#[derive(Debug)]
pub(crate) enum InternalMessage {
    RangeMessage(RangePerDoc),
    Cancelled(ProgressToken),
    Finished(ProgressToken),
    OnGoing(ProgressToken, u32),
}

fn find_nu_scripts_in_folder(folder_uri: &Uri) -> Result<nu_glob::Paths> {
    let path = uri_to_path(folder_uri);
    if !path.is_dir() {
        return Err(miette!("\nworkspace folder does not exist."));
    }
    let pattern = format!("{}/**/*.nu", path.to_string_lossy());
    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.
/// The fake path stops that with `ParseError::ModuleNotFound`,
/// which seems benign for tasks like references/renaming.
///
/// FIXME: cross-file shadowing can still cause false-positive/false-negative cases
fn pseudo_path() -> Result<PathBuf> {
    let mut path = std::env::current_dir().into_diagnostic()?;
    path.push("non-existing-dir");
    path.push("non-existing-file");
    Ok(path)
}

impl LanguageServer {
    /// Get initial workspace folders from initialization response
    pub(crate) fn initialize_workspace_folders(
        &mut self,
        init_params: serde_json::Value,
    ) -> Option<()> {
        if let Some(array) = init_params.get("workspaceFolders") {
            let folders: Vec<WorkspaceFolder> = serde_json::from_value(array.clone()).ok()?;
            for folder in folders {
                self.workspace_folders.insert(folder.name.clone(), folder);
            }
        }
        Some(())
    }

    /// Highlight all occurrences of the text at cursor, in current file
    pub(crate) fn document_highlight(
        &mut self,

Review comment (bug):
This note explains the bug mentioned [here](https://github.com/nushell/nushell/pull/15470#issuecomment-2771804887).

I've tried other methods like creating a module from existing block, but they ended up making it worse (either crash or totally wrong spans).
This hack, although seems dangerous, actually behaves closest to ideal according to my tests.

I'd like to leave it in this PR as a stopgap while searching for better solutions.



Code after:

/// Message sent from background thread to main
#[derive(Debug)]
pub(crate) enum InternalMessage {
    RangeMessage(RangePerDoc),
    Cancelled(ProgressToken),
    Finished(ProgressToken),
    OnGoing(ProgressToken, u32),
}

fn find_nu_scripts_in_folder(folder_uri: &Uri) -> Result<nu_glob::Paths> {
    let path = uri_to_path(folder_uri);
    if !path.is_dir() {
        return Err(miette!("\nworkspace folder does not exist."));
    }
    let pattern = format!("{}/**/*.nu", path.to_string_lossy());
    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 {
    /// Get initial workspace folders from initialization response
    pub(crate) fn initialize_workspace_folders(
        &mut self,
        init_params: serde_json::Value,
    ) -> Option<()> {
        if let Some(array) = init_params.get("workspaceFolders") {
            let folders: Vec<WorkspaceFolder> = serde_json::from_value(array.clone()).ok()?;
            for folder in folders {
                self.workspace_folders.insert(folder.name.clone(), folder);
            }
        }