nu_command/path/
self_.rs

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