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