diff --git a/src/builtin/alias.rs b/src/builtin/alias.rs index 23c28ef..de3bf96 100644 --- a/src/builtin/alias.rs +++ b/src/builtin/alias.rs @@ -30,7 +30,7 @@ pub fn alias(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult< ShErr::full( ShErrKind::SyntaxErr, "alias: Expected an assignment in alias args", - span.into() + span ) ) }; @@ -41,3 +41,45 @@ pub fn alias(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult< state::set_status(0); Ok(()) } + +pub fn unalias(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<()> { + let NdRule::Command { assignments: _, argv } = node.class else { + unreachable!() + }; + + let (argv, io_frame) = setup_builtin(argv, job, Some((io_stack, node.redirs)))?; + + + if argv.is_empty() { + // Display the environment variables + let mut alias_output = read_logic(|l| { + l.aliases() + .iter() + .map(|ent| format!("{} = \"{}\"", ent.0, ent.1)) + .collect::>() + }); + alias_output.sort(); // Sort them alphabetically + let mut alias_output = alias_output.join("\n"); // Join them with newlines + alias_output.push('\n'); // Push a final newline + + let stdout = borrow_fd(STDOUT_FILENO); + write(stdout, alias_output.as_bytes())?; // Write it + } else { + for (arg,span) in argv { + flog!(DEBUG, arg); + if read_logic(|l| l.get_alias(&arg)).is_none() { + return Err( + ShErr::full( + ShErrKind::SyntaxErr, + format!("unalias: alias '{arg}' not found"), + span + ) + ) + }; + write_logic(|l| l.remove_alias(&arg)) + } + } + io_frame.unwrap().restore()?; + state::set_status(0); + Ok(()) +} diff --git a/src/builtin/jobctl.rs b/src/builtin/jobctl.rs index fa47d6f..8c82060 100644 --- a/src/builtin/jobctl.rs +++ b/src/builtin/jobctl.rs @@ -95,7 +95,7 @@ fn parse_job_id(arg: &str, blame: Span) -> ShResult { ShErr::full( ShErrKind::InternalErr, "Found a job but no table id in parse_job_id()", - blame.into() + blame ) ) } @@ -121,7 +121,7 @@ fn parse_job_id(arg: &str, blame: Span) -> ShResult { ShErr::full( ShErrKind::InternalErr, "Found a job but no table id in parse_job_id()", - blame.into() + blame ) ) } @@ -130,7 +130,7 @@ fn parse_job_id(arg: &str, blame: Span) -> ShResult { ShErr::full( ShErrKind::SyntaxErr, format!("Invalid fd arg: {}", arg), - blame.into() + blame ) ) } @@ -151,12 +151,12 @@ pub fn jobs(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<( ShErr::full( ShErrKind::SyntaxErr, "Invalid flag in jobs call", - span.into() + span ) ) } chars.next(); - while let Some(ch) = chars.next() { + for ch in chars { let flag = match ch { 'l' => JobCmdFlags::LONG, 'p' => JobCmdFlags::PIDS, @@ -167,7 +167,7 @@ pub fn jobs(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<( ShErr::full( ShErrKind::SyntaxErr, "Invalid flag in jobs call", - span.into() + span ) ) diff --git a/src/builtin/mod.rs b/src/builtin/mod.rs index c6f44b3..b2e34d2 100644 --- a/src/builtin/mod.rs +++ b/src/builtin/mod.rs @@ -14,7 +14,7 @@ pub mod flowctl; pub mod zoltraak; pub mod shopt; -pub const BUILTINS: [&str;16] = [ +pub const BUILTINS: [&str;17] = [ "echo", "cd", "export", @@ -25,6 +25,7 @@ pub const BUILTINS: [&str;16] = [ "fg", "bg", "alias", + "unalias", "return", "break", "continue", @@ -55,11 +56,12 @@ pub const BUILTINS: [&str;16] = [ /// * If redirections are given to this function, the caller must call `IoFrame.restore()` on the returned `IoFrame` /// * If redirections are given, the second field of the resulting tuple will *always* be `Some()` /// * If no redirections are given, the second field will *always* be `None` +type SetupReturns = ShResult<(Vec<(String,Span)>, Option)>; pub fn setup_builtin( argv: Vec, job: &mut JobBldr, io_mode: Option<(&mut IoStack,Vec)>, -) -> ShResult<(Vec<(String,Span)>, Option)> { +) -> SetupReturns { let mut argv: Vec<(String,Span)> = prepare_argv(argv)?; let child_pgid = if let Some(pgid) = job.pgid() { diff --git a/src/builtin/shift.rs b/src/builtin/shift.rs index aaf61b1..7127e82 100644 --- a/src/builtin/shift.rs +++ b/src/builtin/shift.rs @@ -16,7 +16,7 @@ pub fn shift(node: Node, job: &mut JobBldr) -> ShResult<()> { ShErr::full( ShErrKind::ExecFail, "Expected a number in shift args", - span.into() + span ) ) }; diff --git a/src/builtin/source.rs b/src/builtin/source.rs index d47efd5..a109481 100644 --- a/src/builtin/source.rs +++ b/src/builtin/source.rs @@ -16,7 +16,7 @@ pub fn source(node: Node, job: &mut JobBldr) -> ShResult<()> { ShErr::full( ShErrKind::ExecFail, "source: File not found", - span.into() + span ) ); } @@ -25,7 +25,7 @@ pub fn source(node: Node, job: &mut JobBldr) -> ShResult<()> { ShErr::full( ShErrKind::ExecFail, "source: Given path is not a file", - span.into() + span ) ); } diff --git a/src/builtin/zoltraak.rs b/src/builtin/zoltraak.rs index d78e060..5a378b5 100644 --- a/src/builtin/zoltraak.rs +++ b/src/builtin/zoltraak.rs @@ -4,7 +4,7 @@ use crate::{getopt::{get_opts_from_tokens, Opt, OptSet}, jobs::JobBldr, libsh::e use super::setup_builtin; -pub const ZOLTRAAK_OPTS: LazyLock = LazyLock::new(|| { +pub static ZOLTRAAK_OPTS: LazyLock = LazyLock::new(|| { [ Opt::Long("dry-run".into()), Opt::Long("confirm".into()), @@ -90,7 +90,7 @@ pub fn zoltraak(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResu } if let Err(e) = annihilate(&arg, flags).blame(span) { io_frame.restore()?; - return Err(e.into()); + return Err(e); } } diff --git a/src/expand.rs b/src/expand.rs index 9017087..4bc6a2a 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -198,7 +198,7 @@ pub fn expand_cmd_sub(raw: &str) -> ShResult { flog!(DEBUG, "done"); Ok(io_buf.as_str()?.trim().to_string()) } - _ => return Err(ShErr::simple(ShErrKind::InternalErr, "Command sub failed")) + _ => Err(ShErr::simple(ShErrKind::InternalErr, "Command sub failed")) } } } @@ -557,7 +557,7 @@ fn tokenize_prompt(raw: &str) -> Vec { // Collect up to 2 more octal digits for _ in 0..2 { if let Some(&next_ch) = chars.peek() { - if next_ch >= '0' && next_ch <= '7' { + if ('0'..='7').contains(&next_ch) { octal_str.push(chars.next().unwrap()); } else { break; @@ -631,7 +631,7 @@ pub fn expand_prompt(raw: &str) -> ShResult { } let pathbuf = PathBuf::from(&path); let mut segments = pathbuf.iter().count(); - let mut path_iter = pathbuf.into_iter(); + let mut path_iter = pathbuf.iter(); while segments > 4 { path_iter.next(); segments -= 1; @@ -698,9 +698,9 @@ pub fn expand_aliases(input: String, mut already_expanded: HashSet, log_ } if expanded_this_iter.is_empty() { - return result + result } else { - already_expanded.extend(expanded_this_iter.into_iter()); - return expand_aliases(result, already_expanded, log_tab) + already_expanded.extend(expanded_this_iter); + expand_aliases(result, already_expanded, log_tab) } } diff --git a/src/fern.rs b/src/fern.rs index 01e906b..8d11220 100644 --- a/src/fern.rs +++ b/src/fern.rs @@ -1,3 +1,8 @@ +#![allow( + clippy::derivable_impls, + clippy::tabs_in_doc_comments, + clippy::while_let_on_iterator +)] pub mod prelude; pub mod libsh; pub mod prompt; diff --git a/src/jobs.rs b/src/jobs.rs index bbd01e8..0810c22 100644 --- a/src/jobs.rs +++ b/src/jobs.rs @@ -64,7 +64,7 @@ pub struct ChildProc { stat: WtStat } -impl<'a> ChildProc { +impl ChildProc { pub fn new(pid: Pid, command: Option<&str>, pgid: Option) -> ShResult { let command = command.map(|str| str.to_string()); let stat = if kill(pid,None).is_ok() { @@ -86,7 +86,7 @@ impl<'a> ChildProc { self.pgid } pub fn cmd(&self) -> Option<&str> { - self.command.as_ref().map(|cmd| cmd.as_str()) + self.command.as_deref() } pub fn stat(&self) -> WtStat { self.stat @@ -120,6 +120,7 @@ impl<'a> ChildProc { } } +#[derive(Default,Debug)] pub struct JobTab { fg: Option, order: Vec, @@ -129,7 +130,7 @@ pub struct JobTab { impl JobTab { pub fn new() -> Self { - Self { fg: None, order: vec![], new_updates: vec![], jobs: vec![] } + Self::default() } pub fn take_fg(&mut self) -> Option { self.fg.take() @@ -168,7 +169,7 @@ impl JobTab { job.set_tabid(tab_pos); self.order.push(tab_pos); if !silent { - write(borrow_fd(1),format!("{}", job.display(&self.order, JobCmdFlags::INIT)).as_bytes())?; + write(borrow_fd(1),job.display(&self.order, JobCmdFlags::INIT).as_bytes())?; } if tab_pos == self.jobs.len() { self.jobs.push(Some(job)) @@ -246,7 +247,7 @@ impl JobTab { pub fn get_fg_mut(&mut self) -> Option<&mut Job> { self.fg.as_mut() } - pub fn new_fg<'a>(&mut self, job: Job) -> ShResult> { + pub fn new_fg(&mut self, job: Job) -> ShResult> { let pgid = job.pgid(); self.fg = Some(job); attach_tty(pgid)?; @@ -375,11 +376,12 @@ impl JobBldr { } /// A wrapper around Vec with some job-specific methods +#[derive(Default,Debug)] pub struct JobStack(Vec); impl JobStack { pub fn new() -> Self { - Self(vec![]) + Self::default() } pub fn new_job(&mut self) { self.0.push(JobBldr::new()) @@ -388,8 +390,7 @@ impl JobStack { self.0.last_mut() } pub fn finalize_job(&mut self) -> Option { - let job = self.0.pop().map(|bldr| bldr.build()); - job + self.0.pop().map(|bldr| bldr.build()) } } @@ -453,7 +454,7 @@ impl Job { self.set_stats(stat); Ok(killpg(self.pgid, sig)?) } - pub fn wait_pgrp<'a>(&mut self) -> ShResult> { + pub fn wait_pgrp(&mut self) -> ShResult> { let mut stats = vec![]; flog!(TRACE, "waiting on children"); flog!(TRACE, self.children); @@ -675,14 +676,14 @@ pub fn attach_tty(pgid: Pid) -> ShResult<()> { new_mask.add(Signal::SIGTTIN); new_mask.add(Signal::SIGTTOU); - pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(&mut new_mask), Some(&mut mask_bkup))?; + pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(&new_mask), Some(&mut mask_bkup))?; let result = tcsetpgrp(borrow_fd(0), pgid); - pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(&mut mask_bkup), Some(&mut new_mask))?; + pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(&mask_bkup), Some(&mut new_mask))?; match result { - Ok(_) => return Ok(()), + Ok(_) => Ok(()), Err(e) => { flog!(ERROR, "error while switching term control: {}",e); tcsetpgrp(borrow_fd(0), getpgrp())?; diff --git a/src/libsh/error.rs b/src/libsh/error.rs index 0b30c9a..2206599 100644 --- a/src/libsh/error.rs +++ b/src/libsh/error.rs @@ -114,7 +114,6 @@ impl ShErr { } pub fn with_span(sherr: ShErr, span: Span) -> Self { let (kind,msg,notes,_) = sherr.unpack(); - let span = span.into(); Self::Full { kind, msg, notes, span } } pub fn kind(&self) -> &ShErrKind { @@ -300,19 +299,19 @@ impl From for ShErr { impl From for ShErr { fn from(value: std::env::VarError) -> Self { - ShErr::simple(ShErrKind::InternalErr, &value.to_string()) + ShErr::simple(ShErrKind::InternalErr, value.to_string()) } } impl From for ShErr { fn from(value: rustyline::error::ReadlineError) -> Self { - ShErr::simple(ShErrKind::ParseErr, &value.to_string()) + ShErr::simple(ShErrKind::ParseErr, value.to_string()) } } impl From for ShErr { fn from(value: Errno) -> Self { - ShErr::simple(ShErrKind::Errno, &value.to_string()) + ShErr::simple(ShErrKind::Errno, value.to_string()) } } diff --git a/src/libsh/sys.rs b/src/libsh/sys.rs index f504e5d..75e1bb0 100644 --- a/src/libsh/sys.rs +++ b/src/libsh/sys.rs @@ -35,6 +35,10 @@ pub fn save_termios() { } } #[allow(static_mut_refs)] +///Access the saved termios +/// +///# Safety +///This function is unsafe because it accesses a public mutable static value. This function should only ever be called after save_termios() has already been called. pub unsafe fn get_saved_termios() -> Option { // SAVED_TERMIOS should *only ever* be set once and accessed once // Set at the start of the program, and accessed during the exit of the program to reset the termios. diff --git a/src/libsh/term.rs b/src/libsh/term.rs index 8611889..2452015 100644 --- a/src/libsh/term.rs +++ b/src/libsh/term.rs @@ -127,7 +127,7 @@ impl StyleSet { Self { styles: vec![] } } - pub fn add(mut self, style: Style) -> Self { + pub fn add_style(mut self, style: Style) -> Self { if !self.styles.contains(&style) { self.styles.push(style); } @@ -149,7 +149,7 @@ impl BitOr for Style { type Output = StyleSet; fn bitor(self, rhs: Self) -> Self::Output { - StyleSet::new().add(self).add(rhs) + StyleSet::new().add_style(self).add_style(rhs) } } @@ -158,12 +158,12 @@ impl BitOr