Skip to content

Commit

Permalink
Rename LSP action (#1811)
Browse files Browse the repository at this point in the history
* Add rename support

(Cross-file renaming is only working in one direction)

* Fix some rebase issues

* Insta review

* Make the test deterministic
  • Loading branch information
jneem committed Feb 9, 2024
1 parent b57f74b commit 839a118
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 5 deletions.
6 changes: 4 additions & 2 deletions lsp/lsp-harness/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ use lsp_types::{
notification::{Notification, PublishDiagnostics},
request::{
Completion, DocumentSymbolRequest, Formatting, GotoDefinition, HoverRequest, References,
Request as LspRequest,
Rename, Request as LspRequest,
},
CompletionParams, DocumentFormattingParams, DocumentSymbolParams, GotoDefinitionParams,
HoverParams, PublishDiagnosticsParams, ReferenceParams, Url,
HoverParams, PublishDiagnosticsParams, ReferenceParams, RenameParams, Url,
};
pub use output::LspDebug;
use serde::Deserialize;
Expand Down Expand Up @@ -43,6 +43,7 @@ pub enum Request {
Completion(CompletionParams),
Formatting(DocumentFormattingParams),
Hover(HoverParams),
Rename(RenameParams),
Symbols(DocumentSymbolParams),
}

Expand Down Expand Up @@ -142,6 +143,7 @@ impl TestHarness {
Request::Formatting(f) => self.request::<Formatting>(f),
Request::Hover(h) => self.request::<HoverRequest>(h),
Request::References(r) => self.request::<References>(r),
Request::Rename(r) => self.request::<Rename>(r),
Request::Symbols(s) => self.request::<DocumentSymbolRequest>(s),
}
}
Expand Down
24 changes: 23 additions & 1 deletion lsp/lsp-harness/src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use std::io::Write;

use lsp_types::{DocumentSymbolResponse, GotoDefinitionResponse};
use lsp_types::{DocumentSymbolResponse, GotoDefinitionResponse, WorkspaceEdit};

pub trait LspDebug {
fn debug(&self, w: impl Write) -> std::io::Result<()>;
Expand Down Expand Up @@ -54,6 +54,12 @@ impl<T: LspDebug> LspDebug for Vec<T> {
}
}

impl<S: LspDebug, T: LspDebug> LspDebug for (S, T) {
fn debug(&self, mut w: impl Write) -> std::io::Result<()> {
write!(w, "({}, {})", self.0.debug_str(), self.1.debug_str())
}
}

impl LspDebug for lsp_types::Range {
fn debug(&self, mut w: impl Write) -> std::io::Result<()> {
write!(
Expand All @@ -64,6 +70,12 @@ impl LspDebug for lsp_types::Range {
}
}

impl LspDebug for lsp_types::Url {
fn debug(&self, mut w: impl Write) -> std::io::Result<()> {
write!(w, "{}", self.as_str())
}
}

impl LspDebug for lsp_types::Location {
fn debug(&self, mut w: impl Write) -> std::io::Result<()> {
write!(w, "{}:{}", self.uri.as_str(), self.range.debug_str())
Expand Down Expand Up @@ -188,3 +200,13 @@ impl LspDebug for DocumentSymbolResponse {
}
}
}

impl LspDebug for WorkspaceEdit {
fn debug(&self, w: impl Write) -> std::io::Result<()> {
let changes = self.changes.clone();
let mut changes = changes.into_iter().flatten().collect::<Vec<_>>();
// Sort the keys, for determinism
changes.sort_by_key(|(url, _)| url.clone());
changes.debug(w)
}
}
1 change: 1 addition & 0 deletions lsp/nls/src/requests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod completion;
pub mod goto;
pub mod hover;
pub mod rename;
pub mod symbols;

#[cfg(feature = "format")]
Expand Down
56 changes: 56 additions & 0 deletions lsp/nls/src/requests/rename.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::collections::HashMap;

use lsp_server::{RequestId, Response, ResponseError};
use lsp_types::{Range, RenameParams, TextEdit, Url, WorkspaceEdit};

use crate::cache::CacheExt as _;
use crate::diagnostic::LocationCompat;
use crate::server::Server;

pub fn handle_rename(
params: RenameParams,
id: RequestId,
server: &mut Server,
) -> Result<(), ResponseError> {
let pos = server.cache.position(&params.text_document_position)?;

let ident = server.lookup_ident_by_position(pos)?;
let term = server.lookup_term_by_position(pos)?;
let mut def_locs = term
.map(|term| server.get_defs(term, ident))
.unwrap_or_default();

def_locs.extend(ident.and_then(|id| id.pos.into_opt()));

let mut all_positions: Vec<_> = def_locs
.iter()
.flat_map(|id| server.analysis.get_usages(id))
.filter_map(|id| id.pos.into_opt())
.chain(def_locs.iter().copied())
.chain(def_locs.iter().flat_map(|def| server.get_field_refs(*def)))
.collect();

// Sort in some arbitrary order, for determinism and deduplication.
all_positions.sort_by_key(|span| (span.src_id, span.start, span.end));
all_positions.dedup();

// Group edits by file
let mut changes = HashMap::<Url, Vec<TextEdit>>::new();
for pos in all_positions {
let url = Url::from_file_path(server.cache.files().name(pos.src_id)).unwrap();
changes.entry(url).or_default().push(TextEdit {
range: Range::from_span(&pos, server.cache.files()),
new_text: params.new_name.clone(),
});
}

server.reply(Response::new_ok(
id,
WorkspaceEdit {
changes: Some(changes),
document_changes: None,
change_annotations: None,
},
));
Ok(())
}
11 changes: 9 additions & 2 deletions lsp/nls/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use lsp_types::{
CodeActionParams, CompletionOptions, CompletionParams, DidChangeTextDocumentParams,
DidOpenTextDocumentParams, DocumentFormattingParams, DocumentSymbolParams,
ExecuteCommandParams, GotoDefinitionParams, HoverOptions, HoverParams, HoverProviderCapability,
OneOf, PublishDiagnosticsParams, ReferenceParams, ServerCapabilities,
OneOf, PublishDiagnosticsParams, ReferenceParams, RenameParams, ServerCapabilities,
TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, Url,
WorkDoneProgressOptions,
};
Expand All @@ -39,7 +39,7 @@ use crate::{
field_walker::{Def, FieldResolver},
identifier::LocIdent,
pattern::Bindings,
requests::{completion, formatting, goto, hover, symbols},
requests::{completion, formatting, goto, hover, rename, symbols},
trace::Trace,
};

Expand Down Expand Up @@ -93,6 +93,7 @@ impl Server {
commands: vec!["eval".to_owned()],
..Default::default()
}),
rename_provider: Some(OneOf::Left(true)),
..ServerCapabilities::default()
}
}
Expand Down Expand Up @@ -288,6 +289,12 @@ impl Server {
command::handle_command(params, req.id.clone(), self)
}

