fix: fix commandline when called with no arguments (#8207)

# Description

This fixes the `commandline` command when it's run with no arguments, so
it outputs the command being run. New line characters are included.

This allows for:

- [A way to get current command inside pre_execution hook · Issue #6264
· nushell/nushell](https://github.com/nushell/nushell/issues/6264)
- The possibility of *Atuin* to work work *Nushell*. *Atuin* hooks need
to know the current repl input before it is run.

# User-Facing Changes

# Tests + Formatting

Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# After Submitting

If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
This commit is contained in:
Steven Xu
2023-03-17 09:45:35 +11:00
committed by GitHub
parent 0903a891e4
commit b2a557d4ed
9 changed files with 244 additions and 57 deletions

View File

@ -24,6 +24,7 @@ fancy-regex = "0.11.0"
itertools = "0.10.0"
log = "0.4.14"
shadow-rs = { version = "0.21.0", default-features = false }
unicode-segmentation = "1.10.0"
[build-dependencies]
shadow-rs = { version = "0.21.0", default-features = false }

View File

@ -1,10 +1,10 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::ReplOperation;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category;
use nu_protocol::IntoPipelineData;
use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Type, Value};
use unicode_segmentation::UnicodeSegmentation;
#[derive(Clone)]
pub struct Commandline;
@ -17,6 +17,11 @@ impl Command for Commandline {
fn signature(&self) -> Signature {
Signature::build("commandline")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.switch(
"cursor",
"Set or get the current cursor position",
Some('c'),
)
.switch(
"append",
"appends the string to the end of the buffer",
@ -56,30 +61,77 @@ impl Command for Commandline {
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
if let Some(cmd) = call.opt::<Value>(engine_state, stack, 0)? {
let mut ops = engine_state
.repl_operation_queue
let mut buffer = engine_state
.repl_buffer_state
.lock()
.expect("repl op queue mutex");
ops.push_back(if call.has_flag("append") {
ReplOperation::Append(cmd.as_string()?)
.expect("repl buffer state mutex");
let mut cursor_pos = engine_state
.repl_cursor_pos
.lock()
.expect("repl cursor pos mutex");
if call.has_flag("cursor") {
let cmd_str = cmd.as_string()?;
match cmd_str.parse::<i64>() {
Ok(n) => {
*cursor_pos = if n <= 0 {
0usize
} else {
buffer
.grapheme_indices(true)
.map(|(i, _c)| i)
.nth(n as usize)
.unwrap_or(buffer.len())
}
}
Err(_) => {
return Err(ShellError::CantConvert {
to_type: "int".to_string(),
from_type: "string".to_string(),
span: cmd.span()?,
help: Some(format!(
r#"string "{cmd_str}" does not represent a valid integer"#
)),
})
}
}
} else if call.has_flag("append") {
buffer.push_str(&cmd.as_string()?);
} else if call.has_flag("insert") {
ReplOperation::Insert(cmd.as_string()?)
let cmd_str = cmd.as_string()?;
buffer.insert_str(*cursor_pos, &cmd_str);
*cursor_pos += cmd_str.len();
} else {
ReplOperation::Replace(cmd.as_string()?)
});
Ok(Value::Nothing { span: call.head }.into_pipeline_data())
} else if let Some(ref cmd) = *engine_state
.repl_buffer_state
.lock()
.expect("repl buffer state mutex")
{
Ok(Value::String {
val: cmd.clone(),
span: call.head,
*buffer = cmd.as_string()?;
*cursor_pos = buffer.len();
}
.into_pipeline_data())
} else {
Ok(Value::Nothing { span: call.head }.into_pipeline_data())
} else {
let buffer = engine_state
.repl_buffer_state
.lock()
.expect("repl buffer state mutex");
if call.has_flag("cursor") {
let cursor_pos = engine_state
.repl_cursor_pos
.lock()
.expect("repl cursor pos mutex");
let char_pos = buffer
.grapheme_indices(true)
.position(|(i, _c)| i == *cursor_pos)
.unwrap_or(buffer.len());
Ok(Value::String {
val: char_pos.to_string(),
span: call.head,
}
.into_pipeline_data())
} else {
Ok(Value::String {
val: buffer.to_string(),
span: call.head,
}
.into_pipeline_data())
}
}
}
}