nu_command/path/
self_.rs

1use nu_engine::command_prelude::*;
2use nu_path::expand_path_with;
3use nu_protocol::{engine::StateWorkingSet, shell_error::io::IoError};
4
5#[derive(Clone)]
6pub struct PathSelf;
7
8impl Command for PathSelf {
9    fn name(&self) -> &str {
10        "path self"
11    }
12
13    fn signature(&self) -> Signature {
14        Signature::build("path self")
15            .input_output_type(Type::Nothing, Type::String)
16            .allow_variants_without_examples(true)
17            .optional(
18                "path",
19                SyntaxShape::Filepath,
20                "Path to get instead of the current file.",
21            )
22            .category(Category::Path)
23    }
24
25    fn description(&self) -> &str {
26        "Get the absolute path of the script or module containing this command at parse time."
27    }
28
29    fn is_const(&self) -> bool {
30        true
31    }
32
33    fn run(
34        &self,
35        _engine_state: &EngineState,
36        _stack: &mut Stack,
37        call: &Call,
38        _input: PipelineData,
39    ) -> Result<PipelineData, ShellError> {
40        Err(ShellError::GenericError {
41            error: "this command can only run during parse-time".into(),
42            msg: "can't run after parse-time".into(),
43            span: Some(call.head),
44            help: Some("try assigning this command's output to a const variable".into()),
45            inner: vec![],
46        })
47    }
48
49    fn run_const(
50        &self,
51        working_set: &StateWorkingSet,
52        call: &Call,
53        _input: PipelineData,
54    ) -> Result<PipelineData, ShellError> {
55        let path: Option<String> = call.opt_const(working_set, 0)?;
56        let cwd = working_set.permanent_state.cwd(None)?;
57        let current_file = working_set.files.top().ok_or_else(|| {
58            IoError::new_with_additional_context(
59                std::io::ErrorKind::NotFound,
60                call.head,
61                None,
62                "Couldn't find current file",
63            )
64        })?;
65
66        let out = if let Some(path) = path {
67            let dir = expand_path_with(
68                current_file.parent().ok_or_else(|| {
69                    IoError::new_with_additional_context(
70                        std::io::ErrorKind::NotFound,
71                        call.head,
72                        current_file.to_owned(),
73                        "Couldn't find current file's parent.",
74                    )
75                })?,
76                &cwd,
77                true,
78            );
79            Value::string(
80                expand_path_with(path, dir, false).to_string_lossy(),
81                call.head,
82            )
83        } else {
84            Value::string(
85                expand_path_with(current_file, &cwd, true).to_string_lossy(),
86                call.head,
87            )
88        };
89
90        Ok(out.into_pipeline_data())
91    }
92
93    fn examples(&self) -> Vec<Example> {
94        vec![
95            Example {
96                description: "Get the path of the current file",
97                example: r#"const current_file = path self"#,
98                result: None,
99            },
100            Example {
101                description: "Get the path of the directory containing the current file",
102                example: r#"const current_file = path self ."#,
103                result: None,
104            },
105            #[cfg(windows)]
106            Example {
107                description: "Get the absolute form of a path relative to the current file",
108                example: r#"const current_file = path self ..\foo"#,
109                result: None,
110            },
111            #[cfg(not(windows))]
112            Example {
113                description: "Get the absolute form of a path relative to the current file",
114                example: r#"const current_file = path self ../foo"#,
115                result: None,
116            },
117        ]
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    #[test]
126    fn test_examples() {
127        use crate::test_examples;
128
129        test_examples(PathSelf {})
130    }
131}