Skip to content

Commit

Permalink
feat: find references and hover
Browse files Browse the repository at this point in the history
  • Loading branch information
viddrobnic committed Jul 28, 2024
1 parent c94bc08 commit cfcdcfe
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 59 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions language_server/src/analyze/document_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use parser::position::{Position, Range};

use super::location::LocationData;

#[derive(Debug, PartialEq, Eq, Default)]
pub struct DefinitionInfo {
pub defined_at: Range,
}

#[derive(Debug, PartialEq, Eq, Default)]
pub struct ReferencesInfo {
pub references: Vec<Range>,
}

#[derive(Debug, PartialEq, Eq, Default)]
pub struct DocumentInfo {
pub definitions: LocationData<DefinitionInfo>,
pub references: LocationData<ReferencesInfo>,
}

impl DocumentInfo {
pub fn get_definition(&self, position: &Position) -> Option<Range> {
self.definitions
.get(position)
.map(|def| def.entry.defined_at)
}

pub fn get_references(&self, position: &Position) -> Option<&Vec<Range>> {
let def_at = self.get_definition(position)?;
self.references
.get(&def_at.start)
.map(|entry| &entry.entry.references)
}
}
18 changes: 2 additions & 16 deletions language_server/src/analyze/mod.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
use document_info::{DefinitionInfo, DocumentInfo, ReferencesInfo};
use location::{LocationData, LocationEntry};
use parser::{ast, position::Range};
use symbol_table::SymbolTable;

pub mod document_info;
pub mod location;

mod symbol_table;

#[derive(Debug, PartialEq, Eq, Default)]
pub struct DefinitionInfo {
pub defined_at: Range,
}

#[derive(Debug, PartialEq, Eq, Default)]
pub struct ReferencesInfo {
pub references: Vec<Range>,
}

#[derive(Debug, PartialEq, Eq, Default)]
pub struct DocumentInfo {
pub definitions: LocationData<DefinitionInfo>,
pub references: LocationData<ReferencesInfo>,
}

pub fn analyze(program: &ast::Program) -> DocumentInfo {
let analyzer = Analyzer::new();
analyzer.analyze(program)
Expand Down
66 changes: 50 additions & 16 deletions language_server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ use std::{
path::PathBuf,
};

use analyze::{analyze, DocumentInfo};
use analyze::{analyze, document_info::DocumentInfo};
use error::{Error, ErrorKind};
use message::{initialize::*, *};
use parser::position::Position;
use text::{
DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams, Location,
TextDocumentPositionParams,
};
use parser::position::PositionOrdering;
use reference::ReferenceParams;
use text::*;

pub mod error;

Expand Down Expand Up @@ -174,22 +172,56 @@ impl Server {
"initialize" => Response::new_ok(req.id, self.get_capabilities()),
"shutdown" => Response::new_ok(req.id, serde_json::Value::Null),
"textDocument/definition" => {
// TODO: Handle errors better
let (req_id, params) = req.extract::<TextDocumentPositionParams>()?;

let doc_info = self.documents.get(&params.text_document.uri);
let mut res: Option<Location> = None;
if let Some(doc_info) = doc_info {
res = doc_info
.definitions
.get(&Position {
line: params.position.line,
character: params.position.character,
})
.map(|def| Location {
uri: params.text_document.uri.to_string(),
range: def.entry.defined_at.into(),
});
.get_definition(&params.position)
.map(|def| Location::new(params.text_document.uri.to_string(), def));
}

Response::new_ok(req_id, res)
}
"textDocument/documentHighlight" => {
let (req_id, params) = req.extract::<TextDocumentPositionParams>()?;

let doc_info = self.documents.get(&params.text_document.uri);
let mut res: Option<Vec<DocumentHighlight>> = None;
if let Some(doc_info) = doc_info {
res = doc_info.get_references(&params.position).map(|ranges| {
ranges
.iter()
.map(|rng| DocumentHighlight { range: *rng })
.collect()
});
}

Response::new_ok(req_id, res)
}
"textDocument/references" => {
let (req_id, params) = req.extract::<ReferenceParams>()?;
let doc_name = params.text_position.text_document.uri.clone();
let pos = params.text_position.position;

let doc_info = self.documents.get(&doc_name);
let mut res: Option<Vec<Location>> = None;
if let Some(doc_info) = doc_info {
res = doc_info.get_references(&pos).map(|ranges| {
ranges
.iter()
.filter_map(|rng| {
if params.context.include_declaration
|| pos.cmp_range(rng) != PositionOrdering::Inside
{
Some(Location::new(doc_name.clone(), *rng))
} else {
None
}
})
.collect()
});
}

Response::new_ok(req_id, res)
Expand Down Expand Up @@ -219,6 +251,8 @@ impl Server {
change: TextDocumentSyncKind::Full as u8,
},
definition_provider: true,
document_highlight_provider: true,
references_provider: true,
},
}
}
Expand Down
2 changes: 2 additions & 0 deletions language_server/src/message/initialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub struct InitializeResult {
pub struct ServerCapabilities {
pub text_document_sync: TextDocumentSyncOptions,
pub definition_provider: bool,
pub document_highlight_provider: bool,
pub references_provider: bool,
// pub diagnostic_provider: DiagnosticOptions,
}

Expand Down
1 change: 1 addition & 0 deletions language_server/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use serde_json::Value;
use crate::error::{Error, ErrorKind};

pub mod initialize;
pub mod reference;
pub mod text;

mod headers;
Expand Down
17 changes: 17 additions & 0 deletions language_server/src/message/reference.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use serde::{Deserialize, Serialize};

use crate::TextDocumentPositionParams;

#[derive(Debug, Serialize, Deserialize)]
pub struct ReferenceParams {
#[serde(flatten)]
pub text_position: TextDocumentPositionParams,

pub context: ReferenceContext,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ReferenceContext {
pub include_declaration: bool,
}
33 changes: 8 additions & 25 deletions language_server/src/message/text.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use parser::position::{Position, Range};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -35,18 +36,6 @@ pub struct DidCloseTextDocumentParams {
pub text_document: TextDocumentIdentifier,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Position {
pub line: usize,
pub character: usize,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Range {
pub start: Position,
pub end: Position,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Location {
pub uri: String,
Expand All @@ -60,20 +49,14 @@ pub struct TextDocumentPositionParams {
pub position: Position,
}

impl From<parser::position::Position> for Position {
fn from(value: parser::position::Position) -> Self {
Self {
line: value.line,
character: value.character,
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DocumentHighlight {
pub range: Range,
}

impl From<parser::position::Range> for Range {
fn from(value: parser::position::Range) -> Self {
Self {
start: value.start.into(),
end: value.end.into(),
}
impl Location {
pub fn new(uri: String, range: Range) -> Self {
Self { uri, range }
}
}
1 change: 1 addition & 0 deletions parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ edition = "2021"

[dependencies]
thiserror = "1.0"
serde = { version = "1.0", features = ["derive"] }
6 changes: 4 additions & 2 deletions parser/src/position.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use serde::{Deserialize, Serialize};

/// Represents position inside code.
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Serialize, Deserialize)]
pub struct Position {
/// Line number, starting with 0.
pub line: usize,
Expand Down Expand Up @@ -33,7 +35,7 @@ impl Position {
}
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Serialize, Deserialize)]
pub struct Range {
/// Range start position, inclusive.
pub start: Position,
Expand Down

0 comments on commit cfcdcfe

Please sign in to comment.