Skip to content

Commit

Permalink
Feat: rename
Browse files Browse the repository at this point in the history
  • Loading branch information
maurobalbi committed Feb 13, 2024
1 parent 15cfef8 commit 0ad1d19
Show file tree
Hide file tree
Showing 15 changed files with 443 additions and 51 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## v0.1.0

### New Features

- Renaming

### Improved

- Improve Reference for Variants, add better tests
- Render Documentation for Custom Types


## v0.0.9

### Added
Expand Down
9 changes: 5 additions & 4 deletions crates/glas/src/capabilities.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use lsp_types::{
CompletionOptions, HoverProviderCapability, InitializeParams, OneOf, SemanticTokensLegend,
SemanticTokensOptions, SemanticTokensServerCapabilities, ServerCapabilities,
TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
WorkDoneProgressOptions,
CompletionOptions, HoverProviderCapability, InitializeParams, OneOf, RenameOptions, SemanticTokensLegend, SemanticTokensOptions, SemanticTokensServerCapabilities, ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, WorkDoneProgressOptions
};

use crate::semantic_tokens::{SEMANTIC_TOKEN_MODIFIERS, SEMANTIC_TOKEN_TYPES};
Expand Down Expand Up @@ -66,6 +63,10 @@ pub(crate) fn negotiate_capabilities(
trigger_characters: Some(vec![".".into(), "@".into()]),
..Default::default()
}),
rename_provider: Some(OneOf::Right(RenameOptions {
prepare_provider: Some(true),
work_done_progress_options: WorkDoneProgressOptions::default(),
})),
semantic_tokens_provider: Some(SemanticTokensServerCapabilities::SemanticTokensOptions(
SemanticTokensOptions {
work_done_progress_options: WorkDoneProgressOptions::default(),
Expand Down
53 changes: 49 additions & 4 deletions crates/glas/src/convert.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use crate::{semantic_tokens, LineMap, Result, Vfs};
use async_lsp::{ErrorCode, ResponseError};
use ide::{
CompletionItem, CompletionItemKind, CompletionRelevance, Diagnostic, DiagnosticKind, FileId,
FilePos, FileRange, HlRange, HlRelated, HoverResult, Severity,
CompletionItem, CompletionItemKind, CompletionRelevance, Diagnostic, DiagnosticKind, FileId, FilePos, FileRange, HlRange, HlRelated, HoverResult, Severity, TextEdit, WorkspaceEdit
};
use lsp::{
DiagnosticTag, DocumentHighlight, DocumentHighlightKind, Documentation, Hover, MarkupContent,
MarkupKind, SemanticToken,
DiagnosticTag, DocumentHighlight, DocumentHighlightKind, Documentation, Hover, MarkupContent, MarkupKind, PrepareRenameResponse, SemanticToken
};
use lsp_types::{
self as lsp, DiagnosticRelatedInformation, DiagnosticSeverity, Location, NumberOrString,
Expand Down Expand Up @@ -196,6 +195,22 @@ pub(crate) fn to_diagnostics(
ret
}

pub(crate) fn to_rename_error(message: String) -> ResponseError {
ResponseError::new(ErrorCode::REQUEST_FAILED, message)
}

pub(crate) fn to_prepare_rename_response(
line_map: &LineMap,
range: TextRange,
text: String,
) -> PrepareRenameResponse {
let range = to_range(line_map, range);
PrepareRenameResponse::RangeWithPlaceholder {
range,
placeholder: text,
}
}

pub(crate) fn to_document_highlight(
line_map: &LineMap,
hls: &[HlRelated],
Expand All @@ -212,6 +227,36 @@ pub(crate) fn to_document_highlight(
.collect()
}

pub(crate) fn to_workspace_edit(vfs: &Vfs, ws_edit: WorkspaceEdit) -> lsp::WorkspaceEdit {
let content_edits = ws_edit
.content_edits
.into_iter()
.map(|(file, edits)| {
let uri = vfs.uri_for_file(file);
let edits = edits
.into_iter()
.map(|edit| {
let line_map = vfs.line_map_for_file(file);
to_text_edit(&line_map, edit)
})
.collect();
(uri, edits)
})
.collect();
lsp::WorkspaceEdit {
changes: Some(content_edits),
document_changes: None,
change_annotations: None,
}
}

pub(crate) fn to_text_edit(line_map: &LineMap, edit: TextEdit) -> lsp::TextEdit {
lsp::TextEdit {
range: to_range(line_map, edit.delete),
new_text: edit.insert.into(),
}
}

pub(crate) fn to_semantic_tokens(line_map: &LineMap, hls: &[HlRange]) -> Vec<SemanticToken> {
// We must not exceed the last line.
let last_line = line_map.last_line();
Expand Down
28 changes: 24 additions & 4 deletions crates/glas/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ use crate::{convert, lsp_ext::SyntaxTreeParams, StateSnapshot};
use anyhow::{ensure, Context, Result};
use ide::{FileRange, GotoDefinitionResult};
use lsp_types::{
CompletionParams, CompletionResponse, Diagnostic, DocumentFormattingParams, DocumentHighlight,
DocumentHighlightParams, GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverParams,
Location, Position, Range, ReferenceParams, SemanticTokens, SemanticTokensParams,
SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, TextEdit, Url,
CompletionParams, CompletionResponse, Diagnostic, DocumentFormattingParams, DocumentHighlight, DocumentHighlightParams, GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverParams, Location, Position, PrepareRenameResponse, Range, ReferenceParams, RenameParams, SemanticTokens, SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, TextDocumentPositionParams, TextEdit, Url, WorkspaceEdit
};

const MAX_DIAGNOSTICS_CNT: usize = 128;
Expand Down Expand Up @@ -165,6 +162,29 @@ pub(crate) fn references(
Ok(Some(locs))
}

pub(crate) fn prepare_rename(
snap: StateSnapshot,
params: TextDocumentPositionParams,
) -> Result<Option<PrepareRenameResponse>> {
let (fpos, line_map) = convert::from_file_pos(&snap.vfs(), &params)?;
let (range, text) = snap
.analysis
.prepare_rename(fpos)?
.map_err(convert::to_rename_error)?;
let resp = convert::to_prepare_rename_response(&line_map, range, text.into());
Ok(Some(resp))
}

pub(crate) fn rename(snap: StateSnapshot, params: RenameParams) -> Result<Option<WorkspaceEdit>> {
let (fpos, _) = convert::from_file_pos(&snap.vfs(), &params.text_document_position)?;
let ws_edit = snap
.analysis
.rename(fpos, &params.new_name)?
.map_err(convert::to_rename_error)?;
let resp = convert::to_workspace_edit(&snap.vfs(), ws_edit);
Ok(Some(resp))
}

pub(crate) fn syntax_tree(snap: StateSnapshot, params: SyntaxTreeParams) -> Result<String> {
let (file, _) = convert::from_file(&snap.vfs(), &params.text_document)?;
let syntax_tree = snap.analysis.syntax_tree(file)?;
Expand Down
2 changes: 2 additions & 0 deletions crates/glas/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ impl Server {
.request_snap::<req::HoverRequest>(handler::hover)
.request_snap::<req::DocumentHighlightRequest>(handler::document_highlight)
.request_snap::<req::References>(handler::references)
.request_snap::<req::PrepareRenameRequest>(handler::prepare_rename)
.request_snap::<req::Rename>(handler::rename)
.request_snap::<lsp_ext::SyntaxTree>(handler::syntax_tree)
.request_snap::<req::SemanticTokensFullRequest>(handler::semantic_token_full)
.request_snap::<req::SemanticTokensRangeRequest>(handler::semantic_token_range)
Expand Down
3 changes: 2 additions & 1 deletion crates/ide/src/def/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,8 @@ impl Import {
pub fn import_from_module_name(self, db: &dyn DefDatabase) -> SmolStr {
let import = db.lookup_intern_import(self.id);
let module_idx = self.data(db).module;
db.module_items(import.file_id)[module_idx].accessor.clone()
let module = &db.module_items(import.file_id)[module_idx];
module.as_name.clone().unwrap_or_else(|| module.accessor.clone())
}

pub fn imported_from_module(self, db: &dyn DefDatabase) -> Option<FileId> {
Expand Down
16 changes: 8 additions & 8 deletions crates/ide/src/def/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,15 @@ impl<'a> FindUsages<'a> {
// This is currently handled by the last step in highlight related
fn found_name(
&self,
_name_ref: &ast::Name,
_sink: &mut dyn FnMut(FileId, TextRange) -> bool,
name: &ast::Name,
sink: &mut dyn FnMut(FileId, TextRange) -> bool,
) -> bool {
// if let Some(def) = classify_node(self.sema, name_ref.syntax()) {
// if self.def == def {
// let file_id = self.sema.find_file(name_ref.syntax()).file_id;
// return sink(file_id, name_ref.syntax().text_range())
// }
// }
if let Some(def) = classify_node(self.sema, name.syntax()) {
if self.def == def {
let file_id = self.sema.find_file(name.syntax()).file_id;
return sink(file_id, name.syntax().text_range())
}
}
false
}
}
Expand Down
34 changes: 34 additions & 0 deletions crates/ide/src/ide/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,23 @@ pub type <Test>"#
],
)
}

#[test]
fn import_aliased_module() {
check(
r#"
#- test.gleam
pub type Test
#- test2.gleam
import test.{type $0Test} as t
"#,
expect![
r#"
pub type <Test>"#
],
)
}

#[test]
fn resolve_qualified() {
Expand Down Expand Up @@ -337,4 +354,21 @@ fn main() {
],
)
}

#[test]
fn resolve_imported_fn() {
check(
r#"
#- test.gleam
pub fn testfn() {}
#- test2.gleam
import test.{$0testfn}
"#,
expect![
r#"
pub fn <testfn>() {}"#
],
)
}
}
15 changes: 3 additions & 12 deletions crates/ide/src/ide/highlight_related.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,6 @@ pub(crate) fn highlight_related(db: &dyn TyDatabase, fpos: FilePos) -> Option<Ve
})
}

if let Some(nav) = def.to_nav(db) {
if fpos.file_id == nav.file_id {
res.insert(HlRelated {
range: nav.focus_range,
is_definition: true,
});
}
};

Some(res.into_iter().collect())
}

Expand Down Expand Up @@ -81,19 +72,19 @@ mod tests {
fn definition() {
check(
"fn case_hl() { case 1 { a -> $0a } }",
expect!["fn case_hl() { case 1 { <<a>> -> <a> } }"],
expect!["fn case_hl() { case 1 { <a> -> <a> } }"],
);
check(
"fn highlight(a) { $0a }",
expect!["fn highlight(<<a>>) { <a> }"],
expect!["fn highlight(<a>) { <a> }"],
);
}

#[test]
fn hl_field() {
check(
"type Wobblie { Variant1(name: Int) Variant2(name: Int) } fn hl(a: Wobblie) { a.$0name }",
expect!["type Wobblie { Variant1(<<name: Int>>) Variant2(name: Int) } fn hl(a: Wobblie) { a.<name> }"],
expect!["type Wobblie { Variant1(<name>: Int) Variant2(<name>: Int) } fn hl(a: Wobblie) { a.<name> }"],
);
}
}
17 changes: 17 additions & 0 deletions crates/ide/src/ide/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ mod goto_definition;
mod highlight_related;
mod hover;
mod references;
mod rename;
mod semantic_highlighting;
mod syntax_tree;

use crate::base::SourceDatabaseStorage;
use crate::def::{DefDatabaseStorage, InternDatabaseStorage};
use crate::text_edit::WorkspaceEdit;
use crate::ty::{TyDatabase, TyDatabaseStorage};
use crate::{
Change, DefDatabase, Diagnostic, FileId, FilePos, FileRange, FileSet, SourceDatabase,
SourceRoot, VfsPath,
};
use salsa::{Database, Durability, ParallelDatabase};
use smol_str::SmolStr;
use std::fmt;
use syntax::TextRange;

Expand All @@ -35,6 +38,8 @@ pub struct NavigationTarget {

pub use salsa::Cancelled;

use self::rename::RenameResult;

pub type Cancellable<T> = Result<T, Cancelled>;

#[salsa::database(
Expand Down Expand Up @@ -179,7 +184,19 @@ impl Analysis {
pub fn references(&self, pos: FilePos) -> Cancellable<Option<Vec<FileRange>>> {
self.with_db(|db| references::references(db, pos))
}

pub fn prepare_rename(&self, fpos: FilePos) -> Cancellable<RenameResult<(TextRange, SmolStr)>> {
self.with_db(|db| rename::prepare_rename(db, fpos))
}

pub fn rename(
&self,
fpos: FilePos,
new_name: &str,
) -> Cancellable<RenameResult<WorkspaceEdit>> {
self.with_db(|db| rename::rename(db, fpos, new_name))
}

pub fn syntax_tree(&self, file_id: FileId) -> Cancellable<String> {
self.with_db(|db| syntax_tree::syntax_tree(db, file_id))
}
Expand Down
Loading

0 comments on commit 0ad1d19

Please sign in to comment.