forked from extern/nushell
Add pathvar
command (#3670)
* Add pathvar command Signed-off-by: nathom <nathanthomas707@gmail.com> * Add pathvar command to context Signed-off-by: nathom <nathanthomas707@gmail.com> * Add pathvar reset command Signed-off-by: nathom <nathanthomas707@gmail.com> * Update help message Signed-off-by: nathom <nathanthomas707@gmail.com> * Remove insert command Signed-off-by: nathom <nathanthomas707@gmail.com> * Remove unused import Signed-off-by: nathom <nathanthomas707@gmail.com> * Remove insert mod Signed-off-by: nathom <nathanthomas707@gmail.com> * Support for windows path separator Signed-off-by: nathom <nathanthomas707@gmail.com> * Clear clippy errors Signed-off-by: nathom <nathanthomas707@gmail.com> * Remove empty file Signed-off-by: nathom <nathanthomas707@gmail.com> * Formatting Signed-off-by: nathom <nathanthomas707@gmail.com>
This commit is contained in:
parent
6ba40773bb
commit
a3f119e0bd
@ -12,6 +12,7 @@ mod generators;
|
||||
mod math;
|
||||
mod network;
|
||||
mod path;
|
||||
mod pathvar;
|
||||
mod platform;
|
||||
mod random;
|
||||
mod shells;
|
||||
@ -43,6 +44,7 @@ pub use generators::*;
|
||||
pub use math::*;
|
||||
pub use network::*;
|
||||
pub use path::*;
|
||||
pub use pathvar::*;
|
||||
pub use platform::*;
|
||||
pub use random::*;
|
||||
pub use shells::*;
|
||||
|
59
crates/nu-command/src/commands/pathvar/add.rs
Normal file
59
crates/nu-command/src/commands/pathvar/add.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"pathvar add"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("pathvar add").required("path", SyntaxShape::FilePath, "path to add")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Add a filepath to the start of the pathvar"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
add(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Add /usr/local/bin to the pathvar",
|
||||
example: "pathvar add /usr/local/bin",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let ctx = &args.context;
|
||||
|
||||
let path_to_add: Tagged<PathBuf> = args.req(0)?;
|
||||
let path = path_to_add.item.into_os_string().into_string();
|
||||
|
||||
if let Ok(mut path) = path {
|
||||
path.push(NATIVE_PATH_ENV_SEPARATOR);
|
||||
if let Some(old_pathvar) = ctx.scope.get_env(NATIVE_PATH_ENV_VAR) {
|
||||
path.push_str(&old_pathvar);
|
||||
ctx.scope.add_env_var(NATIVE_PATH_ENV_VAR, path);
|
||||
Ok(OutputStream::empty())
|
||||
} else {
|
||||
Err(ShellError::unexpected("PATH not set"))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Invalid path.",
|
||||
"cannot convert to string",
|
||||
path_to_add.tag,
|
||||
))
|
||||
}
|
||||
}
|
58
crates/nu-command/src/commands/pathvar/append.rs
Normal file
58
crates/nu-command/src/commands/pathvar/append.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"pathvar append"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("pathvar append").required("path", SyntaxShape::FilePath, "path to append")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Add a path to the end of the pathvar"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
add(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Append /bin to the pathvar",
|
||||
example: "pathvar append /bin",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let ctx = &args.context;
|
||||
let path_to_append_arg: Tagged<PathBuf> = args.req(0)?;
|
||||
let path_to_append = path_to_append_arg.item.into_os_string().into_string();
|
||||
|
||||
if let Ok(path) = path_to_append {
|
||||
if let Some(mut pathvar) = ctx.scope.get_env(NATIVE_PATH_ENV_VAR) {
|
||||
pathvar.push(NATIVE_PATH_ENV_SEPARATOR);
|
||||
pathvar.push_str(&path);
|
||||
ctx.scope.add_env_var(NATIVE_PATH_ENV_VAR, pathvar);
|
||||
Ok(OutputStream::empty())
|
||||
} else {
|
||||
Err(ShellError::unexpected("PATH not set"))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Invalid path.",
|
||||
"cannot convert to string",
|
||||
path_to_append_arg.tag,
|
||||
))
|
||||
}
|
||||
}
|
58
crates/nu-command/src/commands/pathvar/command.rs
Normal file
58
crates/nu-command/src/commands/pathvar/command.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, Value};
|
||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
||||
|
||||
pub struct Command;
|
||||
|
||||
impl WholeStreamCommand for Command {
|
||||
fn name(&self) -> &str {
|
||||
"pathvar"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("pathvar")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Manipulate the PATH variable (or pathvar)."
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
get_pathvar(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Display the current session's pathvar",
|
||||
example: "pathvar",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Add /usr/bin to the pathvar",
|
||||
example: "pathvar add /usr/bin",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Remove the 3rd path in the pathvar",
|
||||
example: "pathvar remove 2",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pathvar(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if let Some(pathvar) = args.context.scope.get_env(NATIVE_PATH_ENV_VAR) {
|
||||
let pathvar: Vec<Value> = pathvar
|
||||
.split(NATIVE_PATH_ENV_SEPARATOR)
|
||||
.map(Value::from)
|
||||
.collect();
|
||||
|
||||
Ok(OutputStream::from(pathvar))
|
||||
} else {
|
||||
Err(ShellError::unexpected("PATH not set"))
|
||||
}
|
||||
}
|
13
crates/nu-command/src/commands/pathvar/mod.rs
Normal file
13
crates/nu-command/src/commands/pathvar/mod.rs
Normal file
@ -0,0 +1,13 @@
|
||||
pub mod add;
|
||||
pub mod append;
|
||||
pub mod command;
|
||||
pub mod remove;
|
||||
pub mod reset;
|
||||
pub mod save;
|
||||
|
||||
pub use add::SubCommand as PathvarAdd;
|
||||
pub use append::SubCommand as PathvarAppend;
|
||||
pub use command::Command as Pathvar;
|
||||
pub use remove::SubCommand as PathvarRemove;
|
||||
pub use reset::SubCommand as PathvarReset;
|
||||
pub use save::SubCommand as PathvarSave;
|
66
crates/nu-command/src/commands/pathvar/remove.rs
Normal file
66
crates/nu-command/src/commands/pathvar/remove.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"pathvar remove"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("pathvar remove").required(
|
||||
"index",
|
||||
SyntaxShape::Int,
|
||||
"index of the path to remove (starting at 0)",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Remove a path from the pathvar"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
remove(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Remove the second path from the pathvar",
|
||||
example: "pathvar remove 1",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let ctx = &args.context;
|
||||
let index_to_remove_arg: Tagged<u64> = args.req(0)?;
|
||||
let index_to_remove = index_to_remove_arg.item as usize;
|
||||
|
||||
if let Some(old_pathvar) = ctx.scope.get_env(NATIVE_PATH_ENV_VAR) {
|
||||
let mut paths: Vec<&str> = old_pathvar.split(NATIVE_PATH_ENV_SEPARATOR).collect();
|
||||
|
||||
if index_to_remove >= paths.len() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Index out of bounds",
|
||||
format!("the index must be between 0 and {}", paths.len() - 1),
|
||||
index_to_remove_arg.tag,
|
||||
));
|
||||
}
|
||||
|
||||
paths.remove(index_to_remove);
|
||||
ctx.scope.add_env_var(
|
||||
NATIVE_PATH_ENV_VAR,
|
||||
paths.join(&NATIVE_PATH_ENV_SEPARATOR.to_string()),
|
||||
);
|
||||
|
||||
Ok(OutputStream::empty())
|
||||
} else {
|
||||
Err(ShellError::unexpected("PATH not set"))
|
||||
}
|
||||
}
|
52
crates/nu-command/src/commands/pathvar/reset.rs
Normal file
52
crates/nu-command/src/commands/pathvar/reset.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, UntaggedValue};
|
||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"pathvar reset"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("pathvar reset")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Reset the pathvar to the one specified in the config"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
reset(args)
|
||||
}
|
||||
}
|
||||
pub fn reset(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let ctx = &args.context;
|
||||
|
||||
if let Some(global_cfg) = &mut ctx.configs().lock().global_config {
|
||||
let default_pathvar = global_cfg.vars.get("path");
|
||||
if let Some(pathvar) = default_pathvar {
|
||||
if let UntaggedValue::Table(paths) = &pathvar.value {
|
||||
let pathvar_str = paths
|
||||
.iter()
|
||||
.map(|x| x.as_string().expect("Error converting path to string"))
|
||||
.join(&NATIVE_PATH_ENV_SEPARATOR.to_string());
|
||||
ctx.scope.add_env_var(NATIVE_PATH_ENV_VAR, pathvar_str);
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::untagged_runtime_error(
|
||||
"Default path is not set in config file.",
|
||||
));
|
||||
}
|
||||
Ok(OutputStream::empty())
|
||||
} else {
|
||||
let value = UntaggedValue::Error(crate::commands::config::err_no_global_cfg_present())
|
||||
.into_value(name);
|
||||
|
||||
Ok(OutputStream::one(value))
|
||||
}
|
||||
}
|
57
crates/nu-command/src/commands/pathvar/save.rs
Normal file
57
crates/nu-command/src/commands/pathvar/save.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, UntaggedValue, Value};
|
||||
use nu_test_support::{NATIVE_PATH_ENV_SEPARATOR, NATIVE_PATH_ENV_VAR};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"pathvar save"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("pathvar save")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Save the current pathvar to the config file"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
save(args)
|
||||
}
|
||||
}
|
||||
pub fn save(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let ctx = &args.context;
|
||||
|
||||
if let Some(global_cfg) = &mut ctx.configs().lock().global_config {
|
||||
if let Some(pathvar) = ctx.scope.get_env(NATIVE_PATH_ENV_VAR) {
|
||||
let paths: Vec<Value> = pathvar
|
||||
.split(NATIVE_PATH_ENV_SEPARATOR)
|
||||
.map(Value::from)
|
||||
.collect();
|
||||
|
||||
let span_range = 0..paths.len();
|
||||
let row = Value::new(
|
||||
UntaggedValue::Table(paths),
|
||||
Tag::from(Span::from(&span_range)),
|
||||
);
|
||||
|
||||
global_cfg.vars.insert("path".to_string(), row);
|
||||
global_cfg.write()?;
|
||||
ctx.reload_config(global_cfg)?;
|
||||
|
||||
Ok(OutputStream::empty())
|
||||
} else {
|
||||
Err(ShellError::unexpected("PATH not set"))
|
||||
}
|
||||
} else {
|
||||
let value = UntaggedValue::Error(crate::commands::config::err_no_global_cfg_present())
|
||||
.into_value(name);
|
||||
|
||||
Ok(OutputStream::one(value))
|
||||
}
|
||||
}
|
@ -27,6 +27,12 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
||||
whole_stream_command(Cd),
|
||||
whole_stream_command(Remove),
|
||||
whole_stream_command(Open),
|
||||
whole_stream_command(Pathvar),
|
||||
whole_stream_command(PathvarAdd),
|
||||
whole_stream_command(PathvarRemove),
|
||||
whole_stream_command(PathvarReset),
|
||||
whole_stream_command(PathvarAppend),
|
||||
whole_stream_command(PathvarSave),
|
||||
whole_stream_command(Config),
|
||||
whole_stream_command(ConfigGet),
|
||||
whole_stream_command(ConfigSet),
|
||||
|
@ -14,6 +14,11 @@ pub const NATIVE_PATH_ENV_VAR: &str = "Path";
|
||||
#[cfg(not(windows))]
|
||||
pub const NATIVE_PATH_ENV_VAR: &str = "PATH";
|
||||
|
||||
#[cfg(windows)]
|
||||
pub const NATIVE_PATH_ENV_SEPARATOR: char = ':';
|
||||
#[cfg(not(windows))]
|
||||
pub const NATIVE_PATH_ENV_SEPARATOR: char = ';';
|
||||
|
||||
impl Outcome {
|
||||
pub fn new(out: String, err: String) -> Outcome {
|
||||
Outcome { out, err }
|
||||
|
Loading…
Reference in New Issue
Block a user