perf: early skip for special calls

This commit is contained in:
blindfs 2025-04-09 10:02:39 +08:00
parent 7915e14463
commit 49dc162f08
2 changed files with 46 additions and 8 deletions

View File

@ -2,7 +2,7 @@ use crate::Id;
use nu_protocol::{ use nu_protocol::{
ast::{Argument, Block, Call, Expr, Expression, FindMapResult, ListItem, PathMember, Traverse}, ast::{Argument, Block, Call, Expr, Expression, FindMapResult, ListItem, PathMember, Traverse},
engine::StateWorkingSet, engine::StateWorkingSet,
Span, ModuleId, Span,
}; };
use std::sync::Arc; use std::sync::Arc;
@ -58,6 +58,12 @@ fn try_find_id_in_def(
location: Option<&usize>, location: Option<&usize>,
id_ref: Option<&Id>, id_ref: Option<&Id>,
) -> Option<(Id, Span)> { ) -> Option<(Id, Span)> {
// skip if the id to search is not a declaration id
if let Some(id_ref) = id_ref {
if !matches!(id_ref, Id::Declaration(_)) {
return None;
}
}
let mut span = None; let mut span = None;
for arg in call.arguments.iter() { for arg in call.arguments.iter() {
if location.is_none_or(|pos| arg.span().contains(*pos)) { if location.is_none_or(|pos| arg.span().contains(*pos)) {
@ -108,6 +114,12 @@ fn try_find_id_in_mod(
location: Option<&usize>, location: Option<&usize>,
id_ref: Option<&Id>, id_ref: Option<&Id>,
) -> Option<(Id, Span)> { ) -> Option<(Id, Span)> {
// skip if the id to search is not a module id
if let Some(id_ref) = id_ref {
if !matches!(id_ref, Id::Module(_, _)) {
return None;
}
}
let check_location = |span: &Span| location.is_none_or(|pos| span.contains(*pos)); let check_location = |span: &Span| location.is_none_or(|pos| span.contains(*pos));
call.arguments.first().and_then(|arg| { call.arguments.first().and_then(|arg| {
@ -117,7 +129,24 @@ fn try_find_id_in_mod(
match arg { match arg {
Argument::Positional(expr) => { Argument::Positional(expr) => {
let name = expr.as_string()?; let name = expr.as_string()?;
let module_id = working_set.find_module(name.as_bytes())?; let module_id = working_set.find_module(name.as_bytes()).or_else(|| {
// in case the module is hidden
let mut any_id = true;
let mut id_num_ref = 0;
if let Some(Id::Module(id_ref, _)) = id_ref {
any_id = false;
id_num_ref = id_ref.get();
}
(0..working_set.num_modules())
.find(|id| {
(any_id || id_num_ref == *id)
&& working_set
.get_module(ModuleId::new(*id))
.span
.is_some_and(|mod_span| call.span().contains_span(mod_span))
})
.map(ModuleId::new)
})?;
let found_id = Id::Module(module_id, name.as_bytes().to_vec()); let found_id = Id::Module(module_id, name.as_bytes().to_vec());
let found_span = strip_quotes(arg.span(), working_set).1; let found_span = strip_quotes(arg.span(), working_set).1;
id_ref id_ref
@ -139,7 +168,7 @@ fn try_find_id_in_use(
call: &Call, call: &Call,
working_set: &StateWorkingSet, working_set: &StateWorkingSet,
location: Option<&usize>, location: Option<&usize>,
id: Option<&Id>, id_ref: Option<&Id>,
) -> Option<(Id, Span)> { ) -> Option<(Id, Span)> {
// NOTE: `call.parser_info` contains a 'import_pattern' field for `use`/`hide` commands, // NOTE: `call.parser_info` contains a 'import_pattern' field for `use`/`hide` commands,
// If it's missing, usually it means the PWD env is not correctly set, // If it's missing, usually it means the PWD env is not correctly set,
@ -155,7 +184,7 @@ fn try_find_id_in_use(
let find_by_name = |name: &[u8]| { let find_by_name = |name: &[u8]| {
let module = working_set.get_module(module_id); let module = working_set.get_module(module_id);
match id { match id_ref {
Some(Id::Variable(var_id_ref)) => module Some(Id::Variable(var_id_ref)) => module
.constants .constants
.get(name) .get(name)
@ -196,7 +225,7 @@ fn try_find_id_in_use(
let module_name = call.arguments.first()?; let module_name = call.arguments.first()?;
let span = module_name.span(); let span = module_name.span();
let (span_content, clean_span) = strip_quotes(span, working_set); let (span_content, clean_span) = strip_quotes(span, working_set);
if let Some(Id::Module(id_ref, name_ref)) = id { if let Some(Id::Module(id_ref, name_ref)) = id_ref {
// still need to check the rest, if id not matched // still need to check the rest, if id not matched
if module_id == *id_ref && *name_ref == span_content { if module_id == *id_ref && *name_ref == span_content {
return Some((Id::Module(module_id, span_content.to_vec()), clean_span)); return Some((Id::Module(module_id, span_content.to_vec()), clean_span));
@ -262,8 +291,14 @@ fn try_find_id_in_overlay(
call: &Call, call: &Call,
working_set: &StateWorkingSet, working_set: &StateWorkingSet,
location: Option<&usize>, location: Option<&usize>,
id: Option<&Id>, id_ref: Option<&Id>,
) -> Option<(Id, Span)> { ) -> Option<(Id, Span)> {
// skip if the id to search is not a module id
if let Some(id_ref) = id_ref {
if !matches!(id_ref, Id::Module(_, _)) {
return None;
}
}
let check_location = |span: &Span| location.is_none_or(|pos| span.contains(*pos)); let check_location = |span: &Span| location.is_none_or(|pos| span.contains(*pos));
let module_from_parser_info = |span: Span, name: &str| { let module_from_parser_info = |span: Span, name: &str| {
let Expression { let Expression {
@ -274,7 +309,8 @@ fn try_find_id_in_overlay(
return None; return None;
}; };
let found_id = Id::Module(*module_id, name.as_bytes().to_vec()); let found_id = Id::Module(*module_id, name.as_bytes().to_vec());
id.is_none_or(|id_r| found_id == *id_r) id_ref
.is_none_or(|id_r| found_id == *id_r)
.then_some((found_id, strip_quotes(span, working_set).1)) .then_some((found_id, strip_quotes(span, working_set).1))
}; };
// NOTE: `overlay_expr` doesn't exist for `overlay hide` // NOTE: `overlay_expr` doesn't exist for `overlay hide`
@ -283,7 +319,8 @@ fn try_find_id_in_overlay(
working_set.find_overlay(name.as_bytes())?.origin, working_set.find_overlay(name.as_bytes())?.origin,
name.as_bytes().to_vec(), name.as_bytes().to_vec(),
); );
id.is_none_or(|id_r| found_id == *id_r) id_ref
.is_none_or(|id_r| found_id == *id_r)
.then_some((found_id, strip_quotes(span, working_set).1)) .then_some((found_id, strip_quotes(span, working_set).1))
}; };

View File

@ -7,6 +7,7 @@ export def foooo [
export def "foo str" [] { "foo" } export def "foo str" [] { "foo" }
export module "mod name" { export module "mod name" {
# cmt
export module "sub module" { export module "sub module" {
export def "cmd name" [] { } export def "cmd name" [] { }
} }