mirror of
https://github.com/nushell/nushell
synced 2025-01-12 21:29:07 +00:00
REFACTOR: remove the shell commands (#8415)
Related to #8368.
# Description
as planned in #8311, the `enter`, `shells`, `g`, `n` and `p` commands
have been re-implemented in pure-`nushell` in the standard library.
this PR removes the `rust` implementations of these commands.
- all the "shells" tests have been removed from
`crates/nu-commnand/tests/commands/` in
2cc6a82da6
, except for the `exit` command
- `cd` does not use the `shells` feature in its source code anymore =>
that does not change its single-shell behaviour
- all the command implementations have been removed from
`crates/nu-command/src/shells/`, except for `exit.rs` => `mod.rs` has
been modified accordingly
- the `exit` command now does not compute any "shell" related things
- the `--now` option has been removed from `exit`, as it does not serve
any purpose without sub-shells
# User-Facing Changes
users may now not use `enter`, `shells`, `g`, `n` and `p`
now they would have to use the standard library to have access to
equivalent features, thanks to the `dirs.nu` module introduced by @bobhy
in #8368
# Tests + Formatting
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- ⚫ `toolkit test`
- ⚫ `toolkit test stdlib`
# After Submitting
the website will have to be regenerated to reflect the removed commands
👍
This commit is contained in:
parent
b4a1f0f003
commit
bf86cd50a5
18 changed files with 49 additions and 853 deletions
|
@ -277,12 +277,7 @@ pub fn create_default_context() -> EngineState {
|
||||||
|
|
||||||
// Shells
|
// Shells
|
||||||
bind_command! {
|
bind_command! {
|
||||||
Enter,
|
|
||||||
Exit,
|
Exit,
|
||||||
GotoShell,
|
|
||||||
NextShell,
|
|
||||||
PrevShell,
|
|
||||||
Shells,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Formats
|
// Formats
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::filesystem::cd_query::query;
|
use crate::filesystem::cd_query::query;
|
||||||
use crate::{get_current_shell, get_shells};
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use libc::gid_t;
|
use libc::gid_t;
|
||||||
use nu_engine::{current_dir, CallExt};
|
use nu_engine::{current_dir, CallExt};
|
||||||
|
@ -164,23 +163,6 @@ impl Command for Cd {
|
||||||
val: path.clone(),
|
val: path.clone(),
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
let cwd = Value::string(cwd.to_string_lossy(), call.head);
|
|
||||||
|
|
||||||
let mut shells = get_shells(engine_state, stack, cwd);
|
|
||||||
let current_shell = get_current_shell(engine_state, stack);
|
|
||||||
shells[current_shell] = path_value.clone();
|
|
||||||
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_SHELLS".into(),
|
|
||||||
Value::List {
|
|
||||||
vals: shells,
|
|
||||||
span: call.head,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_CURRENT_SHELL".into(),
|
|
||||||
Value::int(current_shell as i64, call.head),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(oldpwd) = stack.get_env_var(engine_state, "PWD") {
|
if let Some(oldpwd) = stack.get_env_var(engine_state, "PWD") {
|
||||||
stack.add_env_var("OLDPWD".into(), oldpwd)
|
stack.add_env_var("OLDPWD".into(), oldpwd)
|
||||||
|
|
|
@ -1,103 +0,0 @@
|
||||||
use super::{get_current_shell, get_shells};
|
|
||||||
use nu_engine::{current_dir, CallExt};
|
|
||||||
use nu_protocol::ast::Call;
|
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
|
||||||
use nu_protocol::{
|
|
||||||
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Source a file for environment variables.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Enter;
|
|
||||||
|
|
||||||
impl Command for Enter {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"enter"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("enter")
|
|
||||||
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
|
||||||
.required(
|
|
||||||
"path",
|
|
||||||
SyntaxShape::Filepath,
|
|
||||||
"the path to enter as a new shell",
|
|
||||||
)
|
|
||||||
.category(Category::Shells)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Enters a new shell at the given path."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let new_path: Value = call.req(engine_state, stack, 0)?;
|
|
||||||
let path_span = new_path.span()?;
|
|
||||||
|
|
||||||
let new_path = new_path.as_path()?;
|
|
||||||
|
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
|
||||||
let new_path = nu_path::canonicalize_with(new_path, &cwd)?;
|
|
||||||
|
|
||||||
if !new_path.exists() {
|
|
||||||
return Err(ShellError::DirectoryNotFound(path_span, None));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !new_path.is_dir() {
|
|
||||||
return Err(ShellError::DirectoryNotFoundCustom(
|
|
||||||
"not a directory".to_string(),
|
|
||||||
path_span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_path = Value::string(new_path.to_string_lossy(), call.head);
|
|
||||||
|
|
||||||
let cwd = Value::string(cwd.to_string_lossy(), call.head);
|
|
||||||
|
|
||||||
let mut shells = get_shells(engine_state, stack, cwd);
|
|
||||||
let mut current_shell = get_current_shell(engine_state, stack);
|
|
||||||
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_LAST_SHELL".into(),
|
|
||||||
Value::int(current_shell as i64, call.head),
|
|
||||||
);
|
|
||||||
|
|
||||||
if current_shell + 1 > shells.len() {
|
|
||||||
shells.push(new_path.clone());
|
|
||||||
current_shell = shells.len();
|
|
||||||
} else {
|
|
||||||
shells.insert(current_shell + 1, new_path.clone());
|
|
||||||
current_shell += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_SHELLS".into(),
|
|
||||||
Value::List {
|
|
||||||
vals: shells,
|
|
||||||
span: call.head,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_CURRENT_SHELL".into(),
|
|
||||||
Value::int(current_shell as i64, call.head),
|
|
||||||
);
|
|
||||||
|
|
||||||
stack.add_env_var("PWD".into(), new_path);
|
|
||||||
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![Example {
|
|
||||||
description: "Enter a new shell at path '../dir-foo'",
|
|
||||||
example: r#"enter ../dir-foo"#,
|
|
||||||
result: None,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,7 @@
|
||||||
use super::{get_current_shell, get_last_shell, get_shells};
|
use nu_engine::CallExt;
|
||||||
use nu_engine::{current_dir, CallExt};
|
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
|
||||||
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Exit;
|
pub struct Exit;
|
||||||
|
@ -22,11 +19,6 @@ impl Command for Exit {
|
||||||
SyntaxShape::Int,
|
SyntaxShape::Int,
|
||||||
"Exit code to return immediately with",
|
"Exit code to return immediately with",
|
||||||
)
|
)
|
||||||
.switch(
|
|
||||||
"now",
|
|
||||||
"Exit out of all shells immediately (exiting Nu)",
|
|
||||||
Some('n'),
|
|
||||||
)
|
|
||||||
.category(Category::Shells)
|
.category(Category::Shells)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,66 +43,14 @@ impl Command for Exit {
|
||||||
std::process::exit(exit_code as i32);
|
std::process::exit(exit_code as i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
if call.has_flag("now") {
|
std::process::exit(0);
|
||||||
std::process::exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
|
||||||
let cwd = Value::string(cwd.to_string_lossy(), call.head);
|
|
||||||
|
|
||||||
let mut shells = get_shells(engine_state, stack, cwd);
|
|
||||||
let mut current_shell = get_current_shell(engine_state, stack);
|
|
||||||
let mut last_shell = get_last_shell(engine_state, stack);
|
|
||||||
|
|
||||||
shells.remove(current_shell);
|
|
||||||
|
|
||||||
if current_shell <= last_shell {
|
|
||||||
last_shell = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_shell == shells.len() && !shells.is_empty() {
|
|
||||||
current_shell -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if shells.is_empty() {
|
|
||||||
std::process::exit(0);
|
|
||||||
} else {
|
|
||||||
let new_path = shells[current_shell].clone();
|
|
||||||
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_SHELLS".into(),
|
|
||||||
Value::List {
|
|
||||||
vals: shells,
|
|
||||||
span: call.head,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_CURRENT_SHELL".into(),
|
|
||||||
Value::int(current_shell as i64, call.head),
|
|
||||||
);
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_LAST_SHELL".into(),
|
|
||||||
Value::int(last_shell as i64, call.head),
|
|
||||||
);
|
|
||||||
|
|
||||||
stack.add_env_var("PWD".into(), new_path);
|
|
||||||
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![Example {
|
||||||
Example {
|
description: "Exit the current shell",
|
||||||
description: "Exit the current shell",
|
example: "exit",
|
||||||
example: "exit",
|
result: None,
|
||||||
result: None,
|
}]
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Exit all shells (exiting Nu)",
|
|
||||||
example: "exit --now",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
use super::{list_shells, switch_shell, SwitchTo};
|
|
||||||
use nu_engine::CallExt;
|
|
||||||
use nu_protocol::ast::Call;
|
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
|
||||||
use nu_protocol::{
|
|
||||||
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Source a file for environment variables.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct GotoShell;
|
|
||||||
|
|
||||||
impl Command for GotoShell {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"g"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("g")
|
|
||||||
.input_output_types(vec![
|
|
||||||
(Type::Nothing, Type::Nothing),
|
|
||||||
(Type::Nothing, Type::Table(vec![])),
|
|
||||||
])
|
|
||||||
.optional(
|
|
||||||
"shell_number",
|
|
||||||
SyntaxShape::OneOf(vec![SyntaxShape::Int, SyntaxShape::String]),
|
|
||||||
"shell number to change to",
|
|
||||||
)
|
|
||||||
.category(Category::Shells)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Switch to a given shell, or list all shells if no given shell number."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let new_shell: Option<Value> = call.opt(engine_state, stack, 0)?;
|
|
||||||
|
|
||||||
match new_shell {
|
|
||||||
Some(shell_span) => match &shell_span {
|
|
||||||
Value::String { val, span } => {
|
|
||||||
if val == "-" {
|
|
||||||
switch_shell(engine_state, stack, call, *span, SwitchTo::Last)
|
|
||||||
} else {
|
|
||||||
Err(ShellError::TypeMismatch {
|
|
||||||
err_message: "int or '-'".into(),
|
|
||||||
span: *span,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value::Int { val, span } => switch_shell(
|
|
||||||
engine_state,
|
|
||||||
stack,
|
|
||||||
call,
|
|
||||||
*span,
|
|
||||||
SwitchTo::Nth(*val as usize),
|
|
||||||
),
|
|
||||||
_ => Err(ShellError::TypeMismatch {
|
|
||||||
err_message: "int or '-'".into(),
|
|
||||||
span: call.head,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
None => list_shells(engine_state, stack, call.head),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Lists all open shells",
|
|
||||||
example: r#"g"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Make two directories and enter new shells for them, use `g` to jump to the specific shell",
|
|
||||||
example: r#"mkdir foo bar; enter foo; enter ../bar; g 1"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Use `shells` to show all the opened shells and run `g 2` to jump to the third one",
|
|
||||||
example: r#"shells; g 2"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Make two directories and enter new shells for them, use `g -` to jump to the last used shell",
|
|
||||||
example: r#"mkdir foo bar; enter foo; enter ../bar; g -"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,147 +1,3 @@
|
||||||
mod enter;
|
|
||||||
mod exit;
|
mod exit;
|
||||||
mod g;
|
|
||||||
mod n;
|
|
||||||
mod p;
|
|
||||||
mod shells_;
|
|
||||||
|
|
||||||
pub use enter::Enter;
|
|
||||||
pub use exit::Exit;
|
pub use exit::Exit;
|
||||||
pub use g::GotoShell;
|
|
||||||
pub use n::NextShell;
|
|
||||||
use nu_engine::current_dir;
|
|
||||||
use nu_protocol::ast::Call;
|
|
||||||
use nu_protocol::engine::{EngineState, Stack};
|
|
||||||
use nu_protocol::{IntoInterruptiblePipelineData, PipelineData, ShellError, Span, Value};
|
|
||||||
pub use p::PrevShell;
|
|
||||||
pub use shells_::Shells;
|
|
||||||
|
|
||||||
enum SwitchTo {
|
|
||||||
Next,
|
|
||||||
Prev,
|
|
||||||
Last,
|
|
||||||
Nth(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_shells(engine_state: &EngineState, stack: &mut Stack, cwd: Value) -> Vec<Value> {
|
|
||||||
let shells = stack.get_env_var(engine_state, "NUSHELL_SHELLS");
|
|
||||||
let shells = if let Some(v) = shells {
|
|
||||||
v.as_list()
|
|
||||||
.map(|x| x.to_vec())
|
|
||||||
.unwrap_or_else(|_| vec![cwd])
|
|
||||||
} else {
|
|
||||||
vec![cwd]
|
|
||||||
};
|
|
||||||
shells
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_current_shell(engine_state: &EngineState, stack: &mut Stack) -> usize {
|
|
||||||
let current_shell = stack.get_env_var(engine_state, "NUSHELL_CURRENT_SHELL");
|
|
||||||
if let Some(v) = current_shell {
|
|
||||||
v.as_integer().unwrap_or_default() as usize
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_last_shell(engine_state: &EngineState, stack: &mut Stack) -> usize {
|
|
||||||
let last_shell = stack.get_env_var(engine_state, "NUSHELL_LAST_SHELL");
|
|
||||||
if let Some(v) = last_shell {
|
|
||||||
v.as_integer().unwrap_or_default() as usize
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn switch_shell(
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
span: Span,
|
|
||||||
switch_to: SwitchTo,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
|
||||||
let cwd = Value::string(cwd.to_string_lossy(), call.head);
|
|
||||||
|
|
||||||
let shells = get_shells(engine_state, stack, cwd);
|
|
||||||
let current_shell = get_current_shell(engine_state, stack);
|
|
||||||
|
|
||||||
let new_shell = match switch_to {
|
|
||||||
SwitchTo::Next => {
|
|
||||||
let mut new_shell = current_shell + 1;
|
|
||||||
|
|
||||||
if new_shell == shells.len() {
|
|
||||||
new_shell = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_shell
|
|
||||||
}
|
|
||||||
SwitchTo::Prev => {
|
|
||||||
if current_shell == 0 {
|
|
||||||
shells.len() - 1
|
|
||||||
} else {
|
|
||||||
current_shell - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SwitchTo::Last => get_last_shell(engine_state, stack),
|
|
||||||
SwitchTo::Nth(n) => n,
|
|
||||||
};
|
|
||||||
|
|
||||||
let new_path = shells
|
|
||||||
.get(new_shell)
|
|
||||||
.ok_or(ShellError::NotFound { span })?
|
|
||||||
.to_owned();
|
|
||||||
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_SHELLS".into(),
|
|
||||||
Value::List {
|
|
||||||
vals: shells,
|
|
||||||
span: call.head,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_CURRENT_SHELL".into(),
|
|
||||||
Value::int(new_shell as i64, call.head),
|
|
||||||
);
|
|
||||||
|
|
||||||
stack.add_env_var(
|
|
||||||
"NUSHELL_LAST_SHELL".into(),
|
|
||||||
Value::int(current_shell as i64, call.head),
|
|
||||||
);
|
|
||||||
|
|
||||||
stack.add_env_var("PWD".into(), new_path);
|
|
||||||
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list_shells(
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
span: Span,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
|
||||||
let cwd = Value::String {
|
|
||||||
val: cwd.to_string_lossy().to_string(),
|
|
||||||
span,
|
|
||||||
};
|
|
||||||
|
|
||||||
let shells = get_shells(engine_state, stack, cwd);
|
|
||||||
let current_shell = get_current_shell(engine_state, stack);
|
|
||||||
|
|
||||||
Ok(shells
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(move |(idx, val)| Value::Record {
|
|
||||||
cols: vec!["active".to_string(), "path".to_string()],
|
|
||||||
vals: vec![
|
|
||||||
Value::Bool {
|
|
||||||
val: idx == current_shell,
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
val,
|
|
||||||
],
|
|
||||||
span,
|
|
||||||
})
|
|
||||||
.into_pipeline_data(None))
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
use super::{switch_shell, SwitchTo};
|
|
||||||
use nu_protocol::ast::Call;
|
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
|
||||||
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Type};
|
|
||||||
|
|
||||||
/// Source a file for environment variables.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct NextShell;
|
|
||||||
|
|
||||||
impl Command for NextShell {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"n"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("n")
|
|
||||||
.category(Category::Shells)
|
|
||||||
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Switch to the next shell."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
switch_shell(engine_state, stack, call, call.head, SwitchTo::Next)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Make two directories and enter new shells for them, use `n` to jump to the next shell",
|
|
||||||
example: r#"mkdir foo bar; enter foo; enter ../bar; n"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Run `n` several times and note the changes of current directory",
|
|
||||||
example: r#"n"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
use super::{switch_shell, SwitchTo};
|
|
||||||
use nu_protocol::ast::Call;
|
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
|
||||||
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Type};
|
|
||||||
|
|
||||||
/// Source a file for environment variables.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PrevShell;
|
|
||||||
|
|
||||||
impl Command for PrevShell {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"p"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("p")
|
|
||||||
.category(Category::Shells)
|
|
||||||
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Switch to the previous shell."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
switch_shell(engine_state, stack, call, call.head, SwitchTo::Prev)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Make two directories and enter new shells for them, use `p` to jump to the previous shell",
|
|
||||||
example: r#"mkdir foo bar; enter foo; enter ../bar; p"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Run `p` several times and note the changes of current directory",
|
|
||||||
example: r#"p"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
use super::list_shells;
|
|
||||||
use nu_protocol::ast::Call;
|
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
|
||||||
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Type};
|
|
||||||
|
|
||||||
/// Source a file for environment variables.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Shells;
|
|
||||||
|
|
||||||
impl Command for Shells {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"shells"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("shells")
|
|
||||||
.category(Category::Shells)
|
|
||||||
.input_output_types(vec![(Type::Nothing, Type::Table(vec![]))])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Lists all open shells."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
list_shells(engine_state, stack, call.head)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Enter a new shell at parent path '..' and show all opened shells",
|
|
||||||
example: r#"enter ..; shells"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Show currently active shell",
|
|
||||||
example: r#"shells | where active == true"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
use nu_test_support::fs::{files_exist_at, Stub::EmptyFile};
|
|
||||||
use nu_test_support::nu;
|
|
||||||
use nu_test_support::playground::Playground;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn knows_the_filesystems_entered() {
|
|
||||||
Playground::setup("enter_test_1", |dirs, sandbox| {
|
|
||||||
sandbox
|
|
||||||
.within("red_pill")
|
|
||||||
.with_files(vec![
|
|
||||||
EmptyFile("andres.nu"),
|
|
||||||
EmptyFile("jtnu"),
|
|
||||||
EmptyFile("yehuda.nu"),
|
|
||||||
])
|
|
||||||
.within("blue_pill")
|
|
||||||
.with_files(vec![
|
|
||||||
EmptyFile("bash.nxt"),
|
|
||||||
EmptyFile("korn.nxt"),
|
|
||||||
EmptyFile("powedsh.nxt"),
|
|
||||||
])
|
|
||||||
.mkdir("expected");
|
|
||||||
|
|
||||||
let red_pill_dir = dirs.test().join("red_pill");
|
|
||||||
let blue_pill_dir = dirs.test().join("blue_pill");
|
|
||||||
let expected = dirs.test().join("expected");
|
|
||||||
let expected_recycled = expected.join("recycled");
|
|
||||||
|
|
||||||
nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
"
|
|
||||||
enter expected
|
|
||||||
mkdir recycled
|
|
||||||
enter ../red_pill
|
|
||||||
mv jtnu ../expected
|
|
||||||
enter ../blue_pill
|
|
||||||
cp *.nxt ../expected/recycled
|
|
||||||
p
|
|
||||||
p
|
|
||||||
mv ../red_pill/yehuda.nu .
|
|
||||||
n
|
|
||||||
mv andres.nu ../expected/andres.nu
|
|
||||||
exit
|
|
||||||
cd ..
|
|
||||||
rm red_pill --recursive
|
|
||||||
exit
|
|
||||||
n
|
|
||||||
rm blue_pill --recursive
|
|
||||||
exit
|
|
||||||
"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(!red_pill_dir.exists());
|
|
||||||
assert!(files_exist_at(
|
|
||||||
vec![
|
|
||||||
Path::new("andres.nu"),
|
|
||||||
Path::new("jtnu"),
|
|
||||||
Path::new("yehuda.nu"),
|
|
||||||
],
|
|
||||||
expected
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(!blue_pill_dir.exists());
|
|
||||||
assert!(files_exist_at(
|
|
||||||
vec![
|
|
||||||
Path::new("bash.nxt"),
|
|
||||||
Path::new("korn.nxt"),
|
|
||||||
Path::new("powedsh.nxt"),
|
|
||||||
],
|
|
||||||
expected_recycled
|
|
||||||
));
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
use nu_test_support::{nu, pipeline, playground::Playground};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn list_shells() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".", pipeline(
|
|
||||||
r#"g | get path | length "#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn enter_shell() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".", pipeline(
|
|
||||||
r#"g 0"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.err.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn enter_not_exist_shell() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".", pipeline(
|
|
||||||
r#"g 1"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.err.contains("Not found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn switch_to_last_used_shell_1() {
|
|
||||||
Playground::setup("switch_last_used_shell_1", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("foo").mkdir("bar");
|
|
||||||
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
pipeline(
|
|
||||||
r#"enter foo; enter ../bar; g 0; g -;g | get active.2"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn switch_to_last_used_shell_2() {
|
|
||||||
Playground::setup("switch_last_used_shell_2", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("foo").mkdir("bar");
|
|
||||||
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
pipeline(
|
|
||||||
r#"enter foo; enter ../bar; n; g -;g | get active.2"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn switch_to_last_used_shell_3() {
|
|
||||||
Playground::setup("switch_last_used_shell_3", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("foo").mkdir("bar");
|
|
||||||
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
pipeline(
|
|
||||||
r#"enter foo; enter ../bar; p; g -;g | get active.2"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn switch_to_last_used_shell_4() {
|
|
||||||
Playground::setup("switch_last_used_shell_4", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("foo").mkdir("bar");
|
|
||||||
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
pipeline(
|
|
||||||
r#"enter foo; enter ../bar; g 2; exit; g -;g | get active.0"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -18,7 +18,6 @@ mod drop;
|
||||||
mod each;
|
mod each;
|
||||||
mod echo;
|
mod echo;
|
||||||
mod empty;
|
mod empty;
|
||||||
mod enter;
|
|
||||||
mod error_make;
|
mod error_make;
|
||||||
mod every;
|
mod every;
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
|
@ -30,7 +29,6 @@ mod first;
|
||||||
mod flatten;
|
mod flatten;
|
||||||
mod for_;
|
mod for_;
|
||||||
mod format;
|
mod format;
|
||||||
mod g;
|
|
||||||
mod get;
|
mod get;
|
||||||
mod glob;
|
mod glob;
|
||||||
mod group_by;
|
mod group_by;
|
||||||
|
@ -54,11 +52,9 @@ mod merge;
|
||||||
mod mkdir;
|
mod mkdir;
|
||||||
mod move_;
|
mod move_;
|
||||||
mod mut_;
|
mod mut_;
|
||||||
mod n;
|
|
||||||
mod network;
|
mod network;
|
||||||
mod nu_check;
|
mod nu_check;
|
||||||
mod open;
|
mod open;
|
||||||
mod p;
|
|
||||||
mod par_each;
|
mod par_each;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod path;
|
mod path;
|
||||||
|
@ -84,7 +80,6 @@ mod select;
|
||||||
mod semicolon;
|
mod semicolon;
|
||||||
mod seq;
|
mod seq;
|
||||||
mod seq_char;
|
mod seq_char;
|
||||||
mod shells;
|
|
||||||
mod skip;
|
mod skip;
|
||||||
mod sort;
|
mod sort;
|
||||||
mod sort_by;
|
mod sort_by;
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
use nu_test_support::{nu, pipeline, playground::Playground};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn switch_to_next_shell_1() {
|
|
||||||
Playground::setup("switch_to_next_shell_1", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("foo").mkdir("bar");
|
|
||||||
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
pipeline(
|
|
||||||
r#"enter foo; enter ../bar; n; g | get active.0"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn switch_to_next_shell_2() {
|
|
||||||
Playground::setup("switch_to_next_shell_2", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("foo").mkdir("bar");
|
|
||||||
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
pipeline(
|
|
||||||
r#"enter foo; enter ../bar; n; n; g | get active.1"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
use nu_test_support::{nu, pipeline, playground::Playground};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn switch_to_prev_shell_1() {
|
|
||||||
Playground::setup("switch_to_next_shell_1", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("foo").mkdir("bar");
|
|
||||||
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
pipeline(
|
|
||||||
r#"enter foo; enter ../bar; p; g | get active.1"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn switch_to_prev_shell_2() {
|
|
||||||
Playground::setup("switch_to_next_shell_2", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("foo").mkdir("bar");
|
|
||||||
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
pipeline(
|
|
||||||
r#"enter foo; enter ../bar; p; p; p; g | get active.2"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
use nu_test_support::{nu, pipeline, playground::Playground};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn list_shells_1() {
|
|
||||||
Playground::setup("list_shells_1", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("foo").mkdir("bar");
|
|
||||||
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
pipeline(
|
|
||||||
r#"enter foo; enter ../bar; g| get active.2"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn list_shells_2() {
|
|
||||||
Playground::setup("list_shells_2", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("foo").mkdir("bar");
|
|
||||||
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
pipeline(
|
|
||||||
r#"enter foo; enter ../bar; shells| get active.2"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -27,6 +27,8 @@ export def-env "dirs add" [
|
||||||
_fetch 0
|
_fetch 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export alias enter = dirs add
|
||||||
|
|
||||||
# Advance to the next directory in the list or wrap to beginning.
|
# Advance to the next directory in the list or wrap to beginning.
|
||||||
export def-env "dirs next" [
|
export def-env "dirs next" [
|
||||||
N:int = 1 # number of positions to move.
|
N:int = 1 # number of positions to move.
|
||||||
|
@ -34,6 +36,8 @@ export def-env "dirs next" [
|
||||||
_fetch $N
|
_fetch $N
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export alias n = dirs next
|
||||||
|
|
||||||
# Back up to the previous directory or wrap to the end.
|
# Back up to the previous directory or wrap to the end.
|
||||||
export def-env "dirs prev" [
|
export def-env "dirs prev" [
|
||||||
N:int = 1 # number of positions to move.
|
N:int = 1 # number of positions to move.
|
||||||
|
@ -41,6 +45,8 @@ export def-env "dirs prev" [
|
||||||
_fetch (-1 * $N)
|
_fetch (-1 * $N)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export alias p = dirs prev
|
||||||
|
|
||||||
# Drop the current directory from the list, if it's not the only one.
|
# Drop the current directory from the list, if it's not the only one.
|
||||||
# PWD becomes the next working directory
|
# PWD becomes the next working directory
|
||||||
export def-env "dirs drop" [] {
|
export def-env "dirs drop" [] {
|
||||||
|
@ -54,6 +60,8 @@ export def-env "dirs drop" [] {
|
||||||
_fetch 0
|
_fetch 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export alias dexit = dirs drop
|
||||||
|
|
||||||
# Display current working directories.
|
# Display current working directories.
|
||||||
export def-env "dirs show" [] {
|
export def-env "dirs show" [] {
|
||||||
mut out = []
|
mut out = []
|
||||||
|
@ -67,6 +75,31 @@ export def-env "dirs show" [] {
|
||||||
$out
|
$out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export alias shells = dirs show
|
||||||
|
|
||||||
|
export def-env "dirs goto" [shell?: int] {
|
||||||
|
if $shell == null {
|
||||||
|
return (dirs show)
|
||||||
|
}
|
||||||
|
|
||||||
|
if $shell < 0 or $shell >= ($env.DIRS_LIST | length) {
|
||||||
|
let span = (metadata $shell | get span)
|
||||||
|
error make {
|
||||||
|
msg: $"(ansi red_bold)invalid_shell_index(ansi reset)"
|
||||||
|
label: {
|
||||||
|
text: $"`shell` should be between 0 and (($env.DIRS_LIST | length) - 1)"
|
||||||
|
start: $span.start
|
||||||
|
end: $span.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let-env DIRS_POSITION = $shell
|
||||||
|
|
||||||
|
cd ($env.DIRS_LIST | get $env.DIRS_POSITION)
|
||||||
|
}
|
||||||
|
|
||||||
|
export alias g = dirs goto
|
||||||
|
|
||||||
# fetch item helper
|
# fetch item helper
|
||||||
def-env _fetch [
|
def-env _fetch [
|
||||||
offset: int, # signed change to position
|
offset: int, # signed change to position
|
||||||
|
|
|
@ -88,6 +88,7 @@ pub fn load_standard_library(
|
||||||
// Conventionally, for a command implemented as `std foo`, the name added
|
// Conventionally, for a command implemented as `std foo`, the name added
|
||||||
// is either `std foo` or bare `foo`, not some arbitrary rename.
|
// is either `std foo` or bare `foo`, not some arbitrary rename.
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
let prelude = vec![
|
let prelude = vec![
|
||||||
("std help", "help"),
|
("std help", "help"),
|
||||||
("std help commands", "help commands"),
|
("std help commands", "help commands"),
|
||||||
|
@ -95,6 +96,13 @@ pub fn load_standard_library(
|
||||||
("std help modules", "help modules"),
|
("std help modules", "help modules"),
|
||||||
("std help externs", "help externs"),
|
("std help externs", "help externs"),
|
||||||
("std help operators", "help operators"),
|
("std help operators", "help operators"),
|
||||||
|
|
||||||
|
("enter", "enter"),
|
||||||
|
("shells", "shells"),
|
||||||
|
("g", "g"),
|
||||||
|
("n", "n"),
|
||||||
|
("p", "p"),
|
||||||
|
("dexit", "dexit"),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut working_set = StateWorkingSet::new(engine_state);
|
let mut working_set = StateWorkingSet::new(engine_state);
|
||||||
|
|
|
@ -179,15 +179,6 @@ fn bad_short_flag() -> TestResult {
|
||||||
fail_test(r#"def foo3 [-l?:int] { $l }"#, "short flag")
|
fail_test(r#"def foo3 [-l?:int] { $l }"#, "short flag")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_with_error_doesnt_panic() -> TestResult {
|
|
||||||
fail_test(
|
|
||||||
r#"alias s = shells
|
|
||||||
s ."#,
|
|
||||||
"extra positional",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn quotes_with_equals() -> TestResult {
|
fn quotes_with_equals() -> TestResult {
|
||||||
run_test(
|
run_test(
|
||||||
|
|
Loading…
Reference in a new issue