Added alias (-a) and signal (-S) flags for 'complete' and 'compgen'

This commit is contained in:
2026-02-27 13:10:24 -05:00
parent faae6b82be
commit 076c94df3c
3 changed files with 78 additions and 13 deletions

View File

@@ -12,7 +12,7 @@ use crate::{
state::{self, read_meta, write_meta}, state::{self, read_meta, write_meta},
}; };
pub const COMPGEN_OPTS: [OptSpec; 9] = [ pub const COMPGEN_OPTS: [OptSpec; 11] = [
OptSpec { OptSpec {
opt: Opt::Short('F'), opt: Opt::Short('F'),
takes_arg: true, takes_arg: true,
@@ -45,13 +45,21 @@ pub const COMPGEN_OPTS: [OptSpec; 9] = [
opt: Opt::Short('v'), opt: Opt::Short('v'),
takes_arg: false, takes_arg: false,
}, },
OptSpec {
opt: Opt::Short('a'),
takes_arg: false,
},
OptSpec {
opt: Opt::Short('S'),
takes_arg: false,
},
OptSpec { OptSpec {
opt: Opt::Short('o'), opt: Opt::Short('o'),
takes_arg: true, takes_arg: true,
}, },
]; ];
pub const COMP_OPTS: [OptSpec; 12] = [ pub const COMP_OPTS: [OptSpec; 14] = [
OptSpec { OptSpec {
opt: Opt::Short('F'), opt: Opt::Short('F'),
takes_arg: true, takes_arg: true,
@@ -96,6 +104,14 @@ pub const COMP_OPTS: [OptSpec; 12] = [
opt: Opt::Short('v'), opt: Opt::Short('v'),
takes_arg: false, takes_arg: false,
}, },
OptSpec {
opt: Opt::Short('a'),
takes_arg: false,
},
OptSpec {
opt: Opt::Short('S'),
takes_arg: false,
},
OptSpec { OptSpec {
opt: Opt::Short('o'), opt: Opt::Short('o'),
takes_arg: true, takes_arg: true,
@@ -105,20 +121,22 @@ pub const COMP_OPTS: [OptSpec; 12] = [
bitflags! { bitflags! {
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CompFlags: u32 { pub struct CompFlags: u32 {
const FILES = 0b0000000001; const FILES = 0b0000000001;
const DIRS = 0b0000000010; const DIRS = 0b0000000010;
const CMDS = 0b0000000100; const CMDS = 0b0000000100;
const USERS = 0b0000001000; const USERS = 0b0000001000;
const VARS = 0b0000010000; const VARS = 0b0000010000;
const JOBS = 0b0000100000; const JOBS = 0b0000100000;
const PRINT = 0b0001000000; const ALIAS = 0b0001000000;
const REMOVE = 0b0010000000; const SIGNALS = 0b0010000000;
const PRINT = 0b0100000000;
const REMOVE = 0b1000000000;
} }
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CompOptFlags: u32 { pub struct CompOptFlags: u32 {
const DEFAULT = 0b0000000001; const DEFAULT = 0b0000000001;
const DIRNAMES = 0b0000000010; const DIRNAMES = 0b0000000010;
const NOSPACE = 0b0000000100; const NOSPACE = 0b0000000100;
} }
} }
@@ -274,6 +292,8 @@ pub fn get_comp_opts(opts: Vec<Opt>) -> ShResult<CompOpts> {
} }
}, },
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('r') => comp_opts.flags |= CompFlags::REMOVE,
Opt::Short('j') => comp_opts.flags |= CompFlags::JOBS, Opt::Short('j') => comp_opts.flags |= CompFlags::JOBS,
Opt::Short('p') => comp_opts.flags |= CompFlags::PRINT, Opt::Short('p') => comp_opts.flags |= CompFlags::PRINT,

View File

@@ -2,6 +2,8 @@ use std::{
collections::HashSet, fmt::Debug, path::PathBuf, sync::Arc, collections::HashSet, fmt::Debug, path::PathBuf, sync::Arc,
}; };
use nix::sys::signal::Signal;
use crate::{ use crate::{
builtin::complete::{CompFlags, CompOptFlags, CompOpts}, builtin::complete::{CompFlags, CompOptFlags, CompOpts},
libsh::{ libsh::{
@@ -16,9 +18,31 @@ use crate::{
Marker, annotate_input_recursive, Marker, annotate_input_recursive,
markers::{self, is_marker}, 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<String> {
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<String> {
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<String> { pub fn complete_jobs(start: &str) -> Vec<String> {
if let Some(prefix) = start.strip_prefix('%') { if let Some(prefix) = start.strip_prefix('%') {
read_jobs(|j| { read_jobs(|j| {
@@ -227,6 +251,8 @@ pub struct BashCompSpec {
pub signals: bool, pub signals: bool,
/// -j: complete job pids or names /// -j: complete job pids or names
pub jobs: bool, pub jobs: bool,
/// -a: complete aliases
pub aliases: bool,
pub flags: CompOptFlags, pub flags: CompOptFlags,
/// The original command /// The original command
@@ -277,6 +303,10 @@ impl BashCompSpec {
self.jobs = enable; self.jobs = enable;
self self
} }
pub fn aliases(mut self, enable: bool) -> Self {
self.aliases = enable;
self
}
pub fn from_comp_opts(opts: CompOpts) -> Self { pub fn from_comp_opts(opts: CompOpts) -> Self {
let CompOpts { let CompOpts {
func, func,
@@ -294,6 +324,7 @@ impl BashCompSpec {
users: flags.contains(CompFlags::USERS), users: flags.contains(CompFlags::USERS),
vars: flags.contains(CompFlags::VARS), vars: flags.contains(CompFlags::VARS),
jobs: flags.contains(CompFlags::JOBS), jobs: flags.contains(CompFlags::JOBS),
aliases: flags.contains(CompFlags::ALIAS),
flags: opt_flags, flags: opt_flags,
signals: false, // TODO: implement signal completion signals: false, // TODO: implement signal completion
source: String::new(), source: String::new(),
@@ -390,6 +421,12 @@ impl CompSpec for BashCompSpec {
if self.jobs { if self.jobs {
candidates.extend(complete_jobs(&expanded)); 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 { if let Some(words) = &self.wordlist {
candidates.extend(words.iter().filter(|w| w.starts_with(&expanded)).cloned()); candidates.extend(words.iter().filter(|w| w.starts_with(&expanded)).cloned());
} }

View File

@@ -1035,6 +1035,14 @@ impl MetaTab {
"disown".into(), "disown".into(),
Box::new(BashCompSpec::new().jobs(true)) as Box<dyn CompSpec>, Box::new(BashCompSpec::new().jobs(true)) as Box<dyn CompSpec>,
); );
map.insert(
"alias".into(),
Box::new(BashCompSpec::new().aliases(true)) as Box<dyn CompSpec>,
);
map.insert(
"trap".into(),
Box::new(BashCompSpec::new().signals(true)) as Box<dyn CompSpec>,
);
map map
} }