Rename::METHOD => {
debug!("rename");
let params: RenameParams = serde_json::from_value(req.params).unwrap();
rename::handle_rename(params, req.id.clone(), self)
}

_ => Ok(()),
};

Expand Down
55 changes: 55 additions & 0 deletions lsp/nls/tests/inputs/rename.ncl
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
### /base.ncl
let foo = import "dep.ncl" in
{
x = foo.included,
y = { foo = x },
}
### /dep.ncl
{
included = 5
}
### # Rename foo to a bar (but not the "foo" in "foo = x")
### [[request]]
### type = "Rename"
### textDocument.uri = "file:///base.ncl"
### position = { line = 0, character = 5 }
### newName = "bar"
###
### [[request]]
### type = "Rename"
### textDocument.uri = "file:///base.ncl"
### position = { line = 2, character = 9 }
### newName = "bar"
###
### # Rename "foo" in "foo = x" (shouldn't rename the others)
### [[request]]
### type = "Rename"
### textDocument.uri = "file:///base.ncl"
### position = { line = 3, character = 11 }
### newName = "baz"
###
### # Rename x to y
### [[request]]
### type = "Rename"
### textDocument.uri = "file:///base.ncl"
### position = { line = 2, character = 4 }
### newName = "y"
###
### [[request]]
### type = "Rename"
### textDocument.uri = "file:///base.ncl"
### position = { line = 3, character = 16 }
### newName = "y"
###
### # Cross-file rename
### [[request]]
### type = "Rename"
### textDocument.uri = "file:///base.ncl"
### position = { line = 2, character = 15 }
### newName = "dependency"
###
### [[request]]
### type = "Rename"
### textDocument.uri = "file:///dep.ncl"
### position = { line = 1, character = 5 }
### newName = "dependency"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
source: lsp/nls/tests/main.rs
expression: output
---
[(file:///base.ncl, [<0:4-0:7> bar, <2:8-2:11> bar])]
[(file:///base.ncl, [<0:4-0:7> bar, <2:8-2:11> bar])]
[(file:///base.ncl, [<3:10-3:13> baz])]
[(file:///base.ncl, [<2:4-2:5> y, <3:16-3:17> y])]
[(file:///base.ncl, [<2:4-2:5> y, <3:16-3:17> y])]
[(file:///base.ncl, [<2:12-2:20> dependency]), (file:///dep.ncl, [<1:2-1:10> dependency])]
[(file:///base.ncl, [<2:12-2:20> dependency]), (file:///dep.ncl, [<1:2-1:10> dependency])]

0 comments on commit 839a118

Please sign in to comment.