forked from extern/nushell
Expand Nushell's help system (#7611)
This commit is contained in:
@ -25,7 +25,7 @@ use crate::{
|
||||
parse_internal_call, parse_multispan_value, parse_signature, parse_string, parse_value,
|
||||
parse_var_with_opt_type, trim_quotes, ParsedInternalCall,
|
||||
},
|
||||
unescape_unquote_string, ParseError,
|
||||
unescape_unquote_string, ParseError, Token, TokenContents,
|
||||
};
|
||||
|
||||
pub fn parse_def_predecl(
|
||||
@ -229,57 +229,6 @@ pub fn parse_for(
|
||||
)
|
||||
}
|
||||
|
||||
fn build_usage(working_set: &StateWorkingSet, spans: &[Span]) -> String {
|
||||
let mut usage = String::new();
|
||||
|
||||
let mut num_spaces = 0;
|
||||
let mut first = true;
|
||||
|
||||
// Use the comments to build the usage
|
||||
for comment_part in spans {
|
||||
let contents = working_set.get_span_contents(*comment_part);
|
||||
|
||||
let comment_line = if first {
|
||||
// Count the number of spaces still at the front, skipping the '#'
|
||||
let mut pos = 1;
|
||||
while pos < contents.len() {
|
||||
if let Some(b' ') = contents.get(pos) {
|
||||
// continue
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
num_spaces = pos;
|
||||
|
||||
first = false;
|
||||
|
||||
String::from_utf8_lossy(&contents[pos..]).to_string()
|
||||
} else {
|
||||
let mut pos = 1;
|
||||
|
||||
while pos < contents.len() && pos < num_spaces {
|
||||
if let Some(b' ') = contents.get(pos) {
|
||||
// continue
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
String::from_utf8_lossy(&contents[pos..]).to_string()
|
||||
};
|
||||
|
||||
if !usage.is_empty() {
|
||||
usage.push('\n');
|
||||
}
|
||||
usage.push_str(&comment_line);
|
||||
}
|
||||
|
||||
usage
|
||||
}
|
||||
|
||||
pub fn parse_def(
|
||||
working_set: &mut StateWorkingSet,
|
||||
lite_command: &LiteCommand,
|
||||
@ -287,7 +236,7 @@ pub fn parse_def(
|
||||
) -> (Pipeline, Option<ParseError>) {
|
||||
let spans = &lite_command.parts[..];
|
||||
|
||||
let usage = build_usage(working_set, &lite_command.comments);
|
||||
let (usage, extra_usage) = working_set.build_usage(&lite_command.comments);
|
||||
|
||||
// Checking that the function is used with the correct name
|
||||
// Maybe this is not necessary but it is a sanity check
|
||||
@ -397,6 +346,7 @@ pub fn parse_def(
|
||||
signature.name = name.clone();
|
||||
*signature = signature.add_help();
|
||||
signature.usage = usage;
|
||||
signature.extra_usage = extra_usage;
|
||||
|
||||
*declaration = signature.clone().into_block_command(block_id);
|
||||
|
||||
@ -444,7 +394,7 @@ pub fn parse_extern(
|
||||
let spans = &lite_command.parts;
|
||||
let mut error = None;
|
||||
|
||||
let usage = build_usage(working_set, &lite_command.comments);
|
||||
let (usage, extra_usage) = working_set.build_usage(&lite_command.comments);
|
||||
|
||||
// Checking that the function is used with the correct name
|
||||
// Maybe this is not necessary but it is a sanity check
|
||||
@ -515,11 +465,12 @@ pub fn parse_extern(
|
||||
|
||||
signature.name = name.clone();
|
||||
signature.usage = usage.clone();
|
||||
signature.extra_usage = extra_usage.clone();
|
||||
signature.allows_unknown_args = true;
|
||||
|
||||
let decl = KnownExternal {
|
||||
name: name.to_string(),
|
||||
usage,
|
||||
usage: [usage, extra_usage].join("\n"),
|
||||
signature,
|
||||
};
|
||||
|
||||
@ -559,9 +510,11 @@ pub fn parse_extern(
|
||||
|
||||
pub fn parse_alias(
|
||||
working_set: &mut StateWorkingSet,
|
||||
spans: &[Span],
|
||||
lite_command: &LiteCommand,
|
||||
expand_aliases_denylist: &[usize],
|
||||
) -> (Pipeline, Option<ParseError>) {
|
||||
let spans = &lite_command.parts;
|
||||
|
||||
// if the call is "alias", turn it into "print $nu.scope.aliases"
|
||||
if spans.len() == 1 {
|
||||
let head = Expression {
|
||||
@ -672,7 +625,7 @@ pub fn parse_alias(
|
||||
);
|
||||
}
|
||||
|
||||
working_set.add_alias(alias_name, replacement);
|
||||
working_set.add_alias(alias_name, replacement, lite_command.comments.clone());
|
||||
}
|
||||
|
||||
let err = if spans.len() < 4 {
|
||||
@ -785,7 +738,7 @@ pub fn parse_export_in_block(
|
||||
}
|
||||
|
||||
match full_name.as_slice() {
|
||||
b"export alias" => parse_alias(working_set, &lite_command.parts, expand_aliases_denylist),
|
||||
b"export alias" => parse_alias(working_set, lite_command, expand_aliases_denylist),
|
||||
b"export def" | b"export def-env" => {
|
||||
parse_def(working_set, lite_command, expand_aliases_denylist)
|
||||
}
|
||||
@ -1075,7 +1028,7 @@ pub fn parse_export_in_module(
|
||||
parts: spans[1..].to_vec(),
|
||||
};
|
||||
let (pipeline, err) =
|
||||
parse_alias(working_set, &lite_command.parts, expand_aliases_denylist);
|
||||
parse_alias(working_set, &lite_command, expand_aliases_denylist);
|
||||
error = error.or(err);
|
||||
|
||||
let export_alias_decl_id =
|
||||
@ -1328,11 +1281,41 @@ pub fn parse_export_env(
|
||||
(pipeline, Some(block_id), None)
|
||||
}
|
||||
|
||||
fn collect_first_comments(tokens: &[Token]) -> Vec<Span> {
|
||||
let mut comments = vec![];
|
||||
|
||||
let mut tokens_iter = tokens.iter().peekable();
|
||||
while let Some(token) = tokens_iter.next() {
|
||||
match token.contents {
|
||||
TokenContents::Comment => {
|
||||
comments.push(token.span);
|
||||
}
|
||||
TokenContents::Eol => {
|
||||
if let Some(Token {
|
||||
contents: TokenContents::Eol,
|
||||
..
|
||||
}) = tokens_iter.peek()
|
||||
{
|
||||
if !comments.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
comments.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
comments
|
||||
}
|
||||
|
||||
pub fn parse_module_block(
|
||||
working_set: &mut StateWorkingSet,
|
||||
span: Span,
|
||||
expand_aliases_denylist: &[usize],
|
||||
) -> (Block, Module, Option<ParseError>) {
|
||||
) -> (Block, Module, Vec<Span>, Option<ParseError>) {
|
||||
let mut error = None;
|
||||
|
||||
working_set.enter_scope();
|
||||
@ -1342,6 +1325,8 @@ pub fn parse_module_block(
|
||||
let (output, err) = lex(source, span.start, &[], &[], false);
|
||||
error = error.or(err);
|
||||
|
||||
let module_comments = collect_first_comments(&output);
|
||||
|
||||
let (output, err) = lite_parse(&output);
|
||||
error = error.or(err);
|
||||
|
||||
@ -1378,11 +1363,8 @@ pub fn parse_module_block(
|
||||
(pipeline, err)
|
||||
}
|
||||
b"alias" => {
|
||||
let (pipeline, err) = parse_alias(
|
||||
working_set,
|
||||
&command.parts,
|
||||
expand_aliases_denylist,
|
||||
);
|
||||
let (pipeline, err) =
|
||||
parse_alias(working_set, command, expand_aliases_denylist);
|
||||
|
||||
(pipeline, err)
|
||||
}
|
||||
@ -1452,17 +1434,20 @@ pub fn parse_module_block(
|
||||
|
||||
working_set.exit_scope();
|
||||
|
||||
(block, module, error)
|
||||
(block, module, module_comments, error)
|
||||
}
|
||||
|
||||
pub fn parse_module(
|
||||
working_set: &mut StateWorkingSet,
|
||||
spans: &[Span],
|
||||
lite_command: &LiteCommand,
|
||||
expand_aliases_denylist: &[usize],
|
||||
) -> (Pipeline, Option<ParseError>) {
|
||||
// TODO: Currently, module is closing over its parent scope (i.e., defs in the parent scope are
|
||||
// visible and usable in this module's scope). We want to disable that for files.
|
||||
|
||||
let spans = &lite_command.parts;
|
||||
let mut module_comments = lite_command.comments.clone();
|
||||
|
||||
let mut error = None;
|
||||
let bytes = working_set.get_span_contents(spans[0]);
|
||||
|
||||
@ -1496,12 +1481,14 @@ pub fn parse_module(
|
||||
|
||||
let block_span = Span::new(start, end);
|
||||
|
||||
let (block, module, err) =
|
||||
let (block, module, inner_comments, err) =
|
||||
parse_module_block(working_set, block_span, expand_aliases_denylist);
|
||||
error = error.or(err);
|
||||
|
||||
let block_id = working_set.add_block(block);
|
||||
let _ = working_set.add_module(&module_name, module);
|
||||
|
||||
module_comments.extend(inner_comments);
|
||||
let _ = working_set.add_module(&module_name, module, module_comments);
|
||||
|
||||
let block_expr = Expression {
|
||||
expr: Expr::Block(block_id),
|
||||
@ -1734,7 +1721,7 @@ pub fn parse_use(
|
||||
working_set.parsed_module_files.push(module_path);
|
||||
|
||||
// Parse the module
|
||||
let (block, module, err) = parse_module_block(
|
||||
let (block, module, module_comments, err) = parse_module_block(
|
||||
working_set,
|
||||
Span::new(span_start, span_end),
|
||||
expand_aliases_denylist,
|
||||
@ -1748,7 +1735,8 @@ pub fn parse_use(
|
||||
working_set.currently_parsed_cwd = prev_currently_parsed_cwd;
|
||||
|
||||
let _ = working_set.add_block(block);
|
||||
let module_id = working_set.add_module(&module_name, module.clone());
|
||||
let module_id =
|
||||
working_set.add_module(&module_name, module.clone(), module_comments);
|
||||
|
||||
(
|
||||
ImportPattern {
|
||||
@ -2320,7 +2308,7 @@ pub fn parse_overlay_new(
|
||||
custom_completion: None,
|
||||
}]);
|
||||
|
||||
let module_id = working_set.add_module(&overlay_name, Module::new());
|
||||
let module_id = working_set.add_module(&overlay_name, Module::new(), vec![]);
|
||||
|
||||
working_set.add_overlay(
|
||||
overlay_name.as_bytes().to_vec(),
|
||||
@ -2557,7 +2545,7 @@ pub fn parse_overlay_use(
|
||||
working_set.currently_parsed_cwd.clone()
|
||||
};
|
||||
|
||||
let (block, module, err) = parse_module_block(
|
||||
let (block, module, module_comments, err) = parse_module_block(
|
||||
working_set,
|
||||
Span::new(span_start, span_end),
|
||||
expand_aliases_denylist,
|
||||
@ -2568,7 +2556,8 @@ pub fn parse_overlay_use(
|
||||
working_set.currently_parsed_cwd = prev_currently_parsed_cwd;
|
||||
|
||||
let _ = working_set.add_block(block);
|
||||
let module_id = working_set.add_module(&overlay_name, module.clone());
|
||||
let module_id =
|
||||
working_set.add_module(&overlay_name, module.clone(), module_comments);
|
||||
|
||||
(
|
||||
new_name.map(|spanned| spanned.item).unwrap_or(overlay_name),
|
||||
|
@ -5248,8 +5248,8 @@ pub fn parse_builtin_commands(
|
||||
let (expr, err) = parse_for(working_set, &lite_command.parts, expand_aliases_denylist);
|
||||
(Pipeline::from_vec(vec![expr]), err)
|
||||
}
|
||||
b"alias" => parse_alias(working_set, &lite_command.parts, expand_aliases_denylist),
|
||||
b"module" => parse_module(working_set, &lite_command.parts, expand_aliases_denylist),
|
||||
b"alias" => parse_alias(working_set, lite_command, expand_aliases_denylist),
|
||||
b"module" => parse_module(working_set, lite_command, expand_aliases_denylist),
|
||||
b"use" => {
|
||||
let (pipeline, _, err) =
|
||||
parse_use(working_set, &lite_command.parts, expand_aliases_denylist);
|
||||
|
Reference in New Issue
Block a user