Skip to content

Commit 1bdc896

Browse files
committed
Implement rename refactor
1 parent edeeb7a commit 1bdc896

File tree

6 files changed

+107
-15
lines changed

6 files changed

+107
-15
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ I very much appreciate help from other people especially regarding semantic anal
2424
- From component declaration to matching entity by default binding
2525
- From entity to matching component declaration by default binding
2626
- Supports hovering symbols
27+
- Rename symbol
2728

2829
## Trying it out
2930
A language server is never used directly by the end user and it is integrated into different editor plugins. The ones I know about are listed here.

vhdl_lang/src/analysis/root.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,20 @@ impl DesignRoot {
365365
///
366366
/// If the character value is greater than the line length it defaults back to the
367367
/// line length.
368-
pub fn search_reference<'a>(&'a self, source: &Source, cursor: Position) -> Option<EntRef<'a>> {
368+
pub fn item_at_cursor<'a>(
369+
&'a self,
370+
source: &Source,
371+
cursor: Position,
372+
) -> Option<(SrcPos, EntRef<'a>)> {
369373
let mut searcher = ItemAtCursor::new(source, cursor);
370374
let _ = self.search(&mut searcher);
371-
let id = searcher.result?;
375+
let (pos, id) = searcher.result?;
372376
let ent = self.get_ent(id);
377+
Some((pos, ent))
378+
}
379+
380+
pub fn search_reference<'a>(&'a self, source: &Source, cursor: Position) -> Option<EntRef<'a>> {
381+
let (_, ent) = self.item_at_cursor(source, cursor)?;
373382
Some(ent)
374383
}
375384

