Skip to content
Snippets Groups Projects
Commit 4d971dd4 authored by Michael Aaron Murphy's avatar Michael Aaron Murphy
Browse files

Implement !0, !^, and !*

parent 1147ac57
No related branches found
No related tags found
No related merge requests found
......@@ -4,6 +4,7 @@ use std::process::{Command, Stdio};
// use glob::glob;
use super::Shell;
use parser::ArgumentSplitter;
use parser::expand_string;
use parser::pipelines::RedirectFrom;
use smallstring::SmallString;
......@@ -41,41 +42,66 @@ impl Job {
pub(crate) fn expand(&mut self, shell: &Shell) {
let mut expanded = Array::new();
expanded.grow(self.args.len());
expanded.extend(self.args.drain().flat_map(|arg| if arg == "!!" {
expand_last_command(shell, false)
} else if arg == "!$" {
expand_last_command(shell, true)
} else {
expand_arg(&arg, shell)
expanded.extend(self.args.drain().flat_map(|arg| match arg.as_str() {
"!!" => expand_last_command(shell, Operation::All),
"!$" => expand_last_command(shell, Operation::LastArg),
"!0" => expand_last_command(shell, Operation::Command),
"!^" => expand_last_command(shell, Operation::FirstArg),
"!*" => expand_last_command(shell, Operation::NoCommand),
_ => expand_arg(&arg, shell),
}));
self.args = expanded;
}
}
pub(crate) enum Operation {
LastArg,
FirstArg,
Command,
NoCommand,
All,
}
/// Expands the last command that was provided to the shell.
///
/// If `args_only` is set to `true`, then only the arguments of
/// If `last_arg` is set to `true`, then only the last argument of
/// the last command will be expanded.
fn expand_last_command(shell: &Shell, args_only: bool) -> Array {
// Strips the command from the supplied buffer.
fn get_args(buffer: &[u8]) -> &[u8] {
if let Some(pos) = buffer.iter().position(|&x| x == b' ') {
let buffer = &buffer[pos + 1..];
pub(crate) fn expand_last_command(shell: &Shell, operation: Operation) -> Array {
fn get_last_arg(buffer: &str) -> &str { ArgumentSplitter::new(buffer).last().unwrap_or(buffer) }
fn get_first_arg(buffer: &str) -> &str {
ArgumentSplitter::new(buffer).skip(1).next().unwrap_or(buffer)
}
fn get_command(buffer: &str) -> &str { ArgumentSplitter::new(buffer).next().unwrap_or(buffer) }
fn get_args(buffer: &str) -> &str {
let bbuffer = buffer.as_bytes();
if let Some(pos) = bbuffer.iter().position(|&x| x == b' ') {
let buffer = &bbuffer[pos + 1..];
if let Some(pos) = buffer.iter().position(|&x| x != b' ') {
return &buffer[pos..];
return unsafe { str::from_utf8_unchecked(&buffer[pos..]) };
}
}
&buffer
buffer
}
fn expand_args(buffer: &str, shell: &Shell) -> Array {
ArgumentSplitter::new(buffer).flat_map(|b| expand_arg(b, shell)).collect::<Array>()
}
if let Some(ref context) = shell.context {
if let Some(buffer) = context.history.buffers.iter().last() {
let buffer = buffer.as_bytes();
let last_arg = unsafe {
str::from_utf8_unchecked(if args_only { get_args(&buffer) } else { &buffer })
let buffer = unsafe { str::from_utf8_unchecked(&buffer) };
return match operation {
Operation::LastArg => expand_arg(get_last_arg(buffer), shell),
Operation::FirstArg => expand_arg(get_first_arg(buffer), shell),
Operation::Command => expand_arg(get_command(buffer), shell),
Operation::NoCommand => expand_args(get_args(buffer), shell),
Operation::All => expand_args(buffer, shell),
};
return expand_arg(&last_arg, shell);
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment