From 648cbd46aa39cef7db3a86a18ad847f5fb1df075 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Tue, 10 Sep 2024 23:09:40 +0200 Subject: [PATCH] feat: implement alias (#101) --- crates/deno_task_shell/src/shell/execute.rs | 11 ++++++ crates/deno_task_shell/src/shell/types.rs | 31 +++++++++++++--- crates/shell/src/commands.rs | 39 ++++++++++++++++++++- crates/shell/src/main.rs | 20 ++++++++--- 4 files changed, 91 insertions(+), 10 deletions(-) diff --git a/crates/deno_task_shell/src/shell/execute.rs b/crates/deno_task_shell/src/shell/execute.rs index debbfcf..df4327f 100644 --- a/crates/deno_task_shell/src/shell/execute.rs +++ b/crates/deno_task_shell/src/shell/execute.rs @@ -643,8 +643,19 @@ fn execute_command_args( let command_name = if args.is_empty() { String::new() } else { + // check if the command name is in the alias hashmap + if let Some(value) = state.alias_map().get(&args[0]) { + args.remove(0); + args = value + .iter() + .chain(args.iter()) + .cloned() + .collect::>(); + } + args.remove(0) }; + if state.token().is_cancelled() { Box::pin(future::ready(ExecuteResult::for_cancellation())) } else if let Some(stripped_name) = command_name.strip_prefix('!') { diff --git a/crates/deno_task_shell/src/shell/types.rs b/crates/deno_task_shell/src/shell/types.rs index f69b977..5189e15 100644 --- a/crates/deno_task_shell/src/shell/types.rs +++ b/crates/deno_task_shell/src/shell/types.rs @@ -27,8 +27,12 @@ pub struct ShellState { /// Variables that should be evaluated within the shell and /// not passed down to any sub commands. shell_vars: HashMap, + /// The current working directory of the shell cwd: PathBuf, + /// The commands that are available in the shell commands: Rc>>, + /// A map of aliases for commands (e.g. `ll=ls -al`) + alias: HashMap>, /// Token to cancel execution. token: CancellationToken, /// Git repository handling. @@ -51,6 +55,7 @@ impl ShellState { let mut result = Self { env_vars: Default::default(), shell_vars: Default::default(), + alias: Default::default(), cwd: PathBuf::new(), commands: Rc::new(commands), token: CancellationToken::default(), @@ -72,6 +77,10 @@ impl ShellState { &self.cwd } + pub fn alias_map(&self) -> &HashMap> { + &self.alias + } + pub fn git_repository(&self) -> bool { self.git_repository } @@ -131,7 +140,7 @@ impl ShellState { } } - // TODO: set_cwd() is being called twice + /// Set the current working directory of this shell pub fn set_cwd(&mut self, cwd: &Path) { self.cwd = cwd.to_path_buf(); // $PWD holds the current working directory, so we keep cwd and $PWD in sync @@ -204,6 +213,15 @@ impl ShellState { self.set_cwd(new_dir); self.last_command_cd = true; } + EnvChange::AliasCommand(alias, cmd) => { + self.alias.insert( + alias.clone(), + cmd.split_whitespace().map(ToString::to_string).collect(), + ); + } + EnvChange::UnAliasCommand(alias) => { + self.alias.remove(alias); + } } } @@ -264,12 +282,17 @@ impl ShellState { #[derive(Debug, PartialEq, Eq)] pub enum EnvChange { - // `export ENV_VAR=VALUE` + /// `export ENV_VAR=VALUE` SetEnvVar(String, String), - // `ENV_VAR=VALUE` + /// `ENV_VAR=VALUE` SetShellVar(String, String), - // `unset ENV_VAR` + /// Create an alias for a command (e.g. ll=ls -al) + AliasCommand(String, String), + /// Remove an alias + UnAliasCommand(String), + /// `unset ENV_VAR` UnsetVar(String), + /// Set the current working directory to the new Path Cd(PathBuf), } diff --git a/crates/shell/src/commands.rs b/crates/shell/src/commands.rs index 1467dda..66c8f24 100644 --- a/crates/shell/src/commands.rs +++ b/crates/shell/src/commands.rs @@ -1,11 +1,48 @@ use std::ffi::OsString; -use deno_task_shell::{ExecuteResult, ShellCommand, ShellCommandContext}; +use deno_task_shell::{EnvChange, ExecuteResult, ShellCommand, ShellCommandContext}; use futures::future::LocalBoxFuture; use uu_ls::uumain as uu_ls; pub struct LsCommand; +pub struct AliasCommand; + +pub struct UnAliasCommand; + +impl ShellCommand for AliasCommand { + fn execute(&self, context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> { + if context.args.len() != 1 { + return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(1))); + } + + // parse the args + let env_change = if let Some((alias, cmd)) = context.args[0].split_once('=') { + vec![EnvChange::AliasCommand(alias.into(), cmd.into())] + } else { + return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(1))); + }; + + let result = ExecuteResult::Continue(0, env_change, Vec::default()); + Box::pin(futures::future::ready(result)) + } +} + +impl ShellCommand for UnAliasCommand { + fn execute(&self, context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> { + if context.args.len() != 1 { + return Box::pin(futures::future::ready(ExecuteResult::from_exit_code(1))); + } + + let result = ExecuteResult::Continue( + 0, + vec![EnvChange::UnAliasCommand(context.args[0].clone())], + Vec::default(), + ); + Box::pin(futures::future::ready(result)) + } +} + impl ShellCommand for LsCommand { fn execute(&self, context: ShellCommandContext) -> LocalBoxFuture<'static, ExecuteResult> { let result = execute_ls(context); diff --git a/crates/shell/src/main.rs b/crates/shell/src/main.rs index aecacdf..cdb2e69 100644 --- a/crates/shell/src/main.rs +++ b/crates/shell/src/main.rs @@ -17,10 +17,20 @@ mod completion; mod helper; fn commands() -> HashMap> { - HashMap::from([( - "ls".to_string(), - Rc::new(commands::LsCommand) as Rc, - )]) + HashMap::from([ + ( + "ls".to_string(), + Rc::new(commands::LsCommand) as Rc, + ), + ( + "alias".to_string(), + Rc::new(commands::AliasCommand) as Rc, + ), + ( + "unalias".to_string(), + Rc::new(commands::AliasCommand) as Rc, + ), + ]) } async fn execute(text: &str, state: &mut ShellState) -> anyhow::Result { @@ -48,8 +58,8 @@ async fn execute(text: &str, state: &mut ShellState) -> anyhow::Result { match result { ExecuteResult::Continue(exit_code, changes, _) => { - state.apply_changes(&changes); // set CWD to the last command's CWD + state.apply_changes(&changes); std::env::set_current_dir(state.cwd()).context("Failed to set CWD")?; Ok(exit_code) }