vhdl_lang/src/ast/search.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,7 +1315,7 @@ impl Search for CaseStatement {
13151315
pub struct ItemAtCursor {
13161316
source: Source,
13171317
cursor: Position,
1318-
pub result: Option<EntityId>,
1318+
pub result: Option<(SrcPos, EntityId)>,
13191319
}
13201320

13211321
impl ItemAtCursor {
@@ -1333,11 +1333,16 @@ impl ItemAtCursor {
13331333
pos.start() <= self.cursor && self.cursor <= pos.end()
13341334
}
13351335

1336-
fn is_inside_opt(&self, pos: Option<&SrcPos>) -> bool {
1337-
if let Some(pos) = pos {
1338-
self.is_inside(pos)
1336+
fn search_decl_pos(&mut self, pos: &SrcPos, decl: &FoundDeclaration) -> SearchState {
1337+
if self.is_inside(pos) {
1338+
if let Some(id) = decl.ent_id() {
1339+
self.result = Some((pos.clone(), id));
1340+
Finished(Found)
1341+
} else {
1342+
Finished(NotFound)
1343+
}
13391344
} else {
1340-
false
1345+
NotFinished
13411346
}
13421347
}
13431348
}
@@ -1355,13 +1360,12 @@ impl Searcher for ItemAtCursor {
13551360

13561361
fn search_decl(&mut self, decl: FoundDeclaration) -> SearchState {
13571362
let pos = decl.pos();
1358-
if self.is_inside(pos) || self.is_inside_opt(decl.end_ident_pos()) {
1359-
if let Some(id) = decl.ent_id() {
1360-
self.result = Some(id);
1361-
Finished(Found)
1362-
} else {
1363-
Finished(NotFound)
1364-
}
1363+
if let Finished(res) = self.search_decl_pos(pos, &decl) {
1364+
return Finished(res);
1365+
}
1366+
1367+
if let Some(end_pos) = decl.end_ident_pos() {
1368+
self.search_decl_pos(end_pos, &decl)
13651369
} else {
13661370
NotFinished
13671371
}
@@ -1370,7 +1374,7 @@ impl Searcher for ItemAtCursor {
13701374
fn search_pos_with_ref(&mut self, pos: &SrcPos, reference: &mut Reference) -> SearchState {
13711375
if self.is_inside(pos) {
13721376
if let Some(id) = reference {
1373-
self.result = Some(*id);
1377+
self.result = Some((pos.clone(), *id));
13741378
Finished(Found)
13751379
} else {
13761380
Finished(NotFound)

vhdl_lang/src/project.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,14 @@ impl Project {
233233
Some(ent.declaration())
234234
}
235235

236+
pub fn item_at_cursor<'a>(
237+
&'a self,
238+
source: &Source,
239+
cursor: Position,
240+
) -> Option<(SrcPos, EntRef<'a>)> {
241+
self.root.item_at_cursor(source, cursor)
242+
}
243+
236244
fn get_library(&self, source: &Source) -> Option<Symbol> {
237245
let file = self.files.get(source.file_name())?;
238246
file.library_names.iter().next().cloned()

vhdl_ls/src/stdio_server.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,22 @@ impl ConnectionRpcChannel {
147147
}
148148
Err(request) => request,
149149
};
150+
let request = match extract::<request::Rename>(request) {
151+
Ok((id, params)) => {
152+
let result = server.rename(&params);
153+
self.send_response(lsp_server::Response::new_ok(id, result));
154+
return;
155+
}
156+
Err(request) => request,
157+
};
158+
let request = match extract::<request::PrepareRenameRequest>(request) {
159+
Ok((id, params)) => {
160+
let result = server.prepare_rename(&params);
161+
self.send_response(lsp_server::Response::new_ok(id, result));
162+
return;
163+
}
164+
Err(request) => request,
165+
};
150166
let request = match extract::<request::HoverRequest>(request) {
151167
Ok((id, params)) => {
152168
let result = server.text_document_hover(&params.text_document_position_params);

vhdl_ls/src/vhdl_server.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use lsp_types::*;
88

99
use fnv::FnvHashMap;
1010
use std::collections::hash_map::Entry;
11+
use std::collections::HashMap;
12+
use vhdl_lang::ast::Designator;
1113

1214
use crate::rpc_channel::SharedRpcChannel;
1315
use std::io;
@@ -117,6 +119,10 @@ impl VHDLServer {
117119
hover_provider: Some(HoverProviderCapability::Simple(true)),
118120
references_provider: Some(OneOf::Left(true)),
119121
implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
122+
rename_provider: Some(OneOf::Right(RenameOptions {
123+
prepare_provider: Some(true),
124+
work_done_progress_options: Default::default(),
125+
})),
120126
..Default::default()
121127
};
122128

@@ -365,6 +371,54 @@ impl VHDLServer {
365371
))
366372
}
367373

374+
pub fn prepare_rename(
375+
&mut self,
376+
params: &TextDocumentPositionParams,
377+
) -> Option<PrepareRenameResponse> {
378+
let source = self
379+
.project
380+
.get_source(&uri_to_file_name(&params.text_document.uri))?;
381+
382+
let (pos, ent) = self
383+
.project
384+
.item_at_cursor(&source, from_lsp_pos(params.position))?;
385+
386+
if let Designator::Identifier(_) = ent.designator() {
387+
Some(PrepareRenameResponse::Range(to_lsp_range(pos.range)))
388+
} else {
389+
// It does not make sense to rename operator symbols and character literals
390+
// Also they have different representations that would not be handled consistently
391+
// Such as function "+"(arg1, arg2 : integer) but used as foo + bar
392+
None
393+
}
394+
}
395+
396+
pub fn rename(&mut self, params: &RenameParams) -> Option<WorkspaceEdit> {
397+
let source = self.project.get_source(&uri_to_file_name(
398+
&params.text_document_position.text_document.uri,
399+
))?;
400+
401+
let ent = self.project.find_declaration(
402+
&source,
403+
from_lsp_pos(params.text_document_position.position),
404+
)?;
405+
406+
let mut changes: HashMap<Url, Vec<TextEdit>> = Default::default();
407+
408+
for srcpos in self.project.find_all_references(ent) {
409+
let loc = srcpos_to_location(&srcpos);
410+
changes.entry(loc.uri).or_default().push(TextEdit {
411+
range: loc.range,
412+
new_text: params.new_name.clone(),
413+
});
414+
}
415+
416+
Some(WorkspaceEdit {
417+
changes: Some(changes),
418+
..Default::default()
419+
})
420+
}
421+
368422
pub fn text_document_hover(&mut self, params: &TextDocumentPositionParams) -> Option<Hover> {
369423
let source = self
370424
.project

0 commit comments

Comments
 (0)