diff --git a/crates/lsp/src/global_state.rs b/crates/lsp/src/global_state.rs index ded3e35..d84239d 100644 --- a/crates/lsp/src/global_state.rs +++ b/crates/lsp/src/global_state.rs @@ -1,14 +1,17 @@ +use std::env; +use std::{fs, path::PathBuf}; + use anyhow::Result; use dashmap::DashMap; use lsp_server::{RequestId, Response}; use lsp_types::{ DidChangeTextDocumentParams, DidOpenTextDocumentParams, GotoDefinitionParams, - GotoDefinitionResponse, Location, Url, + GotoDefinitionResponse, Location, Range, Url, }; use parser::{ ast::{AstCircomProgram, AstNode}, parser::Parser, - syntax_node::SyntaxNode, + syntax_node::{SyntaxNode, SyntaxToken}, }; use crate::handler::{ @@ -53,26 +56,54 @@ impl GlobalState { } } + pub fn lookup_definition( + &self, + root: &FileUtils, + ast: &AstCircomProgram, + token: &SyntaxToken, + ) -> Vec { + let mut result = lookup_definition(root, ast, token); + + let p = root.get_path(); + + for lib in ast.libs() { + let lib_abs_path = PathBuf::from(lib.lib().unwrap().value()); + let lib_path = p.parent().unwrap().join(lib_abs_path).clone(); + let url = Url::from_file_path(lib_path.clone()).unwrap(); + if let Ok(src) = fs::read_to_string(lib_path) { + let text_doc = TextDocument { + text: src, + uri: url.clone(), + }; + + let file = &FileUtils::create(&text_doc.text, url.clone()); + let green = Parser::parse_circom(&text_doc.text); + let syntax = SyntaxNode::new_root(green); + + if let Some(lib_ast) = AstCircomProgram::cast(syntax) { + let ans = lookup_definition(file, &lib_ast, token); + result.extend(ans); + } + + } + } + + result + } pub fn goto_definition_handler(&self, id: RequestId, params: GotoDefinitionParams) -> Response { let uri = params.text_document_position_params.text_document.uri; let ast = self.ast_map.get(&uri.to_string()).unwrap(); let file = self.file_map.get(&uri.to_string()).unwrap(); - let mut ranges = Vec::new(); - + let mut locations = Vec::new(); if let Some(token) = lookup_token_at_postion(&file, &ast, params.text_document_position_params.position) { - ranges = lookup_definition(&file, &ast, &token); + locations = self.lookup_definition(&file, &ast, &token); }; - let locations = ranges - .into_iter() - .map(|range| Location::new(uri.clone(), range)) - .collect(); - - let result = Some(GotoDefinitionResponse::Array(locations)); + let result: Option = Some(GotoDefinitionResponse::Array(locations)); let result = serde_json::to_value(result).unwrap(); @@ -83,7 +114,7 @@ impl GlobalState { } } - pub(crate) fn handle_update(&mut self, text_document: &TextDocument) -> Result<()> { + pub(crate) fn handle_update(&self, text_document: &TextDocument) -> Result<()> { let text = &text_document.text; let url = text_document.uri.to_string(); @@ -93,7 +124,8 @@ impl GlobalState { self.ast_map .insert(url.clone(), AstCircomProgram::cast(syntax).unwrap()); - self.file_map.insert(url, FileUtils::create(text)); + self.file_map + .insert(url, FileUtils::create(text, text_document.uri.clone())); Ok(()) } } diff --git a/crates/lsp/src/handler/goto_definition.rs b/crates/lsp/src/handler/goto_definition.rs index 4e4add8..a2f63f5 100644 --- a/crates/lsp/src/handler/goto_definition.rs +++ b/crates/lsp/src/handler/goto_definition.rs @@ -1,15 +1,15 @@ +use std::env; +use std::fs; +use std::path::PathBuf; - +use lsp_types::Location; use lsp_types::{Position, Range}; use parser::{ - ast::{ - AstCircomProgram, AstComponentCall, AstNode, AstTemplateDef, - AstTemplateName, - }, + ast::{AstCircomProgram, AstComponentCall, AstNode, AstTemplateDef, AstTemplateName}, syntax_node::{SyntaxNode, SyntaxToken}, token_kind::TokenKind, }; -use rowan::{SyntaxText}; +use rowan::SyntaxText; use super::lsp_utils::FileUtils; @@ -62,7 +62,7 @@ pub fn lookup_definition( file: &FileUtils, ast: &AstCircomProgram, token: &SyntaxToken, -) -> Vec { +) -> Vec { eprintln!("{token:?}"); let template_list = ast.template_list(); @@ -138,7 +138,13 @@ pub fn lookup_definition( } } } - res + + let locations = res + .into_iter() + .map(|range| Location::new(file.file_path.clone(), range)) + .collect(); + + locations } fn lookup_signal_in_template( @@ -178,6 +184,9 @@ fn lookup_signal_in_template( } #[cfg(test)] mod tests { + use std::path::Path; + + use lsp_types::Url; use parser::{ ast::AstCircomProgram, parser::Parser, syntax_node::SyntaxNode, token_kind::TokenKind, }; @@ -230,7 +239,7 @@ template Y() { "# .to_string(); - let file = FileUtils::create(&source); + let file = FileUtils::create(&source, Url::from_file_path(Path::new("tmp")).unwrap()); let green_node = Parser::parse_circom(&source); let syntax_node = SyntaxNode::new_root(green_node.clone()); @@ -257,4 +266,12 @@ template Y() { } } } + + #[test] + fn url_test() { + let url = Url::from_file_path(Path::new("/hello/abc.tx")); + let binding = url.unwrap(); + let p = binding.path(); + println!("{:?}", Path::new(p).parent()); + } } diff --git a/crates/lsp/src/handler/lsp_utils.rs b/crates/lsp/src/handler/lsp_utils.rs index a74030c..0df5cfa 100644 --- a/crates/lsp/src/handler/lsp_utils.rs +++ b/crates/lsp/src/handler/lsp_utils.rs @@ -1,22 +1,26 @@ -use lsp_types::{Position, Range}; +use std::path::{self, Path, PathBuf}; + +use lsp_types::{Position, Range, Url}; use parser::syntax_node::SyntaxNode; use rowan::TextSize; pub struct FileId(u32); pub struct FileUtils { - file_id: FileId, - end_line_vec: Vec, + pub file_id: FileId, + pub file_path: Url, + pub end_line_vec: Vec, } impl FileUtils { - pub fn create(content: &str) -> Self { - Self::new(FileId(0), content) + pub fn create(content: &str, file_path: Url) -> Self { + Self::new(FileId(0), content, file_path) } - pub(super) fn new(file_id: FileId, content: &str) -> Self { + pub(super) fn new(file_id: FileId, content: &str, file_path: Url) -> Self { let mut file_utils = Self { file_id, + file_path, end_line_vec: Vec::new(), }; @@ -29,6 +33,11 @@ impl FileUtils { file_utils } + pub fn get_path(&self) -> PathBuf { + let p = self.file_path.path(); + PathBuf::from(p) + } + pub fn off_set(&self, position: Position) -> TextSize { if position.line == 0 { return position.character.into(); @@ -63,7 +72,9 @@ impl FileUtils { #[cfg(test)] mod tests { - use lsp_types::Position; + use std::path::Path; + + use lsp_types::{Position, Url}; use crate::handler::lsp_utils::{FileId, FileUtils}; @@ -75,7 +86,11 @@ two three "#; - let file_utils = FileUtils::new(FileId(1), str); + let file_utils = FileUtils::new( + FileId(1), + str, + Url::from_file_path(Path::new("tmp.txt")).unwrap(), + ); let position = Position::new(0, 1); @@ -95,7 +110,11 @@ three "#; // 0, 4, 8 - let file_utils = FileUtils::new(FileId(1), str); + let file_utils = FileUtils::new( + FileId(1), + str, + Url::from_file_path(Path::new("tmp.txt")).unwrap(), + ); assert_eq!(Position::new(1, 1), file_utils.position(2.into())); assert_eq!(Position::new(0, 0), file_utils.position(0.into())); } diff --git a/crates/parser/src/ast.rs b/crates/parser/src/ast.rs index 1a6f504..856551c 100644 --- a/crates/parser/src/ast.rs +++ b/crates/parser/src/ast.rs @@ -1,6 +1,7 @@ -use crate::syntax_node::{CircomLanguage}; +use crate::syntax_node::CircomLanguage; +use logos::Source; pub use rowan::ast::{support, AstChildren, AstNode}; -use rowan::{SyntaxText}; +use rowan::SyntaxText; use crate::{ syntax_node::SyntaxNode, @@ -261,6 +262,12 @@ impl AstCircomProgram { pub fn pragma(&self) -> Option { self.syntax().children().find_map(AstPragma::cast) } + pub fn libs(&self) -> Vec { + self.syntax() + .children() + .filter_map(AstInclude::cast) + .collect() + } pub fn template_list(&self) -> Vec { self.syntax() @@ -309,3 +316,19 @@ impl AstComponentIdentifier { support::child(self.syntax()) } } + +ast_node!(AstCircomString, CircomString); +impl AstCircomString { + pub fn value(&self) -> String { + let text = self.syntax().to_string(); + + text.slice(1..text.len() - 1).unwrap().to_string() + } +} +ast_node!(AstInclude, IncludeKw); + +impl AstInclude { + pub fn lib(&self) -> Option { + support::child(self.syntax()) + } +} diff --git a/crates/syntax/src/utils.rs b/crates/syntax/src/utils.rs new file mode 100644 index 0000000..e69de29