From 7744a0a90094684d8b961a8a9c61ee3e2bbcde95 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 24 Jun 2025 13:41:58 -0300 Subject: [PATCH] feat: `nargo expand` for LSP --- Cargo.lock | 1 + tooling/lsp/Cargo.toml | 1 + tooling/lsp/src/lib.rs | 3 ++ tooling/lsp/src/requests/code_action.rs | 2 +- tooling/lsp/src/requests/completion.rs | 2 +- tooling/lsp/src/requests/expand.rs | 26 ++++++++++++++++ .../lsp/src/requests/hover/from_reference.rs | 11 +++++-- tooling/lsp/src/requests/mod.rs | 22 +++++++++----- tooling/lsp/src/types.rs | 22 +++++++++++++- tooling/nargo_cli/src/cli/expand_cmd.rs | 2 +- tooling/nargo_expand/src/lib.rs | 30 +++++++++++-------- 11 files changed, 95 insertions(+), 27 deletions(-) create mode 100644 tooling/lsp/src/requests/expand.rs diff --git a/Cargo.lock b/Cargo.lock index 203fc22d027..ab5b82e83cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3503,6 +3503,7 @@ dependencies = [ "fxhash", "iter-extended", "nargo", + "nargo_expand", "nargo_fmt", "nargo_toml", "noirc_driver", diff --git a/tooling/lsp/Cargo.toml b/tooling/lsp/Cargo.toml index b6921c986e0..ccbe4b39edf 100644 --- a/tooling/lsp/Cargo.toml +++ b/tooling/lsp/Cargo.toml @@ -16,6 +16,7 @@ workspace = true acvm.workspace = true codespan-lsp.workspace = true nargo = { workspace = true, features = ["rpc"] } +nargo_expand.workspace = true nargo_fmt.workspace = true nargo_toml.workspace = true noirc_driver.workspace = true diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index 0fd86d9dfb6..44380c595fa 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -80,6 +80,8 @@ use solver::WrapperSolver; use types::{NargoTest, NargoTestId, Position, Range, Url, notification, request}; use with_file::parsed_module_with_file; +use crate::{requests::on_expand_request, types::request::NargoExpand}; + #[derive(Debug, Error)] pub enum LspError { /// Error while Resolving Workspace. @@ -170,6 +172,7 @@ impl NargoLspService { .request::(on_signature_help_request) .request::(on_code_action_request) .request::(on_workspace_symbol_request) + .request::(on_expand_request) .notification::(on_initialized) .notification::(on_did_change_configuration) .notification::(on_did_open_text_document) diff --git a/tooling/lsp/src/requests/code_action.rs b/tooling/lsp/src/requests/code_action.rs index 2276f6a3bf2..ef7f266b7f5 100644 --- a/tooling/lsp/src/requests/code_action.rs +++ b/tooling/lsp/src/requests/code_action.rs @@ -67,7 +67,7 @@ pub(crate) fn on_code_action_request( byte_range, args.crate_id, args.def_maps, - args.dependencies, + args.dependencies(), args.interner, args.usage_tracker, ); diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index dd076d6953d..6203b0b4635 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -86,7 +86,7 @@ pub(crate) fn on_completion_request( byte, args.crate_id, args.def_maps, - args.dependencies, + args.dependencies(), args.interner, ); finder.find(&parsed_module) diff --git a/tooling/lsp/src/requests/expand.rs b/tooling/lsp/src/requests/expand.rs new file mode 100644 index 00000000000..7b965913567 --- /dev/null +++ b/tooling/lsp/src/requests/expand.rs @@ -0,0 +1,26 @@ +use std::future; + +use async_lsp::{ResponseError, lsp_types::TextDocumentPositionParams}; +use nargo_expand::get_expanded_crate; + +use crate::{ + LspState, + requests::process_request, + types::{NargoExpandParams, NargoExpandResult}, +}; + +pub(crate) fn on_expand_request( + state: &mut LspState, + params: NargoExpandParams, +) -> impl Future> + use<> { + let text_document_position_params = TextDocumentPositionParams { + text_document: params.text_document, + position: params.position, + }; + + let result = process_request(state, text_document_position_params, |args| { + get_expanded_crate(args.crate_id, args.crate_graph, args.def_maps, args.interner) + }); + + future::ready(result) +} diff --git a/tooling/lsp/src/requests/hover/from_reference.rs b/tooling/lsp/src/requests/hover/from_reference.rs index 80978188a7a..238256ba091 100644 --- a/tooling/lsp/src/requests/hover/from_reference.rs +++ b/tooling/lsp/src/requests/hover/from_reference.rs @@ -85,7 +85,7 @@ fn format_module(id: ModuleId, args: &ProcessRequestCallbackArgs) -> Option bool { - let full_path = - module_full_path(module, args.interner, args.crate_id, &args.crate_name, args.dependencies); + let full_path = module_full_path( + module, + args.interner, + args.crate_id, + &args.crate_name, + args.dependencies(), + ); if full_path.is_empty() { return false; } diff --git a/tooling/lsp/src/requests/mod.rs b/tooling/lsp/src/requests/mod.rs index 955ef9c2157..c58920cc948 100644 --- a/tooling/lsp/src/requests/mod.rs +++ b/tooling/lsp/src/requests/mod.rs @@ -18,7 +18,7 @@ use lsp_types::{ use nargo_fmt::Config; use noirc_frontend::ast::Ident; -use noirc_frontend::graph::CrateId; +use noirc_frontend::graph::{CrateGraph, CrateId}; use noirc_frontend::hir::def_map::{CrateDefMap, ModuleId}; use noirc_frontend::node_interner::ReferenceId; use noirc_frontend::parser::ParserError; @@ -49,6 +49,7 @@ mod code_action; mod code_lens_request; mod completion; mod document_symbol; +mod expand; mod goto_declaration; mod goto_definition; mod hover; @@ -63,9 +64,10 @@ mod workspace_symbol; pub(crate) use { code_action::on_code_action_request, code_lens_request::collect_lenses_for_package, code_lens_request::on_code_lens_request, completion::on_completion_request, - document_symbol::on_document_symbol_request, goto_declaration::on_goto_declaration_request, - goto_definition::on_goto_definition_request, goto_definition::on_goto_type_definition_request, - hover::on_hover_request, inlay_hint::on_inlay_hint_request, references::on_references_request, + document_symbol::on_document_symbol_request, expand::on_expand_request, + goto_declaration::on_goto_declaration_request, goto_definition::on_goto_definition_request, + goto_definition::on_goto_type_definition_request, hover::on_hover_request, + inlay_hint::on_inlay_hint_request, references::on_references_request, rename::on_prepare_rename_request, rename::on_rename_request, signature_help::on_signature_help_request, test_run::on_test_run_request, tests::on_tests_request, workspace_symbol::on_workspace_symbol_request, @@ -458,11 +460,17 @@ pub(crate) struct ProcessRequestCallbackArgs<'a> { package_cache: &'a HashMap, crate_id: CrateId, crate_name: String, - dependencies: &'a Vec, + crate_graph: &'a CrateGraph, def_maps: &'a BTreeMap, usage_tracker: &'a UsageTracker, } +impl<'a> ProcessRequestCallbackArgs<'a> { + pub(crate) fn dependencies(&self) -> &'a Vec { + &self.crate_graph[self.crate_id].dependencies + } +} + pub(crate) fn process_request( state: &mut LspState, text_document_position_params: TextDocumentPositionParams, @@ -516,7 +524,7 @@ where package_cache: &state.package_cache, crate_id, crate_name: package.name.to_string(), - dependencies: &crate_graph[crate_id].dependencies, + crate_graph, def_maps, usage_tracker, })) @@ -581,7 +589,7 @@ where package_cache: &state.package_cache, crate_id, crate_name: package.name.to_string(), - dependencies: &context.crate_graph[crate_id].dependencies, + crate_graph: &context.crate_graph, def_maps, usage_tracker, })) diff --git a/tooling/lsp/src/types.rs b/tooling/lsp/src/types.rs index 9640d3d39d8..9a76cdfe1d4 100644 --- a/tooling/lsp/src/types.rs +++ b/tooling/lsp/src/types.rs @@ -1,7 +1,8 @@ use async_lsp::lsp_types::{ CodeActionOptions, CompletionOptions, DeclarationCapability, DefinitionOptions, DocumentSymbolOptions, HoverOptions, InlayHintOptions, OneOf, ReferencesOptions, RenameOptions, - SignatureHelpOptions, TypeDefinitionProviderCapability, WorkspaceSymbolOptions, + SignatureHelpOptions, TextDocumentIdentifier, TypeDefinitionProviderCapability, + WorkspaceSymbolOptions, }; use noirc_frontend::graph::CrateName; use serde::{Deserialize, Serialize}; @@ -17,6 +18,8 @@ pub(crate) use async_lsp::lsp_types::{ pub(crate) mod request { use async_lsp::lsp_types::{InitializeParams, request::Request}; + use crate::types::{NargoExpandParams, NargoExpandResult}; + use super::{ InitializeResult, NargoTestRunParams, NargoTestRunResult, NargoTestsParams, NargoTestsResult, @@ -51,6 +54,14 @@ pub(crate) mod request { type Result = NargoTestsResult; const METHOD: &'static str = "nargo/tests"; } + + #[derive(Debug)] + pub(crate) struct NargoExpand; + impl Request for NargoExpand { + type Params = NargoExpandParams; + type Result = NargoExpandResult; + const METHOD: &'static str = "nargo/expand"; + } } pub(crate) mod notification { @@ -245,6 +256,15 @@ pub(crate) struct NargoTestRunResult { pub(crate) message: Option, } +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct NargoExpandParams { + pub(crate) text_document: TextDocumentIdentifier, + pub(crate) position: Position, +} + +pub(crate) type NargoExpandResult = String; + pub(crate) type CodeLensResult = Option>; pub(crate) type GotoDefinitionResult = Option; pub(crate) type GotoDeclarationResult = diff --git a/tooling/nargo_cli/src/cli/expand_cmd.rs b/tooling/nargo_cli/src/cli/expand_cmd.rs index 9fa113bd730..88370fde0c9 100644 --- a/tooling/nargo_cli/src/cli/expand_cmd.rs +++ b/tooling/nargo_cli/src/cli/expand_cmd.rs @@ -71,5 +71,5 @@ fn get_expanded_package_or_error( check_crate_and_report_errors(&mut context, crate_id, compile_options)?; - Ok(get_expanded_crate(&context, crate_id)) + Ok(get_expanded_crate(crate_id, &context.crate_graph, &context.def_maps, &context.def_interner)) } diff --git a/tooling/nargo_expand/src/lib.rs b/tooling/nargo_expand/src/lib.rs index 53537cdb246..b887e7a2b68 100644 --- a/tooling/nargo_expand/src/lib.rs +++ b/tooling/nargo_expand/src/lib.rs @@ -1,7 +1,11 @@ +use std::collections::BTreeMap; + use nargo_fmt::ImportsGranularity; use noirc_driver::CrateId; use noirc_frontend::{ - hir::{Context, def_map::ModuleId}, + graph::CrateGraph, + hir::def_map::{CrateDefMap, ModuleId}, + node_interner::NodeInterner, parse_program_with_dummy_file, }; @@ -11,24 +15,24 @@ mod items; mod printer; /// Returns the expanded code for the given crate. -/// Note that `context` must have `activate_lsp_mode` called on it before invoking this function. -pub fn get_expanded_crate(context: &Context, crate_id: CrateId) -> String { - let root_module_id = context.def_maps[&crate_id].root(); +/// Note that `context` that holds the crate graph, def maps and interner +/// must have `activate_lsp_mode` called on it before invoking this function. +pub fn get_expanded_crate( + crate_id: CrateId, + crate_graph: &CrateGraph, + def_maps: &BTreeMap, + interner: &NodeInterner, +) -> String { + let root_module_id = def_maps[&crate_id].root(); let module_id = ModuleId { krate: crate_id, local_id: root_module_id }; - let mut builder = ItemBuilder::new(crate_id, &context.def_interner, &context.def_maps); + let mut builder = ItemBuilder::new(crate_id, interner, def_maps); let item = builder.build_module(module_id); - let dependencies = &context.crate_graph[context.root_crate_id()].dependencies; + let dependencies = &crate_graph[crate_id].dependencies; let mut string = String::new(); - let mut printer = ItemPrinter::new( - crate_id, - &context.def_interner, - &context.def_maps, - dependencies, - &mut string, - ); + let mut printer = ItemPrinter::new(crate_id, interner, def_maps, dependencies, &mut string); printer.show_item(item); let (parsed_module, errors) = parse_program_with_dummy_file(&string);