Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub use contract::{CompiledContract, CompiledContractOutputs, ContractFunction};
pub use debug::DebugFile;
pub use noirc_frontend::graph::{CrateId, CrateName};
pub use program::CompiledProgram;
pub use stdlib::stdlib_paths_with_source;

const STD_CRATE_NAME: &str = "std";
const DEBUG_CRATE_NAME: &str = "__debug";
Expand Down Expand Up @@ -336,7 +337,7 @@ fn add_stdlib_source_to_file_manager(file_manager: &mut FileManager) {
// on the stdlib. For other dependencies, we read the package.Dependencies file to add their file
// contents to the file manager. However since the dependency on the stdlib is implicit, we need
// to manually add it here.
let stdlib_paths_with_source = stdlib::stdlib_paths_with_source();
let stdlib_paths_with_source = stdlib_paths_with_source();
for (path, source) in stdlib_paths_with_source {
file_manager.add_file_with_source_canonical_path(Path::new(&path), source);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_driver/src/stdlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct StdLibAssets;
// This is needed because when we preload the file manager, it needs to know where
// the source code for the stdlib is. The stdlib is treated special because it comes with
// the compiler and is never included as a dependency like other user defined crates.
pub(crate) fn stdlib_paths_with_source() -> Vec<(String, String)> {
pub fn stdlib_paths_with_source() -> Vec<(String, String)> {
StdLibAssets::iter()
.map(|path| {
let source = std::str::from_utf8(StdLibAssets::get(&path).unwrap().data.as_ref())
Expand Down
11 changes: 8 additions & 3 deletions tooling/lsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ 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};
use crate::{
requests::{on_expand_request, on_std_source_code_request},
types::request::{NargoExpand, NargoStdSourceCode},
};

#[derive(Debug, Error)]
pub enum LspError {
Expand Down Expand Up @@ -173,6 +176,7 @@ impl NargoLspService {
.request::<CodeActionRequest, _>(on_code_action_request)
.request::<WorkspaceSymbolRequest, _>(on_workspace_symbol_request)
.request::<NargoExpand, _>(on_expand_request)
.request::<NargoStdSourceCode, _>(on_std_source_code_request)
.notification::<notification::Initialized>(on_initialized)
.notification::<notification::DidChangeConfiguration>(on_did_change_configuration)
.notification::<notification::DidOpenTextDocument>(on_did_open_text_document)
Expand Down Expand Up @@ -424,8 +428,9 @@ pub fn insert_all_files_for_workspace_into_file_manager(
pub fn source_code_overrides(input_files: &HashMap<String, String>) -> HashMap<PathBuf, &str> {
let mut overrides: HashMap<PathBuf, &str> = HashMap::new();
for (path, source) in input_files {
let path = path.strip_prefix("file://").unwrap();
overrides.insert(PathBuf::from_str(path).unwrap(), source);
if let Some(path) = path.strip_prefix("file://") {
overrides.insert(PathBuf::from_str(path).unwrap(), source);
}
}
overrides
}
94 changes: 59 additions & 35 deletions tooling/lsp/src/notifications/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use std::collections::{BTreeMap, HashSet};
use std::ops::ControlFlow;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::str::FromStr as _;

use crate::{
PackageCacheData, WorkspaceCacheData, insert_all_files_for_workspace_into_file_manager,
Expand All @@ -9,8 +11,10 @@ use async_lsp::lsp_types;
use async_lsp::lsp_types::{DiagnosticRelatedInformation, DiagnosticTag, Url};
use async_lsp::{ErrorCode, LanguageClient, ResponseError};
use fm::{FileManager, FileMap};
use nargo::package::{Package, PackageType};
use nargo::workspace::Workspace;
use noirc_driver::check_crate;
use noirc_driver::{CrateName, NOIR_ARTIFACT_VERSION_STRING};
use noirc_errors::reporter::CustomLabel;
use noirc_errors::{CustomDiagnostic, DiagnosticKind, Location};

Expand Down Expand Up @@ -98,7 +102,7 @@ pub(super) fn on_did_save_text_document(

// Process any pending changes
if state.workspaces_to_process.remove(&workspace.root_dir) {
let _ = process_workspace_for_noir_document(state, &workspace.root_dir, false);
let _ = process_workspace(state, &workspace, false);
}

// Cached data should be here but, if it doesn't, we'll just type-check and output diagnostics
Expand All @@ -107,11 +111,7 @@ pub(super) fn on_did_save_text_document(
state.package_cache.get(&workspace.root_dir),
) else {
let output_diagnostics = true;
return match process_workspace_for_noir_document(
state,
&workspace.root_dir,
output_diagnostics,
) {
return match process_workspace(state, &workspace, output_diagnostics) {
Ok(_) => ControlFlow::Continue(()),
Err(err) => return ControlFlow::Break(Err(err)),
};
Expand All @@ -122,11 +122,7 @@ pub(super) fn on_did_save_text_document(
// so here we force a type-check just in case.
if package_cache.diagnostics_just_published {
let output_diagnostics = true;
return match process_workspace_for_noir_document(
state,
&workspace.root_dir,
output_diagnostics,
) {
return match process_workspace(state, &workspace, output_diagnostics) {
Ok(_) => ControlFlow::Continue(()),
Err(err) => return ControlFlow::Break(Err(err)),
};
Expand Down Expand Up @@ -164,41 +160,48 @@ fn handle_text_document_notification(
// If it's the first time we see this package, show diagnostics.
// This can happen for example when a user opens a Noir file in a package for the first time.
let output_diagnostics = true;
process_workspace_for_noir_document(state, &workspace.root_dir, output_diagnostics)
process_workspace(state, &workspace, output_diagnostics)
}
}

fn workspace_from_document_uri(document_uri: Url) -> Result<Workspace, async_lsp::Error> {
let file_path = document_uri.to_file_path().map_err(|_| {
ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path")
})?;
pub(crate) fn workspace_from_document_uri(
document_uri: Url,
) -> Result<Workspace, async_lsp::Error> {
if document_uri.scheme() == "noir-std" {
Ok(fake_stdlib_workspace())
} else {
let file_path = document_uri.to_file_path().map_err(|_| {
ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path")
})?;

let workspace = resolve_workspace_for_source_path(&file_path).map_err(|lsp_error| {
ResponseError::new(ErrorCode::REQUEST_FAILED, lsp_error.to_string())
})?;
let workspace = resolve_workspace_for_source_path(&file_path).map_err(|lsp_error| {
ResponseError::new(ErrorCode::REQUEST_FAILED, lsp_error.to_string())
})?;

Ok(workspace)
Ok(workspace)
}
}

// Given a Noir document, find the workspace it's contained in (an assumed workspace is created if
// it's only contained in a package), then type-checks the workspace's packages,
// caching code lenses and type definitions, and notifying about compilation errors.
pub(crate) fn process_workspace_for_noir_document(
// caching type definitions, and notifying about compilation errors if `output_diagnostics` is true.
pub(crate) fn process_workspace(
state: &mut LspState,
file_path: &Path,
workspace: &Workspace,
output_diagnostics: bool,
) -> Result<(), async_lsp::Error> {
let workspace = resolve_workspace_for_source_path(file_path).map_err(|lsp_error| {
ResponseError::new(ErrorCode::REQUEST_FAILED, lsp_error.to_string())
})?;

let mut workspace_file_manager = workspace.new_file_manager();

insert_all_files_for_workspace_into_file_manager(
state,
&workspace,
&mut workspace_file_manager,
);
if workspace.is_assumed {
let package = workspace.members.first().unwrap();
workspace_file_manager
.add_file_with_source_canonical_path(&package.entry_path, String::new());
} else {
insert_all_files_for_workspace_into_file_manager(
state,
workspace,
&mut workspace_file_manager,
);
}

let parsed_files = parse_diff(&workspace_file_manager, state);

Expand Down Expand Up @@ -247,6 +250,27 @@ pub(crate) fn process_workspace_for_noir_document(
Ok(())
}

pub(crate) fn fake_stdlib_workspace() -> Workspace {
let assumed_package = Package {
version: None,
compiler_required_version: Some(NOIR_ARTIFACT_VERSION_STRING.to_string()),
compiler_required_unstable_features: Vec::new(),
root_dir: PathBuf::from_str("std").unwrap(),
package_type: PackageType::Binary,
entry_path: PathBuf::from_str("fake_entry_path.nr").unwrap(),
name: CrateName::from_str("fake_std").unwrap(),
dependencies: BTreeMap::new(),
expression_width: None,
};
Workspace {
root_dir: PathBuf::from_str("std").unwrap(),
members: vec![assumed_package],
selected_package_index: Some(0),
is_assumed: true,
target_dir: None,
}
}

fn publish_diagnostics(
state: &mut LspState,
package_root_dir: &PathBuf,
Expand Down
42 changes: 20 additions & 22 deletions tooling/lsp/src/requests/code_action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use async_lsp::lsp_types::{
CodeAction, CodeActionKind, CodeActionOrCommand, CodeActionParams, CodeActionResponse,
TextDocumentPositionParams, TextEdit, Url, WorkspaceEdit,
};
use fm::{FileId, FileMap, PathString};
use fm::{FileId, FileMap};
use noirc_errors::Span;
use noirc_frontend::{
ParsedModule,
Expand Down Expand Up @@ -49,27 +49,25 @@ pub(crate) fn on_code_action_request(
TextDocumentPositionParams { text_document: params.text_document, position };

let result = process_request(state, text_document_position_params, |args| {
let path = PathString::from_path(uri.to_file_path().unwrap());
args.files.get_file_id(&path).and_then(|file_id| {
utils::range_to_byte_span(args.files, file_id, &params.range).and_then(|byte_range| {
let file = args.files.get_file(file_id).unwrap();
let source = file.source();
let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id);

let mut finder = CodeActionFinder::new(
uri,
args.files,
file_id,
source,
byte_range,
args.crate_id,
args.def_maps,
args.dependencies(),
args.interner,
args.usage_tracker,
);
finder.find(&parsed_module)
})
let file_id = args.location.file;
utils::range_to_byte_span(args.files, file_id, &params.range).and_then(|byte_range| {
let file = args.files.get_file(file_id).unwrap();
let source = file.source();
let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id);

let mut finder = CodeActionFinder::new(
uri,
args.files,
file_id,
source,
byte_range,
args.crate_id,
args.def_maps,
args.dependencies(),
args.interner,
args.usage_tracker,
);
finder.find(&parsed_module)
})
});
future::ready(result)
Expand Down
14 changes: 3 additions & 11 deletions tooling/lsp/src/requests/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use completion_items::{
trait_impl_method_completion_item,
};
use convert_case::{Case, Casing};
use fm::{FileId, FileMap, PathString};
use fm::{FileId, FileMap};
use iter_extended::vecmap;
use kinds::{FunctionCompletionKind, FunctionKind, RequestedItems};
use noirc_errors::{Location, Span};
Expand Down Expand Up @@ -63,16 +63,9 @@ pub(crate) fn on_completion_request(
state: &mut LspState,
params: CompletionParams,
) -> impl Future<Output = Result<Option<CompletionResponse>, ResponseError>> + use<> {
let uri = params.text_document_position.clone().text_document.uri;

let result = process_request(state, params.text_document_position.clone(), |args| {
let path = PathString::from_path(uri.to_file_path().unwrap());
args.files.get_file_id(&path).and_then(|file_id| {
utils::position_to_byte_index(
args.files,
file_id,
&params.text_document_position.position,
)
let file_id = args.location.file;
utils::position_to_byte_index(args.files, file_id, &params.text_document_position.position)
.and_then(|byte_index| {
let file = args.files.get_file(file_id).unwrap();
let source = file.source();
Expand All @@ -92,7 +85,6 @@ pub(crate) fn on_completion_request(
);
finder.find(&parsed_module)
})
})
});
future::ready(result)
}
Expand Down
23 changes: 9 additions & 14 deletions tooling/lsp/src/requests/document_symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use async_lsp::lsp_types::{
DocumentSymbol, DocumentSymbolParams, DocumentSymbolResponse, Location, Position, SymbolKind,
TextDocumentPositionParams,
};
use fm::{FileId, FileMap, PathString};
use fm::{FileId, FileMap};
use noirc_errors::Span;
use noirc_frontend::ast::TraitBound;
use noirc_frontend::{
Expand All @@ -25,25 +25,20 @@ pub(crate) fn on_document_symbol_request(
state: &mut LspState,
params: DocumentSymbolParams,
) -> impl Future<Output = Result<Option<DocumentSymbolResponse>, ResponseError>> + use<> {
let Ok(file_path) = params.text_document.uri.to_file_path() else {
return future::ready(Ok(None));
};

let text_document_position_params = TextDocumentPositionParams {
text_document: params.text_document.clone(),
position: Position { line: 0, character: 0 },
};

let result = process_request(state, text_document_position_params, |args| {
args.files.get_file_id(&PathString::from_path(file_path)).map(|file_id| {
let file = args.files.get_file(file_id).unwrap();
let source = file.source();
let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id);

let mut collector = DocumentSymbolCollector::new(file_id, args.files);
let symbols = collector.collect(&parsed_module);
DocumentSymbolResponse::Nested(symbols)
})
let file_id = args.location.file;
let file = args.files.get_file(file_id).unwrap();
let source = file.source();
let (parsed_module, _errors) = noirc_frontend::parse_program(source, file_id);

let mut collector = DocumentSymbolCollector::new(file_id, args.files);
let symbols = collector.collect(&parsed_module);
Some(DocumentSymbolResponse::Nested(symbols))
});

future::ready(result)
Expand Down
5 changes: 4 additions & 1 deletion tooling/lsp/src/requests/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ pub(crate) fn on_expand_request(
state: &mut LspState,
params: NargoExpandParams,
) -> impl Future<Output = Result<NargoExpandResult, ResponseError>> + use<> {
let is_stdlib = params.text_document.uri.scheme() == "noir-std";

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)
let crate_id = if is_stdlib { *args.crate_graph.stdlib_crate_id() } else { args.crate_id };
get_expanded_crate(crate_id, args.crate_graph, args.def_maps, args.interner)
});

future::ready(result)
Expand Down
9 changes: 3 additions & 6 deletions tooling/lsp/src/requests/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::{LspState, types::GotoDefinitionResult};
use async_lsp::ResponseError;

use async_lsp::lsp_types;
use fm::PathString;
use lsp_types::request::GotoTypeDefinitionParams;
use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse};

Expand All @@ -33,11 +32,10 @@ fn on_goto_definition_inner(
params: GotoDefinitionParams,
return_type_location_instead: bool,
) -> Result<GotoDefinitionResult, ResponseError> {
let uri = params.text_document_position_params.text_document.uri.clone();
let position = params.text_document_position_params.position;
process_request(state, params.text_document_position_params, |args| {
let path = PathString::from_path(uri.to_file_path().unwrap());
let reference_id = args.files.get_file_id(&path).and_then(|file_id| {
let file_id = args.location.file;
let reference_id =
utils::position_to_byte_index(args.files, file_id, &position).and_then(|byte_index| {
let file = args.files.get_file(file_id).unwrap();
let source = file.source();
Expand All @@ -50,8 +48,7 @@ fn on_goto_definition_inner(
args.def_maps,
);
finder.find(&parsed_module)
})
});
});
let location = if let Some(reference_id) = reference_id {
Some(args.interner.reference_location(reference_id))
} else {
Expand Down
Loading
Loading