mirror of
https://github.com/nushell/nushell
synced 2025-01-14 14:14:13 +00:00
Make g -
switch to the last used shell (#6249)
* Make `g -` switch to the last used shell Related #6223 Signed-off-by: nibon7 <nibon7@163.com> * simplify error handling Signed-off-by: nibon7 <nibon7@163.com> * update NUSHELL_LAST_SHELL environment Signed-off-by: nibon7 <nibon7@163.com> * add test Signed-off-by: nibon7 <nibon7@163.com> * fix description Signed-off-by: nibon7 <nibon7@163.com>
This commit is contained in:
parent
a871f2344a
commit
1ba5b25b29
8 changed files with 148 additions and 9 deletions
|
@ -395,9 +395,23 @@ pub fn evaluate_repl(
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let last_shell = stack.get_env_var(engine_state, "NUSHELL_LAST_SHELL");
|
||||||
|
let last_shell = if let Some(v) = last_shell {
|
||||||
|
v.as_integer().unwrap_or_default() as usize
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
shells[current_shell] = Value::String { val: path, span };
|
shells[current_shell] = Value::String { val: path, span };
|
||||||
|
|
||||||
stack.add_env_var("NUSHELL_SHELLS".into(), Value::List { vals: shells, span });
|
stack.add_env_var("NUSHELL_SHELLS".into(), Value::List { vals: shells, span });
|
||||||
|
stack.add_env_var(
|
||||||
|
"NUSHELL_LAST_SHELL".into(),
|
||||||
|
Value::Int {
|
||||||
|
val: last_shell as i64,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
trace!("eval source: {}", s);
|
trace!("eval source: {}", s);
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,14 @@ impl Command for Enter {
|
||||||
let mut shells = get_shells(engine_state, stack, cwd);
|
let mut shells = get_shells(engine_state, stack, cwd);
|
||||||
let mut current_shell = get_current_shell(engine_state, stack);
|
let mut current_shell = get_current_shell(engine_state, stack);
|
||||||
|
|
||||||
|
stack.add_env_var(
|
||||||
|
"NUSHELL_LAST_SHELL".into(),
|
||||||
|
Value::Int {
|
||||||
|
val: current_shell as i64,
|
||||||
|
span: call.head,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if current_shell + 1 > shells.len() {
|
if current_shell + 1 > shells.len() {
|
||||||
shells.push(new_path.clone());
|
shells.push(new_path.clone());
|
||||||
current_shell = shells.len();
|
current_shell = shells.len();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{get_current_shell, get_shells};
|
use super::{get_current_shell, get_last_shell, get_shells};
|
||||||
use nu_engine::{current_dir, 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};
|
||||||
|
@ -60,9 +60,14 @@ impl Command for Exit {
|
||||||
|
|
||||||
let mut shells = get_shells(engine_state, stack, cwd);
|
let mut shells = get_shells(engine_state, stack, cwd);
|
||||||
let mut current_shell = get_current_shell(engine_state, stack);
|
let mut current_shell = get_current_shell(engine_state, stack);
|
||||||
|
let mut last_shell = get_last_shell(engine_state, stack);
|
||||||
|
|
||||||
shells.remove(current_shell);
|
shells.remove(current_shell);
|
||||||
|
|
||||||
|
if current_shell <= last_shell {
|
||||||
|
last_shell = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if current_shell == shells.len() && !shells.is_empty() {
|
if current_shell == shells.len() && !shells.is_empty() {
|
||||||
current_shell -= 1;
|
current_shell -= 1;
|
||||||
}
|
}
|
||||||
|
@ -86,6 +91,13 @@ impl Command for Exit {
|
||||||
span: call.head,
|
span: call.head,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
stack.add_env_var(
|
||||||
|
"NUSHELL_LAST_SHELL".into(),
|
||||||
|
Value::Int {
|
||||||
|
val: last_shell as i64,
|
||||||
|
span: call.head,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
stack.add_env_var("PWD".into(), new_path);
|
stack.add_env_var("PWD".into(), new_path);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{get_current_shell, get_shells};
|
use super::{get_current_shell, get_last_shell, get_shells};
|
||||||
use nu_engine::{current_dir, 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};
|
||||||
|
@ -20,7 +20,7 @@ impl Command for GotoShell {
|
||||||
Signature::build("g")
|
Signature::build("g")
|
||||||
.optional(
|
.optional(
|
||||||
"shell_number",
|
"shell_number",
|
||||||
SyntaxShape::Int,
|
SyntaxShape::String,
|
||||||
"shell number to change to",
|
"shell number to change to",
|
||||||
)
|
)
|
||||||
.category(Category::Shells)
|
.category(Category::Shells)
|
||||||
|
@ -38,7 +38,7 @@ impl Command for GotoShell {
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let span = call.head;
|
let span = call.head;
|
||||||
let new_shell: Option<Spanned<i64>> = call.opt(engine_state, stack, 0)?;
|
let new_shell: Option<Spanned<String>> = call.opt(engine_state, stack, 0)?;
|
||||||
|
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
let cwd = current_dir(engine_state, stack)?;
|
||||||
let cwd = Value::String {
|
let cwd = Value::String {
|
||||||
|
@ -50,12 +50,22 @@ impl Command for GotoShell {
|
||||||
|
|
||||||
match new_shell {
|
match new_shell {
|
||||||
Some(shell_span) => {
|
Some(shell_span) => {
|
||||||
let new_path = if let Some(v) = shells.get(shell_span.item as usize) {
|
let index = if shell_span.item == "-" {
|
||||||
v.clone()
|
get_last_shell(engine_state, stack)
|
||||||
} else {
|
} else {
|
||||||
return Err(ShellError::NotFound(shell_span.span));
|
shell_span
|
||||||
|
.item
|
||||||
|
.parse::<usize>()
|
||||||
|
.map_err(|_| ShellError::NotFound(shell_span.span))?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let new_path = shells
|
||||||
|
.get(index)
|
||||||
|
.ok_or(ShellError::NotFound(shell_span.span))?
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
let current_shell = get_current_shell(engine_state, stack);
|
||||||
|
|
||||||
stack.add_env_var(
|
stack.add_env_var(
|
||||||
"NUSHELL_SHELLS".into(),
|
"NUSHELL_SHELLS".into(),
|
||||||
Value::List {
|
Value::List {
|
||||||
|
@ -66,7 +76,14 @@ impl Command for GotoShell {
|
||||||
stack.add_env_var(
|
stack.add_env_var(
|
||||||
"NUSHELL_CURRENT_SHELL".into(),
|
"NUSHELL_CURRENT_SHELL".into(),
|
||||||
Value::Int {
|
Value::Int {
|
||||||
val: shell_span.item,
|
val: index as i64,
|
||||||
|
span: call.head,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
stack.add_env_var(
|
||||||
|
"NUSHELL_LAST_SHELL".into(),
|
||||||
|
Value::Int {
|
||||||
|
val: current_shell as i64,
|
||||||
span: call.head,
|
span: call.head,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -114,6 +131,11 @@ impl Command for GotoShell {
|
||||||
example: r#"shells; g 2"#,
|
example: r#"shells; g 2"#,
|
||||||
result: None,
|
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,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,3 +34,12 @@ pub fn get_current_shell(engine_state: &EngineState, stack: &mut Stack) -> usize
|
||||||
0
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,13 @@ impl Command for NextShell {
|
||||||
|
|
||||||
let shells = get_shells(engine_state, stack, cwd);
|
let shells = get_shells(engine_state, stack, cwd);
|
||||||
let mut current_shell = get_current_shell(engine_state, stack);
|
let mut current_shell = get_current_shell(engine_state, stack);
|
||||||
|
stack.add_env_var(
|
||||||
|
"NUSHELL_LAST_SHELL".into(),
|
||||||
|
Value::Int {
|
||||||
|
val: current_shell as i64,
|
||||||
|
span: call.head,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
current_shell += 1;
|
current_shell += 1;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,13 @@ impl Command for PrevShell {
|
||||||
|
|
||||||
let shells = get_shells(engine_state, stack, cwd);
|
let shells = get_shells(engine_state, stack, cwd);
|
||||||
let mut current_shell = get_current_shell(engine_state, stack);
|
let mut current_shell = get_current_shell(engine_state, stack);
|
||||||
|
stack.add_env_var(
|
||||||
|
"NUSHELL_LAST_SHELL".into(),
|
||||||
|
Value::Int {
|
||||||
|
val: current_shell as i64,
|
||||||
|
span: call.head,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if current_shell == 0 {
|
if current_shell == 0 {
|
||||||
current_shell = shells.len() - 1;
|
current_shell = shells.len() - 1;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use nu_test_support::{nu, pipeline};
|
use nu_test_support::{nu, pipeline, playground::Playground};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_shells() {
|
fn list_shells() {
|
||||||
|
@ -29,3 +29,63 @@ fn enter_not_exist_shell() {
|
||||||
|
|
||||||
assert!(actual.err.contains("Not found"));
|
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");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue