Skip to content

Commit c44c5c9

Browse files
committed
add references feature for functions
1 parent 4cec647 commit c44c5c9

2 files changed

Lines changed: 104 additions & 6 deletions

File tree

src/backend.rs

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ use tower_lsp_server::lsp_types::{
1313
DidChangeWorkspaceFoldersParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
1414
DidSaveTextDocumentParams, ExecuteCommandParams, GotoDefinitionParams, GotoDefinitionResponse,
1515
Hover, HoverParams, HoverProviderCapability, InitializeParams, InitializeResult,
16-
InitializedParams, Location, MarkupContent, MarkupKind, MessageType, OneOf, Range, SaveOptions,
17-
SemanticTokensParams, SemanticTokensResult, ServerCapabilities, TextDocumentSyncCapability,
18-
TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions, Uri,
19-
WorkDoneProgressOptions, WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
16+
InitializedParams, Location, MarkupContent, MarkupKind, MessageType, OneOf, Position, Range,
17+
ReferenceParams, SaveOptions, SemanticTokensParams, SemanticTokensResult, ServerCapabilities,
18+
TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
19+
TextDocumentSyncSaveOptions, Uri, WorkDoneProgressOptions, WorkspaceFoldersServerCapabilities,
20+
WorkspaceServerCapabilities,
2021
};
2122
use tower_lsp_server::{Client, LanguageServer};
2223

@@ -31,7 +32,8 @@ use crate::completion::{self, CompletionProvider};
3132
use crate::error::LspError;
3233
use crate::function::Functions;
3334
use crate::utils::{
34-
find_related_call, get_call_span, get_comments_from_lines, position_to_span, span_to_positions,
35+
find_all_references, find_related_call, get_call_span, get_comments_from_lines,
36+
position_to_span, span_contains, span_to_positions,
3537
};
3638

3739
#[derive(Debug)]
@@ -86,6 +88,7 @@ impl LanguageServer for Backend {
8688
}),
8789
hover_provider: Some(HoverProviderCapability::Simple(true)),
8890
definition_provider: Some(OneOf::Left(true)),
91+
references_provider: Some(OneOf::Left(true)),
8992
..ServerCapabilities::default()
9093
},
9194
})
@@ -308,6 +311,67 @@ impl LanguageServer for Backend {
308311
_ => Ok(None),
309312
}
310313
}
314+
315+
async fn references(&self, params: ReferenceParams) -> Result<Option<Vec<Location>>> {
316+
let documents = self.document_map.read().await;
317+
let uri = &params.text_document_position.text_document.uri;
318+
319+
let doc = documents
320+
.get(uri)
321+
.ok_or(LspError::DocumentNotFound(uri.to_owned()))?;
322+
let functions = doc.functions.functions();
323+
324+
let token_position = params.text_document_position.position;
325+
326+
let token_span = position_to_span(token_position)?;
327+
328+
let line = doc
329+
.text
330+
.lines()
331+
.nth(token_position.line as usize)
332+
.ok_or(LspError::Internal("Rope proccesing error".into()))?;
333+
334+
let line_str = line.as_str().ok_or(LspError::ConversionFailed(
335+
"RopeSlice to str conversion failed".into(),
336+
))?;
337+
338+
let func = functions
339+
.iter()
340+
.find(|func| span_contains(func.span(), &token_span))
341+
.ok_or(LspError::CallNotFound(
342+
"Span of the call is not inside function.".into(),
343+
))?;
344+
345+
let Some(pos) = line_str.find(func.name().as_inner()) else {
346+
return Ok(None);
347+
};
348+
349+
let (start, end) = (
350+
Position {
351+
line: token_position.line,
352+
character: u32::try_from(pos).map_err(LspError::from)?,
353+
},
354+
Position {
355+
line: token_position.line,
356+
character: u32::try_from(pos + func.name().as_inner().len())
357+
.map_err(LspError::from)?,
358+
},
359+
);
360+
361+
if token_position <= end && token_position >= start {
362+
Ok(Some(
363+
find_all_references(&functions, func.name())?
364+
.iter()
365+
.map(|range| Location {
366+
range: *range,
367+
uri: uri.clone(),
368+
})
369+
.collect(),
370+
))
371+
} else {
372+
Ok(None)
373+
}
374+
}
311375
}
312376

313377
impl Backend {

src/utils.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use miniscript::iter::TreeLike;
44

55
use crate::error::LspError;
66
use ropey::Rope;
7-
use simplicityhl::parse;
7+
use simplicityhl::{
8+
parse::{self, CallName},
9+
str::FunctionName,
10+
};
811
use tower_lsp_server::lsp_types;
912

1013
fn position_le(a: &simplicityhl::error::Position, b: &simplicityhl::error::Position) -> bool {
@@ -169,6 +172,37 @@ pub fn get_call_span(
169172
})
170173
}
171174

175+
pub fn find_all_references<'a>(
176+
functions: &'a [&'a parse::Function],
177+
func_name: &FunctionName,
178+
) -> Result<Vec<lsp_types::Range>, LspError> {
179+
functions
180+
.iter()
181+
.flat_map(|func| {
182+
parse::ExprTree::Expression(func.body())
183+
.pre_order_iter()
184+
.filter_map(|expr| {
185+
if let parse::ExprTree::Call(call) = expr {
186+
get_call_span(call).ok().map(|span| (call, span))
187+
} else {
188+
None
189+
}
190+
})
191+
.filter(|(call, _)| match call.name() {
192+
CallName::Custom(name) => name == func_name,
193+
_ => false,
194+
})
195+
.map(|(_, span)| span)
196+
.collect::<Vec<_>>()
197+
})
198+
.map(|span| {
199+
let (start, mut end) = span_to_positions(&span)?;
200+
end.character = start.character + u32::try_from(func_name.as_inner().len())?;
201+
Ok(lsp_types::Range { start, end })
202+
})
203+
.collect::<Result<Vec<_>, LspError>>() // collects results, propagating first Err
204+
}
205+
172206
#[cfg(test)]
173207
mod tests {
174208
use super::*;

0 commit comments

Comments
 (0)