1use nu_protocol::{
2 Range, ShellError, Span, Value,
3 engine::{EngineState, Stack},
4 shell_error::generic::GenericError,
5};
6use std::ops::Bound;
7
8type MakeRangeError = fn(&str, Span) -> ShellError;
9
10pub fn process_range(range: &Range) -> Result<(isize, isize), MakeRangeError> {
12 match range {
13 Range::IntRange(range) => {
14 let start = range.start().try_into().unwrap_or(0);
15 let end = match range.end() {
16 Bound::Included(v) => v as isize,
17 Bound::Excluded(v) => (v - 1) as isize,
18 Bound::Unbounded => isize::MAX,
19 };
20 Ok((start, end))
21 }
22 Range::FloatRange(_) => Err(|msg, span| ShellError::TypeMismatch {
23 err_message: msg.to_string(),
24 span,
25 }),
26 }
27}
28
29const HELP_MSG: &str = "Nushell's config file can be found with the command: $nu.config-path. \
30For more help: (https://nushell.sh/book/configuration.html#configurations-with-built-in-commands)";
31
32fn get_editor_commandline(
33 value: &Value,
34 var_name: &str,
35) -> Result<(String, Vec<String>), ShellError> {
36 match value {
37 Value::String { val, .. } if !val.is_empty() => Ok((val.to_string(), Vec::new())),
38 Value::List { vals, .. } if !vals.is_empty() => {
39 let mut editor_cmd = vals.iter().map(|l| l.coerce_string());
40 match editor_cmd.next().transpose()? {
41 Some(editor) if !editor.is_empty() => {
42 let params = editor_cmd.collect::<Result<_, ShellError>>()?;
43 Ok((editor, params))
44 }
45 _ => Err(ShellError::Generic(
46 GenericError::new(
47 "Editor executable is missing",
48 "Set the first element to an executable",
49 value.span(),
50 )
51 .with_help(HELP_MSG),
52 )),
53 }
54 }
55 Value::String { .. } | Value::List { .. } => Err(ShellError::Generic(
56 GenericError::new(
57 format!("{var_name} should be a non-empty string or list<String>"),
58 "Specify an executable here",
59 value.span(),
60 )
61 .with_help(HELP_MSG),
62 )),
63 x => Err(ShellError::CantConvert {
64 to_type: "string or list<string>".into(),
65 from_type: x.get_type().to_string(),
66 span: value.span(),
67 help: None,
68 }),
69 }
70}
71
72pub fn get_editor(
73 engine_state: &EngineState,
74 stack: &Stack,
75 span: Span,
76) -> Result<(String, Vec<String>), ShellError> {
77 let config = stack.get_config(engine_state);
78
79 if let Ok(buff_editor) =
80 get_editor_commandline(&config.buffer_editor, "$env.config.buffer_editor")
81 {
82 Ok(buff_editor)
83 } else if let Some(value) = stack.get_env_var(engine_state, "VISUAL") {
84 get_editor_commandline(value, "$env.VISUAL")
85 } else if let Some(value) = stack.get_env_var(engine_state, "EDITOR") {
86 get_editor_commandline(value, "$env.EDITOR")
87 } else {
88 Err(ShellError::Generic(
89 GenericError::new(
90 "No editor configured",
91 "Please specify one via `$env.config.buffer_editor` or `$env.EDITOR`/`$env.VISUAL`",
92 span,
93 )
94 .with_help(HELP_MSG),
95 ))
96 }
97}