From bfe23b9cd40471b7915da828cd2b2959f7ed183d Mon Sep 17 00:00:00 2001 From: pagedmov Date: Fri, 27 Feb 2026 13:10:24 -0500 Subject: [PATCH] Added alias (-a) and signal (-S) flags for 'complete' and 'compgen' --- src/builtin/complete.rs | 44 +++++++++++++++++++++++++++++----------- src/readline/complete.rs | 39 ++++++++++++++++++++++++++++++++++- src/state.rs | 8 ++++++++ 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/src/builtin/complete.rs b/src/builtin/complete.rs index 028d4f0..17dfd93 100644 --- a/src/builtin/complete.rs +++ b/src/builtin/complete.rs @@ -12,7 +12,7 @@ use crate::{ state::{self, read_meta, write_meta}, }; -pub const COMPGEN_OPTS: [OptSpec; 9] = [ +pub const COMPGEN_OPTS: [OptSpec; 11] = [ OptSpec { opt: Opt::Short('F'), takes_arg: true, @@ -45,13 +45,21 @@ pub const COMPGEN_OPTS: [OptSpec; 9] = [ opt: Opt::Short('v'), takes_arg: false, }, + OptSpec { + opt: Opt::Short('a'), + takes_arg: false, + }, + OptSpec { + opt: Opt::Short('S'), + takes_arg: false, + }, OptSpec { opt: Opt::Short('o'), takes_arg: true, }, ]; -pub const COMP_OPTS: [OptSpec; 12] = [ +pub const COMP_OPTS: [OptSpec; 14] = [ OptSpec { opt: Opt::Short('F'), takes_arg: true, @@ -96,6 +104,14 @@ pub const COMP_OPTS: [OptSpec; 12] = [ opt: Opt::Short('v'), takes_arg: false, }, + OptSpec { + opt: Opt::Short('a'), + takes_arg: false, + }, + OptSpec { + opt: Opt::Short('S'), + takes_arg: false, + }, OptSpec { opt: Opt::Short('o'), takes_arg: true, @@ -105,20 +121,22 @@ pub const COMP_OPTS: [OptSpec; 12] = [ bitflags! { #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct CompFlags: u32 { - const FILES = 0b0000000001; - const DIRS = 0b0000000010; - const CMDS = 0b0000000100; - const USERS = 0b0000001000; - const VARS = 0b0000010000; - const JOBS = 0b0000100000; - const PRINT = 0b0001000000; - const REMOVE = 0b0010000000; + const FILES = 0b0000000001; + const DIRS = 0b0000000010; + const CMDS = 0b0000000100; + const USERS = 0b0000001000; + const VARS = 0b0000010000; + const JOBS = 0b0000100000; + const ALIAS = 0b0001000000; + const SIGNALS = 0b0010000000; + const PRINT = 0b0100000000; + const REMOVE = 0b1000000000; } #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct CompOptFlags: u32 { - const DEFAULT = 0b0000000001; + const DEFAULT = 0b0000000001; const DIRNAMES = 0b0000000010; - const NOSPACE = 0b0000000100; + const NOSPACE = 0b0000000100; } } @@ -274,6 +292,8 @@ pub fn get_comp_opts(opts: Vec) -> ShResult { } }, + Opt::Short('a') => comp_opts.flags |= CompFlags::ALIAS, + Opt::Short('S') => comp_opts.flags |= CompFlags::SIGNALS, Opt::Short('r') => comp_opts.flags |= CompFlags::REMOVE, Opt::Short('j') => comp_opts.flags |= CompFlags::JOBS, Opt::Short('p') => comp_opts.flags |= CompFlags::PRINT, diff --git a/src/readline/complete.rs b/src/readline/complete.rs index bf13525..12fbbe3 100644 --- a/src/readline/complete.rs +++ b/src/readline/complete.rs @@ -2,6 +2,8 @@ use std::{ collections::HashSet, fmt::Debug, path::PathBuf, sync::Arc, }; +use nix::sys::signal::Signal; + use crate::{ builtin::complete::{CompFlags, CompOptFlags, CompOpts}, libsh::{ @@ -16,9 +18,31 @@ use crate::{ Marker, annotate_input_recursive, markers::{self, is_marker}, }, - state::{VarFlags, VarKind, read_jobs, read_meta, read_vars, write_vars}, + state::{VarFlags, VarKind, read_jobs, read_logic, read_meta, read_vars, write_vars}, }; +pub fn complete_signals(start: &str) -> Vec { + Signal::iterator() + .map(|s| { + s.to_string() + .strip_prefix("SIG") + .unwrap_or(s.as_ref()) + .to_string() + }) + .filter(|s| s.starts_with(start)) + .collect() +} + +pub fn complete_aliases(start: &str) -> Vec { + read_logic(|l| { + l.aliases() + .iter() + .filter(|a| a.0.starts_with(start)) + .map(|a| a.0.clone()) + .collect() + }) +} + pub fn complete_jobs(start: &str) -> Vec { if let Some(prefix) = start.strip_prefix('%') { read_jobs(|j| { @@ -227,6 +251,8 @@ pub struct BashCompSpec { pub signals: bool, /// -j: complete job pids or names pub jobs: bool, + /// -a: complete aliases + pub aliases: bool, pub flags: CompOptFlags, /// The original command @@ -277,6 +303,10 @@ impl BashCompSpec { self.jobs = enable; self } + pub fn aliases(mut self, enable: bool) -> Self { + self.aliases = enable; + self + } pub fn from_comp_opts(opts: CompOpts) -> Self { let CompOpts { func, @@ -294,6 +324,7 @@ impl BashCompSpec { users: flags.contains(CompFlags::USERS), vars: flags.contains(CompFlags::VARS), jobs: flags.contains(CompFlags::JOBS), + aliases: flags.contains(CompFlags::ALIAS), flags: opt_flags, signals: false, // TODO: implement signal completion source: String::new(), @@ -390,6 +421,12 @@ impl CompSpec for BashCompSpec { if self.jobs { candidates.extend(complete_jobs(&expanded)); } + if self.aliases { + candidates.extend(complete_aliases(&expanded)); + } + if self.signals { + candidates.extend(complete_signals(&expanded)); + } if let Some(words) = &self.wordlist { candidates.extend(words.iter().filter(|w| w.starts_with(&expanded)).cloned()); } diff --git a/src/state.rs b/src/state.rs index 0eb5533..b893470 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1035,6 +1035,14 @@ impl MetaTab { "disown".into(), Box::new(BashCompSpec::new().jobs(true)) as Box, ); + map.insert( + "alias".into(), + Box::new(BashCompSpec::new().aliases(true)) as Box, + ); + map.insert( + "trap".into(), + Box::new(BashCompSpec::new().signals(true)) as Box, + ); map }