1use crate::{
2 known_external::KnownExternal,
3 lite_parser::LiteCommand,
4 parse_helpers::{SPREAD_OPERATOR, garbage},
5 parse_pipelines::redirecting_builtin_error,
6 parser::{
7 ArgumentParsingLevel, CallKind, ParsedInternalCall, compile_block_with_id, parse_attribute,
8 parse_full_signature, parse_internal_call, parse_string,
9 },
10 type_check::check_block_input_output,
11};
12
13use itertools::Itertools;
14use nu_protocol::{
15 CommandWideCompleter, CustomExample, DeclId, FromValue, ParseError, PositionalArg, Signature,
16 Span, Spanned, SyntaxShape, Type, Value,
17 ast::{AttributeBlock, Call, Expr, Expression, Pipeline},
18 category_from_string,
19 engine::{CommandType, StateWorkingSet},
20 eval_const::eval_constant,
21 shell_error::generic::GenericError,
22};
23
24fn rest_param_is_type_annotated(signature_source: &[u8], rest_name: &str) -> bool {
25 let mut needle = Vec::with_capacity(rest_name.len() + 3);
26 needle.extend_from_slice(SPREAD_OPERATOR);
27 needle.extend_from_slice(rest_name.as_bytes());
28
29 if signature_source.len() < needle.len() {
30 return false;
31 }
32
33 for start in 0..=(signature_source.len() - needle.len()) {
34 if signature_source[start..start + needle.len()] != needle {
35 continue;
36 }
37
38 let mut idx = start + needle.len();
39 while idx < signature_source.len() && signature_source[idx].is_ascii_whitespace() {
40 idx += 1;
41 }
42
43 if idx < signature_source.len() && signature_source[idx] == b':' {
44 return true;
45 }
46 }
47
48 false
49}
50
51pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) {
52 let mut pos = 0;
53
54 let def_type_name = if spans.len() >= 3 {
55 let first_word = working_set.get_span_contents(spans[0]);
56
57 if first_word == b"export" {
58 pos += 2;
59 } else {
60 pos += 1;
61 }
62
63 working_set.get_span_contents(spans[pos - 1]).to_vec()
64 } else {
65 return;
66 };
67
68 if def_type_name != b"def" && def_type_name != b"extern" {
69 return;
70 }
71
72 while pos < spans.len() && working_set.get_span_contents(spans[pos]).starts_with(b"-") {
73 pos += 1;
74 }
75
76 if pos >= spans.len() {
77 return;
78 }
79
80 let name_pos = pos;
81
82 let Some(name) = parse_string(working_set, spans[name_pos]).as_string() else {
83 return;
84 };
85
86 if name.contains('#')
87 || name.contains('^')
88 || name.contains('%')
89 || name.parse::<bytesize::ByteSize>().is_ok()
90 || name.parse::<f64>().is_ok()
91 {
92 working_set.error(ParseError::CommandDefNotValid(spans[name_pos]));
93 return;
94 }
95
96 let mut signature_pos = None;
97
98 while pos < spans.len() {
99 if working_set.get_span_contents(spans[pos]).starts_with(b"[")
100 || working_set.get_span_contents(spans[pos]).starts_with(b"(")
101 {
102 signature_pos = Some(pos);
103 break;
104 }
105
106 pos += 1;
107 }
108
109 let Some(signature_pos) = signature_pos else {
110 return;
111 };
112
113 let mut allow_unknown_args = false;
114
115 for span in spans {
116 if working_set.get_span_contents(*span) == b"--wrapped" && def_type_name == b"def" {
117 allow_unknown_args = true;
118 }
119 }
120
121 let starting_error_count = working_set.parse_errors.len();
122
123 working_set.enter_scope();
124 let sig = parse_full_signature(
125 working_set,
126 &spans[signature_pos..],
127 def_type_name == b"extern",
128 );
129 working_set.parse_errors.truncate(starting_error_count);
130 working_set.exit_scope();
131
132 let Some(mut signature) = sig.as_signature() else {
133 return;
134 };
135
136 signature.name = name;
137
138 if allow_unknown_args {
139 if let Some(rest) = &mut signature.rest_positional
140 && !rest_param_is_type_annotated(
141 working_set.get_span_contents(spans[signature_pos]),
142 &rest.name,
143 )
144 {
145 rest.shape = SyntaxShape::ExternalArgument;
146 }
147 signature.allows_unknown_args = true;
148 }
149
150 let command_type = if def_type_name == b"extern" {
151 CommandType::External
152 } else {
153 CommandType::Custom
154 };
155
156 let decl = signature.predeclare_with_command_type(command_type);
157
158 if working_set.add_predecl(decl).is_some() {
159 working_set.error(ParseError::DuplicateCommandDef(spans[name_pos]));
160 }
161}
162
163pub fn parse_for(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Expression {
164 let spans = &lite_command.parts;
165 if working_set.get_span_contents(spans[0]) != b"for" {
166 working_set.error(ParseError::UnknownState(
167 "internal error: Wrong call name for 'for' function".into(),
168 Span::concat(spans),
169 ));
170 return garbage(working_set, spans[0]);
171 }
172 if let Some(redirection) = lite_command.redirection.as_ref() {
173 working_set.error(redirecting_builtin_error("for", redirection));
174 return garbage(working_set, spans[0]);
175 }
176
177 let Some(decl_id) = working_set.find_decl(b"for") else {
178 working_set.error(ParseError::UnknownState(
179 "internal error: for declaration not found".into(),
180 Span::concat(spans),
181 ));
182 return garbage(working_set, spans[0]);
183 };
184
185 let starting_error_count = working_set.parse_errors.len();
186 working_set.enter_scope();
187 let ParsedInternalCall {
188 call,
189 output,
190 call_kind,
191 } = parse_internal_call(
192 working_set,
193 spans[0],
194 &spans[1..],
195 decl_id,
196 ArgumentParsingLevel::Full,
197 None,
198 );
199
200 if working_set
201 .parse_errors
202 .get(starting_error_count..)
203 .is_none_or(|new_errors| {
204 new_errors
205 .iter()
206 .all(|e| !matches!(e, ParseError::Unclosed(token, _) if *token == "}"))
207 })
208 {
209 working_set.exit_scope();
210 }
211
212 let call_span = Span::concat(spans);
213 let decl = working_set.get_decl(decl_id);
214 let sig = decl.signature();
215
216 if call_kind != CallKind::Valid {
217 return Expression::new(working_set, Expr::Call(call), call_span, output);
218 }
219
220 let [var_decl, iteration_expr, block_expr] = call
221 .positional_iter()
222 .next_array()
223 .expect("for call already checked");
224
225 if let Expression {
226 expr: Expr::Block(block_id) | Expr::RowCondition(block_id),
227 ..
228 } = block_expr
229 {
230 let block = working_set.get_block_mut(*block_id);
231
232 *block.signature = sig;
233 };
234
235 fn yielded_type(ty: Type) -> Type {
238 match ty {
239 Type::List(item) => *item,
240 Type::Table(columns) => Type::Record(columns),
241 Type::Range => Type::Number,
242 Type::OneOf(types) => Type::one_of(types.into_iter().map(yielded_type)),
243 ty => ty,
244 }
245 }
246
247 let var_type = match iteration_expr.ty.clone() {
251 Type::OneOf(types) => Type::one_of(types.into_iter().map(yielded_type)),
252 ty => yielded_type(ty),
253 };
254
255 if let (Some(var_id), Some(block_id)) = (var_decl.as_var(), block_expr.as_block()) {
256 working_set.set_variable_type(var_id, var_type.clone());
257
258 let block = working_set.get_block_mut(block_id);
259 block.signature.required_positional.insert(
260 0,
261 PositionalArg {
262 name: String::new(),
263 desc: String::new(),
264 shape: var_type.to_shape(),
265 var_id: Some(var_id),
266 default_value: None,
267 completion: None,
268 },
269 );
270 }
271
272 Expression::new(working_set, Expr::Call(call), call_span, Type::Nothing)
273}
274
275pub fn parse_attribute_block(
276 working_set: &mut StateWorkingSet,
277 lite_command: &LiteCommand,
278) -> Pipeline {
279 let attributes = lite_command
280 .attribute_commands()
281 .map(|cmd| parse_attribute(working_set, &cmd).0)
282 .collect::<Vec<_>>();
283
284 let last_attr_span = attributes
285 .last()
286 .expect("Attribute block must contain at least one attribute")
287 .expr
288 .span;
289
290 working_set.error(ParseError::AttributeRequiresDefinition(last_attr_span));
291 let cmd_span = if lite_command.command_parts().is_empty() {
292 last_attr_span.past()
293 } else {
294 Span::concat(lite_command.command_parts())
295 };
296 let cmd_expr = garbage(working_set, cmd_span);
297 let ty = cmd_expr.ty.clone();
298
299 let attr_block_span = Span::merge_many(
300 attributes
301 .first()
302 .map(|x| x.expr.span)
303 .into_iter()
304 .chain(Some(cmd_span)),
305 );
306
307 Pipeline::from_vec(vec![Expression::new(
308 working_set,
309 Expr::AttributeBlock(AttributeBlock {
310 attributes,
311 item: Box::new(cmd_expr),
312 }),
313 attr_block_span,
314 ty,
315 )])
316}
317
318pub fn parse_def(
319 working_set: &mut StateWorkingSet,
320 lite_command: &LiteCommand,
321 module_name: Option<&[u8]>,
322) -> (Pipeline, Option<(Vec<u8>, DeclId)>) {
323 let mut attributes = vec![];
324 let mut attribute_vals = vec![];
325
326 for attr_cmd in lite_command.attribute_commands() {
327 let (attr, name) = parse_attribute(working_set, &attr_cmd);
328 if let Some(name) = name {
329 let val = eval_constant(working_set, &attr.expr);
330 match val {
331 Ok(val) => attribute_vals.push((name, val)),
332 Err(e) => working_set.error(e.wrap(working_set, attr.expr.span)),
333 }
334 }
335 attributes.push(attr);
336 }
337
338 let (expr, decl) = parse_def_inner(working_set, attribute_vals, lite_command, module_name);
339
340 let ty = expr.ty.clone();
341
342 let attr_block_span = Span::merge_many(
343 attributes
344 .first()
345 .map(|x| x.expr.span)
346 .into_iter()
347 .chain(Some(expr.span)),
348 );
349
350 let expr = if attributes.is_empty() {
351 expr
352 } else {
353 Expression::new(
354 working_set,
355 Expr::AttributeBlock(AttributeBlock {
356 attributes,
357 item: Box::new(expr),
358 }),
359 attr_block_span,
360 ty,
361 )
362 };
363
364 (Pipeline::from_vec(vec![expr]), decl)
365}
366
367pub fn parse_extern(
368 working_set: &mut StateWorkingSet,
369 lite_command: &LiteCommand,
370 module_name: Option<&[u8]>,
371) -> Pipeline {
372 let mut attributes = vec![];
373 let mut attribute_vals = vec![];
374
375 for attr_cmd in lite_command.attribute_commands() {
376 let (attr, name) = parse_attribute(working_set, &attr_cmd);
377 if let Some(name) = name {
378 let val = eval_constant(working_set, &attr.expr);
379 match val {
380 Ok(val) => attribute_vals.push((name, val)),
381 Err(e) => working_set.error(e.wrap(working_set, attr.expr.span)),
382 }
383 }
384 attributes.push(attr);
385 }
386
387 let expr = parse_extern_inner(working_set, attribute_vals, lite_command, module_name);
388
389 let ty = expr.ty.clone();
390
391 let attr_block_span = Span::merge_many(
392 attributes
393 .first()
394 .map(|x| x.expr.span)
395 .into_iter()
396 .chain(Some(expr.span)),
397 );
398
399 let expr = if attributes.is_empty() {
400 expr
401 } else {
402 Expression::new(
403 working_set,
404 Expr::AttributeBlock(AttributeBlock {
405 attributes,
406 item: Box::new(expr),
407 }),
408 attr_block_span,
409 ty,
410 )
411 };
412
413 Pipeline::from_vec(vec![expr])
414}
415
416fn parse_def_inner(
417 working_set: &mut StateWorkingSet,
418 attributes: Vec<(String, Value)>,
419 lite_command: &LiteCommand,
420 module_name: Option<&[u8]>,
421) -> (Expression, Option<(Vec<u8>, DeclId)>) {
422 let spans = lite_command.command_parts();
423
424 let (desc, extra_desc) = working_set.build_desc(&lite_command.comments);
425 let garbage_result =
426 |working_set: &mut StateWorkingSet<'_>| (garbage(working_set, Span::concat(spans)), None);
427
428 let (name_span, split_id) =
429 if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
430 (spans[1], 2)
431 } else {
432 (spans[0], 1)
433 };
434
435 let def_call = working_set.get_span_contents(name_span);
436 if def_call != b"def" {
437 working_set.error(ParseError::UnknownState(
438 "internal error: Wrong call name for def function".into(),
439 Span::concat(spans),
440 ));
441 return garbage_result(working_set);
442 }
443 if let Some(redirection) = lite_command.redirection.as_ref() {
444 working_set.error(redirecting_builtin_error("def", redirection));
445 return garbage_result(working_set);
446 }
447
448 let Some(decl_id) = working_set.permanent_state.find_decl(def_call, &[]) else {
449 working_set.error(ParseError::UnknownState(
450 "internal error: def declaration not found".into(),
451 Span::concat(spans),
452 ));
453 return garbage_result(working_set);
454 };
455
456 working_set.enter_scope();
457 let (command_spans, rest_spans) = spans.split_at(split_id);
458
459 let mut decl_name_span = None;
460
461 for span in rest_spans {
462 if !working_set.get_span_contents(*span).starts_with(b"-") {
463 decl_name_span = Some(*span);
464 break;
465 }
466 }
467
468 if let Some(name_span) = decl_name_span
469 && let Some(err) = detect_params_in_name(working_set, name_span, decl_id)
470 {
471 working_set.error(err);
472 return garbage_result(working_set);
473 }
474
475 let starting_error_count = working_set.parse_errors.len();
476 let ParsedInternalCall {
477 call,
478 output,
479 call_kind,
480 } = parse_internal_call(
481 working_set,
482 Span::concat(command_spans),
483 rest_spans,
484 decl_id,
485 ArgumentParsingLevel::Full,
486 None,
487 );
488
489 if working_set
490 .parse_errors
491 .get(starting_error_count..)
492 .is_none_or(|new_errors| {
493 new_errors
494 .iter()
495 .all(|e| !matches!(e, ParseError::Unclosed(token, _) if *token == "}"))
496 })
497 {
498 working_set.exit_scope();
499 }
500
501 let call_span = Span::concat(spans);
502 let decl = working_set.get_decl(decl_id);
503 let sig = decl.signature();
504
505 match call.positional_iter().nth(2) {
506 Some(Expression {
507 expr: Expr::Closure(block_id),
508 ..
509 }) => {
510 compile_block_with_id(working_set, *block_id);
511 *working_set.get_block_mut(*block_id).signature = sig.clone();
512 }
513 Some(arg) => working_set.error(ParseError::Expected(
514 "definition body closure { ... }",
515 arg.span,
516 )),
517 None => (),
518 }
519
520 if call_kind != CallKind::Valid {
521 return (
522 Expression::new(working_set, Expr::Call(call), call_span, output),
523 None,
524 );
525 }
526
527 let Ok(has_env) = has_flag_const(working_set, &call, "env") else {
528 return garbage_result(working_set);
529 };
530 let Ok(has_wrapped) = has_flag_const(working_set, &call, "wrapped") else {
531 return garbage_result(working_set);
532 };
533
534 let [name_expr, sig_expr, block_expr] = call
535 .positional_iter()
536 .next_array()
537 .expect("def call already checked");
538
539 let Some(name) = name_expr.as_string() else {
540 working_set.error(ParseError::UnknownState(
541 "Could not get string from string expression".into(),
542 name_expr.span,
543 ));
544 return garbage_result(working_set);
545 };
546
547 if let Some(mod_name) = module_name
548 && name.as_bytes() == mod_name
549 {
550 let name_expr_span = name_expr.span;
551
552 working_set.error(ParseError::NamedAsModule(
553 "command".to_string(),
554 name,
555 "main".to_string(),
556 name_expr_span,
557 ));
558 return (
559 Expression::new(working_set, Expr::Call(call), call_span, Type::Any),
560 None,
561 );
562 }
563
564 let mut result = None;
565
566 if let (Some(mut signature), Some(block_id)) = (sig_expr.as_signature(), block_expr.as_block())
567 {
568 if has_wrapped {
569 let Some(rest) = signature.rest_positional.as_mut() else {
570 working_set.error(ParseError::MissingPositional(
571 "...rest-like positional argument".to_string(),
572 name_expr.span,
573 "def --wrapped must have a ...rest-like positional argument. \
574 Add '...rest: string' to the command's signature."
575 .to_string(),
576 ));
577
578 return (
579 Expression::new(working_set, Expr::Call(call), call_span, Type::Any),
580 result,
581 );
582 };
583
584 if !rest_param_is_type_annotated(
585 working_set.get_span_contents(sig_expr.span),
586 &rest.name,
587 ) {
588 rest.shape = SyntaxShape::ExternalArgument;
589 }
590
591 if let Some(var_id) = rest.var_id {
592 let rest_var = &working_set.get_variable(var_id);
593
594 if rest_var.ty != Type::Any && rest_var.ty != Type::List(Box::new(Type::String)) {
595 working_set.error(ParseError::TypeMismatchHelp(
596 Type::List(Box::new(Type::String)),
597 rest_var.ty.clone(),
598 rest_var.declaration_span,
599 format!(
600 "...rest-like positional argument used in 'def --wrapped' supports only strings. \
601 Change the type annotation of ...{} to 'string'.",
602 &rest.name
603 ),
604 ));
605
606 return (
607 Expression::new(working_set, Expr::Call(call), call_span, Type::Any),
608 result,
609 );
610 }
611 }
612 }
613
614 if let Some(decl_id) = working_set.find_predecl(name.as_bytes()) {
615 signature.name.clone_from(&name);
616 if !has_wrapped {
617 *signature = signature.add_help();
618 }
619 signature.description = desc;
620 signature.extra_description = extra_desc;
621 signature.allows_unknown_args = has_wrapped;
622
623 let (attribute_vals, examples) =
624 handle_special_attributes(attributes, working_set, &mut signature);
625
626 let declaration = working_set.get_decl_mut(decl_id);
627
628 *declaration = signature
629 .clone()
630 .into_block_command(block_id, attribute_vals, examples);
631
632 let block = working_set.get_block_mut(block_id);
633 block.signature = signature;
634 block.redirect_env = has_env;
635
636 if block.signature.input_output_types.is_empty() {
637 block
638 .signature
639 .input_output_types
640 .push((Type::Any, Type::Any));
641 }
642
643 let block = working_set.get_block(block_id);
644
645 let typecheck_errors = check_block_input_output(working_set, block);
646
647 working_set
648 .parse_errors
649 .extend_from_slice(&typecheck_errors);
650
651 result = Some((name.as_bytes().to_vec(), decl_id));
652 } else {
653 working_set.error(ParseError::InternalError(
654 "Predeclaration failed to add declaration".into(),
655 name_expr.span,
656 ));
657 };
658 }
659
660 working_set.merge_predecl(name.as_bytes());
661
662 (
663 Expression::new(working_set, Expr::Call(call), call_span, Type::Any),
664 result,
665 )
666}
667
668fn parse_extern_inner(
669 working_set: &mut StateWorkingSet,
670 attributes: Vec<(String, Value)>,
671 lite_command: &LiteCommand,
672 module_name: Option<&[u8]>,
673) -> Expression {
674 let spans = lite_command.command_parts();
675
676 let (description, extra_description) = working_set.build_desc(&lite_command.comments);
677
678 let (name_span, split_id) =
679 if spans.len() > 1 && (working_set.get_span_contents(spans[0]) == b"export") {
680 (spans[1], 2)
681 } else {
682 (spans[0], 1)
683 };
684
685 let extern_call = working_set.get_span_contents(name_span);
686 if extern_call != b"extern" {
687 working_set.error(ParseError::UnknownState(
688 "internal error: Wrong call name for extern command".into(),
689 Span::concat(spans),
690 ));
691 return garbage(working_set, Span::concat(spans));
692 }
693 if let Some(redirection) = lite_command.redirection.as_ref() {
694 working_set.error(redirecting_builtin_error("extern", redirection));
695 return garbage(working_set, Span::concat(spans));
696 }
697
698 let (call, call_span) = match working_set.permanent().find_decl(extern_call, &[]) {
699 None => {
700 working_set.error(ParseError::UnknownState(
701 "internal error: def declaration not found".into(),
702 Span::concat(spans),
703 ));
704 return garbage(working_set, Span::concat(spans));
705 }
706 Some(decl_id) => {
707 working_set.enter_scope();
708
709 let (command_spans, rest_spans) = spans.split_at(split_id);
710
711 if let Some(name_span) = rest_spans.first()
712 && let Some(err) = detect_params_in_name(working_set, *name_span, decl_id)
713 {
714 working_set.error(err);
715 return garbage(working_set, Span::concat(spans));
716 }
717
718 let ParsedInternalCall { call, .. } = parse_internal_call(
719 working_set,
720 Span::concat(command_spans),
721 rest_spans,
722 decl_id,
723 ArgumentParsingLevel::Full,
724 None,
725 );
726 working_set.exit_scope();
727
728 let call_span = Span::concat(spans);
729
730 (call, call_span)
731 }
732 };
733
734 let (name_and_sig_exprs, body_expr) = {
735 let mut positional_iter = call.positional_iter();
736 (positional_iter.next_array::<2>(), positional_iter.next())
737 };
738
739 if let Some([name_expr, sig]) = name_and_sig_exprs {
740 if let (Some(name), Some(mut signature)) = (&name_expr.as_string(), sig.as_signature()) {
741 if let Some(mod_name) = module_name
742 && name.as_bytes() == mod_name
743 {
744 let name_expr_span = name_expr.span;
745 working_set.error(ParseError::NamedAsModule(
746 "known external".to_string(),
747 name.clone(),
748 "main".to_string(),
749 name_expr_span,
750 ));
751 return Expression::new(working_set, Expr::Call(call), call_span, Type::Any);
752 }
753
754 if let Some(decl_id) = working_set.find_predecl(name.as_bytes()) {
755 let external_name = if let Some(mod_name) = module_name {
756 if name.as_bytes() == b"main" {
757 String::from_utf8_lossy(mod_name).to_string()
758 } else {
759 name.clone()
760 }
761 } else {
762 name.clone()
763 };
764
765 signature.name = external_name;
766 signature.description = description;
767 signature.extra_description = extra_description;
768 signature.allows_unknown_args = true;
769
770 let (attribute_vals, examples) =
771 handle_special_attributes(attributes, working_set, &mut signature);
772
773 let declaration = working_set.get_decl_mut(decl_id);
774
775 if let Some(block_id) = body_expr.and_then(|x| x.as_block()) {
776 if signature.rest_positional.is_none() {
777 working_set.error(ParseError::InternalError(
778 "Extern block must have a rest positional argument".into(),
779 name_expr.span,
780 ));
781 } else {
782 *declaration = signature.clone().into_block_command(
783 block_id,
784 attribute_vals,
785 examples,
786 );
787
788 working_set.get_block_mut(block_id).signature = signature;
789 }
790 } else {
791 if signature.rest_positional.is_none() {
792 *signature = signature.rest(
793 "args",
794 SyntaxShape::ExternalArgument,
795 "All other arguments to the command.",
796 );
797 }
798
799 let decl = KnownExternal {
800 signature,
801 attributes: attribute_vals,
802 examples,
803 span: call_span,
804 };
805
806 *declaration = Box::new(decl);
807 }
808 } else {
809 working_set.error(ParseError::InternalError(
810 "Predeclaration failed to add declaration".into(),
811 spans[split_id],
812 ));
813 };
814 }
815 if let Some(name) = name_expr.as_string() {
816 working_set.merge_predecl(name.as_bytes());
817 } else {
818 working_set.error(ParseError::UnknownState(
819 "Could not get string from string expression".into(),
820 name_expr.span,
821 ));
822 }
823 }
824
825 Expression::new(working_set, Expr::Call(call), call_span, Type::Any)
826}
827
828fn handle_special_attributes(
829 attributes: Vec<(String, Value)>,
830 working_set: &mut StateWorkingSet<'_>,
831 signature: &mut Signature,
832) -> (Vec<(String, Value)>, Vec<CustomExample>) {
833 let mut attribute_vals = vec![];
834 let mut examples = vec![];
835 let mut search_terms = vec![];
836 let mut category = String::new();
837
838 for (name, value) in attributes {
839 let val_span = value.span();
840 match name.as_str() {
841 "example" => match CustomExample::from_value(value) {
842 Ok(example) => examples.push(example),
843 Err(_) => {
844 let e = nu_protocol::ShellError::Generic(
845 GenericError::new(
846 "nu::shell::invalid_example",
847 "Value couldn't be converted to an example",
848 val_span,
849 )
850 .with_help("Is `attr example` shadowed?"),
851 );
852 working_set.error(e.wrap(working_set, val_span));
853 }
854 },
855 "search-terms" => match <Vec<String>>::from_value(value) {
856 Ok(mut terms) => {
857 search_terms.append(&mut terms);
858 }
859 Err(_) => {
860 let e = nu_protocol::ShellError::Generic(
861 GenericError::new(
862 "nu::shell::invalid_search_terms",
863 "Value couldn't be converted to search-terms",
864 val_span,
865 )
866 .with_help("Is `attr search-terms` shadowed?"),
867 );
868 working_set.error(e.wrap(working_set, val_span));
869 }
870 },
871 "category" => match <String>::from_value(value) {
872 Ok(term) => {
873 category.push_str(&term);
874 }
875 Err(_) => {
876 let e = nu_protocol::ShellError::Generic(
877 GenericError::new(
878 "nu::shell::invalid_category",
879 "Value couldn't be converted to category",
880 val_span,
881 )
882 .with_help("Is `attr category` shadowed?"),
883 );
884 working_set.error(e.wrap(working_set, val_span));
885 }
886 },
887 "complete" => match <Spanned<String>>::from_value(value) {
888 Ok(Spanned { item, span }) => {
889 if let Some(decl) = working_set.find_decl(item.as_bytes()) {
890 signature.complete = Some(CommandWideCompleter::Command(decl));
891 } else {
892 working_set.error(ParseError::UnknownCommand(span));
893 }
894 }
895 Err(_) => {
896 let e = nu_protocol::ShellError::Generic(
897 GenericError::new(
898 "nu::shell::invalid_completer",
899 "Value couldn't be converted to a completer",
900 val_span,
901 )
902 .with_help("Is `attr complete` shadowed?"),
903 );
904 working_set.error(e.wrap(working_set, val_span));
905 }
906 },
907 "complete external" => match value {
908 nu_protocol::Value::Nothing { .. } => {
909 signature.complete = Some(CommandWideCompleter::External);
910 }
911 _ => {
912 let e = nu_protocol::ShellError::Generic(
913 GenericError::new(
914 "nu::shell::invalid_completer",
915 "This attribute shouldn't return anything",
916 val_span,
917 )
918 .with_help("Is `attr complete` shadowed?"),
919 );
920 working_set.error(e.wrap(working_set, val_span));
921 }
922 },
923 _ => {
924 attribute_vals.push((name, value));
925 }
926 }
927 }
928
929 signature.search_terms = search_terms;
930 signature.category = category_from_string(&category);
931
932 (attribute_vals, examples)
933}
934
935fn detect_params_in_name(
936 working_set: &StateWorkingSet,
937 name_span: Span,
938 decl_id: DeclId,
939) -> Option<ParseError> {
940 let name = working_set.get_span_contents(name_span);
941 for (offset, char) in name.iter().enumerate() {
942 if *char == b'[' || *char == b'(' {
943 return Some(ParseError::LabeledErrorWithHelp {
944 error: "no space between name and parameters".into(),
945 label: "expected space".into(),
946 help: format!(
947 "consider adding a space between the `{}` command's name and its parameters",
948 working_set.get_decl(decl_id).name()
949 ),
950 span: Span::new(offset + name_span.start - 1, offset + name_span.start - 1),
951 });
952 }
953 }
954
955 None
956}
957
958pub(crate) fn has_flag_const(
959 working_set: &mut StateWorkingSet,
960 call: &Call,
961 name: &str,
962) -> Result<bool, ()> {
963 call.has_flag_const(working_set, name).map_err(|err| {
964 working_set.error(err.wrap(working_set, call.span()));
965 })
966}