mirror of
https://github.com/nushell/nushell
synced 2024-12-26 04:53:09 +00:00
Add path self
command for getting absolute paths to files at parse time (#14303)
Alternative solution to: - #12195 The other approach: - #14305 # Description Adds ~`path const`~ `path self`, a parse-time only command for getting the absolute path of the source file containing it, or any file relative to the source file. - Useful for any script or module that makes use of non nuscript files. - Removes the need for `$env.CURRENT_FILE` and `$env.FILE_PWD`. - Can be used in modules, sourced files or scripts. # Examples ```nushell # ~/.config/nushell/scripts/foo.nu const paths = { self: (path self), dir: (path self .), sibling: (path self sibling), parent_dir: (path self ..), cousin: (path self ../cousin), } export def main [] { $paths } ``` ```nushell > use foo.nu > foo ╭────────────┬────────────────────────────────────────────╮ │ self │ /home/user/.config/nushell/scripts/foo.nu │ │ dir │ /home/user/.config/nushell/scripts │ │ sibling │ /home/user/.config/nushell/scripts/sibling │ │ parent_dir │ /home/user/.config/nushell │ │ cousin │ /home/user/.config/nushell/cousin │ ╰────────────┴────────────────────────────────────────────╯ ``` Trying to run in a non-const context ```nushell > path self Error: × this command can only run during parse-time ╭─[entry #1:1:1] 1 │ path self · ─────┬──── · ╰── can't run after parse-time ╰──── help: try assigning this command's output to a const variable ``` Trying to run in the REPL i.e. not in a file ```nushell > const foo = path self Error: × Error: nu:🐚:file_not_found │ │ × File not found │ ╭─[entry #3:1:13] │ 1 │ const foo = path self │ · ─────┬──── │ · ╰── Couldn't find current file │ ╰──── │ ╭─[entry #3:1:13] 1 │ const foo = path self · ─────┬──── · ╰── Encountered error during parse-time evaluation ╰──── ``` # Comparison with #14305 ## Pros - Self contained implementation, does not require changes in the parser. - More concise usage, especially with parent directories. --------- Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
This commit is contained in:
parent
cda9ae1e42
commit
8771872d86
3 changed files with 132 additions and 0 deletions
|
@ -106,6 +106,7 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
|||
bind_command! {
|
||||
Path,
|
||||
PathBasename,
|
||||
PathSelf,
|
||||
PathDirname,
|
||||
PathExists,
|
||||
PathExpand,
|
||||
|
|
|
@ -6,6 +6,7 @@ mod join;
|
|||
mod parse;
|
||||
pub mod path_;
|
||||
mod relative_to;
|
||||
mod self_;
|
||||
mod split;
|
||||
mod r#type;
|
||||
|
||||
|
@ -18,6 +19,7 @@ pub use parse::SubCommand as PathParse;
|
|||
pub use path_::PathCommand as Path;
|
||||
pub use r#type::SubCommand as PathType;
|
||||
pub use relative_to::SubCommand as PathRelativeTo;
|
||||
pub use self_::SubCommand as PathSelf;
|
||||
pub use split::SubCommand as PathSplit;
|
||||
|
||||
use nu_protocol::{ShellError, Span, Value};
|
||||
|
|
129
crates/nu-command/src/path/self_.rs
Normal file
129
crates/nu-command/src/path/self_.rs
Normal file
|
@ -0,0 +1,129 @@
|
|||
use nu_engine::command_prelude::*;
|
||||
use nu_path::expand_path_with;
|
||||
use nu_protocol::engine::StateWorkingSet;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
||||
impl Command for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"path self"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("path self")
|
||||
.input_output_type(Type::Nothing, Type::String)
|
||||
.allow_variants_without_examples(true)
|
||||
.optional(
|
||||
"path",
|
||||
SyntaxShape::Filepath,
|
||||
"Path to get instead of the current file.",
|
||||
)
|
||||
.category(Category::Path)
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
"Get the absolute path of the script or module containing this command at parse time."
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Err(ShellError::GenericError {
|
||||
error: "this command can only run during parse-time".into(),
|
||||
msg: "can't run after parse-time".into(),
|
||||
span: Some(call.head),
|
||||
help: Some("try assigning this command's output to a const variable".into()),
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let path: Option<String> = call.opt_const(working_set, 0)?;
|
||||
let cwd = working_set.permanent_state.cwd(None)?;
|
||||
let current_file =
|
||||
working_set
|
||||
.files
|
||||
.top()
|
||||
.ok_or_else(|| ShellError::FileNotFoundCustom {
|
||||
msg: "Couldn't find current file".into(),
|
||||
span: call.head,
|
||||
})?;
|
||||
|
||||
let out = if let Some(path) = path {
|
||||
let dir = expand_path_with(
|
||||
current_file
|
||||
.parent()
|
||||
.ok_or_else(|| ShellError::FileNotFoundCustom {
|
||||
msg: "Couldn't find current file's parent.".into(),
|
||||
span: call.head,
|
||||
})?,
|
||||
&cwd,
|
||||
true,
|
||||
);
|
||||
Value::string(
|
||||
expand_path_with(path, dir, false).to_string_lossy(),
|
||||
call.head,
|
||||
)
|
||||
} else {
|
||||
Value::string(
|
||||
expand_path_with(current_file, &cwd, true).to_string_lossy(),
|
||||
call.head,
|
||||
)
|
||||
};
|
||||
|
||||
Ok(out.into_pipeline_data())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Get the path of the current file",
|
||||
example: r#"const current_file = path self"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Get the path of the directory containing the current file",
|
||||
example: r#"const current_file = path self ."#,
|
||||
result: None,
|
||||
},
|
||||
#[cfg(windows)]
|
||||
Example {
|
||||
description: "Get the absolute form of a path relative to the current file",
|
||||
example: r#"const current_file = path self ..\foo"#,
|
||||
result: None,
|
||||
},
|
||||
#[cfg(not(windows))]
|
||||
Example {
|
||||
description: "Get the absolute form of a path relative to the current file",
|
||||
example: r#"const current_file = path self ../foo"#,
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
use crate::test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue