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:
nibon7 2022-08-06 23:11:03 +08:00 committed by GitHub
parent a871f2344a
commit 1ba5b25b29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 148 additions and 9 deletions

View file

@ -395,9 +395,23 @@ pub fn evaluate_repl(
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 };
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 {
trace!("eval source: {}", s);

View file

@ -66,6 +66,14 @@ impl Command for Enter {
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 {
val: current_shell as i64,
span: call.head,
},
);
if current_shell + 1 > shells.len() {
shells.push(new_path.clone());
current_shell = shells.len();

View file

@ -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_protocol::ast::Call;
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 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;
}
@ -86,6 +91,13 @@ impl Command for Exit {
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);

View file

@ -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_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
@ -20,7 +20,7 @@ impl Command for GotoShell {
Signature::build("g")
.optional(
"shell_number",
SyntaxShape::Int,
SyntaxShape::String,
"shell number to change to",
)
.category(Category::Shells)
@ -38,7 +38,7 @@ impl Command for GotoShell {
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
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 = Value::String {
@ -50,12 +50,22 @@ impl Command for GotoShell {
match new_shell {
Some(shell_span) => {
let new_path = if let Some(v) = shells.get(shell_span.item as usize) {
v.clone()
let index = if shell_span.item == "-" {
get_last_shell(engine_state, stack)
} 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(
"NUSHELL_SHELLS".into(),
Value::List {
@ -66,7 +76,14 @@ impl Command for GotoShell {
stack.add_env_var(
"NUSHELL_CURRENT_SHELL".into(),
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,
},
);
@ -114,6 +131,11 @@ impl Command for GotoShell {
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,
},
]
}
}

View file

@ -34,3 +34,12 @@ pub fn get_current_shell(engine_state: &EngineState, stack: &mut Stack) -> usize
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
}
}

View file

@ -36,6 +36,13 @@ impl Command for NextShell {
let 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 {
val: current_shell as i64,
span: call.head,
},
);
current_shell += 1;

View file

@ -36,6 +36,13 @@ impl Command for PrevShell {
let 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 {
val: current_shell as i64,
span: call.head,
},
);
if current_shell == 0 {
current_shell = shells.len() - 1;

View file

@ -1,4 +1,4 @@
use nu_test_support::{nu, pipeline};
use nu_test_support::{nu, pipeline, playground::Playground};
#[test]
fn list_shells() {
@ -29,3 +29,63 @@ fn enter_not_exist_shell() {
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");
})
}