Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LSP references and document highlight #155

Merged
merged 9 commits into from Feb 27, 2022
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -70,8 +70,8 @@ Our TODO list:
* [ ] signatureHelp
* [x] ~~declaration~~, definition, ~~typeDefinition~~
* [ ] implementation
* [ ] references
* [ ] documentHighlight
* [x] references
* [x] documentHighlight
* [ ] documentSymbol
* [ ] codeAction, codeAction resolve
* [ ] codeLens, codeLens resolve, codeLens refresh
Expand Down
4 changes: 4 additions & 0 deletions new-new-packages/compiler/src/compiler/cst.rs
Expand Up @@ -275,6 +275,10 @@ impl Cst {
CstKind::Symbol { offset, value } => *offset..(*offset + value.len()),
CstKind::LeadingWhitespace { value, child } => {
let child_span = child.span();
if child_span.start < value.len() {
// TODO: Remove this when our parser no longer adds a leading newline before parsing.
return 0..child_span.end;
}
(child_span.start - value.len())..child_span.end
}
CstKind::LeadingComment { value, child } => {
Expand Down
18 changes: 14 additions & 4 deletions new-new-packages/compiler/src/compiler/cst_to_ast.rs
Expand Up @@ -87,15 +87,15 @@ impl LoweringContext {
self.create_ast(cst.id, AstKind::Int(Int(value.to_owned())))
}
CstKind::Text { value, .. } => {
let string = self.create_string(cst.id, value.to_owned());
let string = self.create_string_without_id_mapping(value.to_owned());
self.create_ast(cst.id, AstKind::Text(Text(string)))
}
CstKind::Identifier { value, .. } => {
let string = self.create_string(cst.id, value.to_owned());
let string = self.create_string_without_id_mapping(value.to_owned());
self.create_ast(cst.id, AstKind::Identifier(Identifier(string)))
}
CstKind::Symbol { value, .. } => {
let string = self.create_string(cst.id, value.to_owned());
let string = self.create_string_without_id_mapping(value.to_owned());
self.create_ast(cst.id, AstKind::Symbol(Symbol(string)))
}
CstKind::LeadingWhitespace { child, .. } => self.lower_cst(child),
Expand Down Expand Up @@ -329,9 +329,19 @@ impl LoweringContext {
value,
}
}
fn create_string_without_id_mapping(&mut self, value: String) -> AstString {
AstString {
id: self.create_next_id_without_mapping(),
value,
}
}
fn create_next_id(&mut self, cst_id: cst::Id) -> ast::Id {
let id = ast::Id(self.next_id);
let id = self.create_next_id_without_mapping();
assert!(matches!(self.id_mapping.insert(id, cst_id), None));
id
}
fn create_next_id_without_mapping(&mut self) -> ast::Id {
let id = ast::Id(self.next_id);
self.next_id += 1;
id
}
Expand Down
4 changes: 3 additions & 1 deletion new-new-packages/compiler/src/database.rs
Expand Up @@ -9,7 +9,8 @@ use crate::{
input::{GetOpenInputQuery, Input, InputDbStorage, InputWatcher},
language_server::{
folding_range::FoldingRangeDbStorage, hints::HintsDbStorage,
semantic_tokens::SemanticTokenDbStorage, utils::LspPositionConversionStorage,
references::ReferencesDbStorage, semantic_tokens::SemanticTokenDbStorage,
utils::LspPositionConversionStorage,
},
};

Expand All @@ -23,6 +24,7 @@ use crate::{
HirDbStorage,
InputDbStorage,
LspPositionConversionStorage,
ReferencesDbStorage,
SemanticTokenDbStorage,
StringToCstStorage
)]
Expand Down
Expand Up @@ -19,7 +19,7 @@ pub fn find_definition(
let params = params.text_document_position_params;
let input: Input = params.text_document.uri.clone().into();
let position = params.position;
let offset = db.position_to_utf8_byte_offset(position.line, position.character, input.clone());
let offset = db.offset_from_lsp(input.clone(), position.line, position.character);

let origin_cst = db.find_cst_by_offset(input.clone(), offset);
match origin_cst.kind {
Expand Down
Expand Up @@ -146,12 +146,9 @@ impl<'a> Context<'a> {
fn push(&mut self, start: usize, end: usize, kind: FoldingRangeKind) {
let start = self
.db
.utf8_byte_offset_to_lsp(start, self.input.clone())
.to_position();
let end = self
.db
.utf8_byte_offset_to_lsp(end, self.input.clone())
.offset_to_lsp(self.input.clone(), start)
.to_position();
let end = self.db.offset_to_lsp(self.input.clone(), end).to_position();

self.ranges.push(FoldingRange {
start_line: start.line,
Expand Down
4 changes: 2 additions & 2 deletions new-new-packages/compiler/src/language_server/hints.rs
Expand Up @@ -67,7 +67,7 @@ fn hints(db: &dyn HintsDb, input: Input) -> Vec<Hint> {
.unwrap();

let line = db
.utf8_byte_offset_to_lsp(span.start, input.clone())
.offset_to_lsp(input.clone(), span.start)
.to_position()
.line;
let line_start_offsets = db.line_start_utf8_byte_offsets(input.clone());
Expand All @@ -77,7 +77,7 @@ fn hints(db: &dyn HintsDb, input: Input) -> Vec<Hint> {
line_start_offsets[(line + 1) as usize] - 1
};
let position = db
.utf8_byte_offset_to_lsp(last_characer_of_line, input.clone())
.offset_to_lsp(input.clone(), last_characer_of_line)
.to_position();

Some(Hint {
Expand Down
78 changes: 55 additions & 23 deletions new-new-packages/compiler/src/language_server/mod.rs
@@ -1,8 +1,9 @@
use lsp_types::{
DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
DocumentFilter, FoldingRange, FoldingRangeParams, GotoDefinitionParams, GotoDefinitionResponse,
InitializeParams, InitializeResult, InitializedParams, MessageType, Registration,
SemanticTokens, SemanticTokensFullOptions, SemanticTokensOptions, SemanticTokensParams,
DocumentFilter, DocumentHighlight, DocumentHighlightParams, FoldingRange, FoldingRangeParams,
GotoDefinitionParams, GotoDefinitionResponse, InitializeParams, InitializeResult,
InitializedParams, Location, MessageType, ReferenceParams, Registration, SemanticTokens,
SemanticTokensFullOptions, SemanticTokensOptions, SemanticTokensParams,
SemanticTokensRegistrationOptions, SemanticTokensResult, SemanticTokensServerCapabilities,
ServerCapabilities, ServerInfo, StaticRegistrationOptions,
TextDocumentChangeRegistrationOptions, TextDocumentContentChangeEvent,
Expand All @@ -19,13 +20,18 @@ use crate::{
};

use self::{
definition::find_definition, folding_range::FoldingRangeDb, hints::HintsNotification,
semantic_tokens::SemanticTokenDb, utils::LspPositionConversion,
definition::find_definition,
folding_range::FoldingRangeDb,
hints::HintsNotification,
references::{find_document_highlights, find_references},
semantic_tokens::SemanticTokenDb,
utils::LspPositionConversion,
};

pub mod definition;
pub mod folding_range;
pub mod hints;
pub mod references;
pub mod semantic_tokens;
pub mod utils;

Expand Down Expand Up @@ -61,13 +67,20 @@ impl LanguageServer for CandyLanguageServer {

async fn initialized(&self, _: InitializedParams) {
log::info!("LSP: initialized");
let candy_files = DocumentFilter {
language: Some("candy".to_owned()),
scheme: Some("file".to_owned()),
pattern: None,
};
let candy_files = vec![
DocumentFilter {
language: Some("candy".to_owned()),
scheme: Some("file".to_owned()),
pattern: None,
},
DocumentFilter {
language: Some("candy".to_owned()),
scheme: Some("untitled".to_owned()),
pattern: None,
},
];
let text_document_registration_options = TextDocumentRegistrationOptions {
document_selector: Some(vec![candy_files.clone()]),
document_selector: Some(candy_files.clone()),
};
self.client
.register_capability(vec![
Expand All @@ -90,7 +103,7 @@ impl LanguageServer for CandyLanguageServer {
method: "textDocument/didChange".to_owned(),
register_options: Some(
serde_json::to_value(TextDocumentChangeRegistrationOptions {
document_selector: Some(vec![candy_files]),
document_selector: Some(candy_files),
sync_kind: 2, // incremental
})
.unwrap(),
Expand All @@ -105,13 +118,27 @@ impl LanguageServer for CandyLanguageServer {
},
Registration {
id: "4".to_owned(),
method: "textDocument/foldingRange".to_owned(),
method: "textDocument/references".to_owned(),
register_options: Some(
serde_json::to_value(text_document_registration_options.clone()).unwrap(),
),
},
Registration {
id: "5".to_owned(),
method: "textDocument/documentHighlight".to_owned(),
register_options: Some(
serde_json::to_value(text_document_registration_options.clone()).unwrap(),
),
},
Registration {
id: "6".to_owned(),
method: "textDocument/foldingRange".to_owned(),
register_options: Some(
serde_json::to_value(text_document_registration_options.clone()).unwrap(),
),
},
Registration {
id: "7".to_owned(),
method: "textDocument/semanticTokens".to_owned(),
register_options: Some(
serde_json::to_value(
Expand Down Expand Up @@ -178,6 +205,18 @@ impl LanguageServer for CandyLanguageServer {
Ok(find_definition(&db, params))
}

async fn references(&self, params: ReferenceParams) -> jsonrpc::Result<Option<Vec<Location>>> {
let db = self.db.lock().await;
Ok(find_references(&db, params))
}
async fn document_highlight(
&self,
params: DocumentHighlightParams,
) -> jsonrpc::Result<Option<Vec<DocumentHighlight>>> {
let db = self.db.lock().await;
Ok(find_document_highlights(&db, params))
}

async fn folding_range(
&self,
params: FoldingRangeParams,
Expand Down Expand Up @@ -241,16 +280,9 @@ fn apply_text_changes(
for change in changes {
match change.range {
Some(range) => {
let start = db.position_to_utf8_byte_offset(
range.start.line,
range.start.character,
input.clone(),
);
let end = db.position_to_utf8_byte_offset(
range.end.line,
range.end.character,
input.clone(),
);
let start =
db.offset_from_lsp(input.clone(), range.start.line, range.start.character);
let end = db.offset_from_lsp(input.clone(), range.end.line, range.end.character);
text = format!("{}{}{}", &text[..start], &change.text, &text[end..]);
}
None => text = change.text,
Expand Down