From ffe78620a9b14e3a75df12f9f20b2c65dd105cea Mon Sep 17 00:00:00 2001 From: pagedmov Date: Sun, 1 Mar 2026 02:39:22 -0500 Subject: [PATCH] Fixed 'C' and 'D' verbs deleting the newline character --- src/builtin/alias.rs | 6 ++++-- src/builtin/arrops.rs | 1 - src/builtin/dirstack.rs | 24 +++++++++++++----------- src/builtin/jobctl.rs | 12 ++++++++---- src/builtin/zoltraak.rs | 2 +- src/libsh/error.rs | 8 +++----- src/libsh/term.rs | 2 +- src/parse/execute.rs | 2 +- src/parse/lex.rs | 2 +- src/parse/mod.rs | 3 +-- src/readline/linebuf.rs | 4 ++-- src/shopt.rs | 2 +- 12 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/builtin/alias.rs b/src/builtin/alias.rs index 3cef8da..025173d 100644 --- a/src/builtin/alias.rs +++ b/src/builtin/alias.rs @@ -1,6 +1,8 @@ +use ariadne::Fmt; + use crate::{ jobs::JobBldr, - libsh::error::{ShErr, ShErrKind, ShResult}, + libsh::error::{ShErr, ShErrKind, ShResult, next_color}, parse::{NdRule, Node}, prelude::*, procio::{IoStack, borrow_fd}, @@ -80,7 +82,7 @@ pub fn unalias(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResul } else { for (arg, span) in argv { if read_logic(|l| l.get_alias(&arg)).is_none() { - return Err(ShErr::at(ShErrKind::SyntaxErr, span, format!("unalias: alias '{arg}' not found"))); + return Err(ShErr::at(ShErrKind::SyntaxErr, span, format!("unalias: alias '{}' not found",arg.fg(next_color())))); }; write_logic(|l| l.remove_alias(&arg)) } diff --git a/src/builtin/arrops.rs b/src/builtin/arrops.rs index ea83b8f..e0526d0 100644 --- a/src/builtin/arrops.rs +++ b/src/builtin/arrops.rs @@ -1,4 +1,3 @@ -use std::iter::Peekable; use crate::{ getopt::{Opt, OptSpec, get_opts_from_tokens}, jobs::JobBldr, libsh::error::{ShErr, ShErrKind, ShResult}, parse::{NdRule, Node}, prelude::*, procio::{IoStack, borrow_fd}, state::{self, VarFlags, VarKind, write_vars} diff --git a/src/builtin/dirstack.rs b/src/builtin/dirstack.rs index 9c8c531..c11d8ce 100644 --- a/src/builtin/dirstack.rs +++ b/src/builtin/dirstack.rs @@ -1,11 +1,13 @@ use std::{env, path::PathBuf}; +use ariadne::Fmt; use nix::{libc::STDOUT_FILENO, unistd::write}; +use yansi::Color; use crate::{ builtin::setup_builtin, jobs::JobBldr, - libsh::error::{ShErr, ShErrKind, ShResult}, + libsh::error::{ShErr, ShErrKind, ShResult, next_color}, parse::{NdRule, Node, lex::Span}, procio::{IoStack, borrow_fd}, state::{self, read_meta, write_meta}, @@ -48,17 +50,17 @@ fn print_dirs() -> ShResult<()> { fn change_directory(target: &PathBuf, blame: Span) -> ShResult<()> { if !target.is_dir() { return Err( - ShErr::at(ShErrKind::ExecFail, blame, format!("not a directory: {}", target.display())) + ShErr::at(ShErrKind::ExecFail, blame, format!("not a directory: '{}'", target.display().fg(next_color()))) ); } if let Err(e) = env::set_current_dir(target) { return Err( - ShErr::at(ShErrKind::ExecFail, blame, format!("Failed to change directory: {}", e)) + ShErr::at(ShErrKind::ExecFail, blame, format!("Failed to change directory: '{}'", e.fg(Color::Red))) ); } let new_dir = env::current_dir().map_err(|e| { - ShErr::at(ShErrKind::ExecFail, blame, format!("Failed to get current directory: {}", e)) + ShErr::at(ShErrKind::ExecFail, blame, format!("Failed to get current directory: '{}'", e.fg(Color::Red))) })?; unsafe { env::set_var("PWD", new_dir) }; Ok(()) @@ -85,13 +87,13 @@ fn parse_stack_idx(arg: &str, blame: Span, cmd: &str) -> ShResult { for ch in digits.chars() { if !ch.is_ascii_digit() { return Err( - ShErr::at(ShErrKind::ExecFail, blame, format!("{cmd}: invalid argument: {arg}")) + ShErr::at(ShErrKind::ExecFail, blame, format!("{cmd}: invalid argument: '{}'",arg.fg(next_color()))) ); } } let n = digits.parse::().map_err(|e| { - ShErr::at(ShErrKind::ExecFail, blame, format!("{cmd}: invalid index: {e}")) + ShErr::at(ShErrKind::ExecFail, blame, format!("{cmd}: invalid index: '{}'",e.fg(next_color()))) })?; if from_top { @@ -127,7 +129,7 @@ pub fn pushd(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult< no_cd = true; } else if arg.starts_with('-') { return Err( - ShErr::at(ShErrKind::ExecFail, blame, format!("pushd: invalid option: {arg}")) + ShErr::at(ShErrKind::ExecFail, blame, format!("pushd: invalid option: '{}'", arg.fg(next_color()))) ); } else { if dir.is_some() { @@ -138,7 +140,7 @@ pub fn pushd(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult< let target = PathBuf::from(&arg); if !target.is_dir() { return Err( - ShErr::at(ShErrKind::ExecFail, blame, format!("pushd: not a directory: {arg}")) + ShErr::at(ShErrKind::ExecFail, blame, format!("pushd: not a directory: '{}'", target.display().fg(next_color()))) ); } dir = Some(target); @@ -207,7 +209,7 @@ pub fn popd(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<( no_cd = true; } else if arg.starts_with('-') { return Err( - ShErr::at(ShErrKind::ExecFail, blame, format!("popd: invalid option: {arg}")) + ShErr::at(ShErrKind::ExecFail, blame, format!("popd: invalid option: '{}'", arg.fg(next_color()))) ); } } @@ -307,12 +309,12 @@ pub fn dirs(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<( } _ if arg.starts_with('-') => { return Err( - ShErr::at(ShErrKind::ExecFail, blame, format!("dirs: invalid option: {arg}")) + ShErr::at(ShErrKind::ExecFail, blame, format!("dirs: invalid option: '{}'", arg.fg(next_color()))) ); } _ => { return Err( - ShErr::at(ShErrKind::ExecFail, blame, format!("dirs: unexpected argument: {arg}")) + ShErr::at(ShErrKind::ExecFail, blame, format!("dirs: unexpected argument: '{}'", arg.fg(next_color()))) ); } } diff --git a/src/builtin/jobctl.rs b/src/builtin/jobctl.rs index 597c637..4ef37d1 100644 --- a/src/builtin/jobctl.rs +++ b/src/builtin/jobctl.rs @@ -1,6 +1,8 @@ +use ariadne::Fmt; + use crate::{ jobs::{JobBldr, JobCmdFlags, JobID}, - libsh::error::{ShErr, ShErrKind, ShResult}, + libsh::error::{ShErr, ShErrKind, ShResult, next_color}, parse::{NdRule, Node, lex::Span}, prelude::*, procio::{IoStack, borrow_fd}, @@ -16,6 +18,8 @@ pub enum JobBehavior { pub fn continue_job(node: Node, job: &mut JobBldr, behavior: JobBehavior) -> ShResult<()> { let blame = node.get_span().clone(); + let cmd_tk = node.get_command(); + let cmd_span = cmd_tk.unwrap().span.clone(); let cmd = match behavior { JobBehavior::Foregound => "fg", JobBehavior::Background => "bg", @@ -33,13 +37,13 @@ pub fn continue_job(node: Node, job: &mut JobBldr, behavior: JobBehavior) -> ShR let mut argv = argv.into_iter(); if read_jobs(|j| j.get_fg().is_some()) { - return Err(ShErr::at(ShErrKind::InternalErr, blame, format!("Somehow called '{}' with an existing foreground job", cmd))); + return Err(ShErr::at(ShErrKind::InternalErr, cmd_span, format!("Somehow called '{}' with an existing foreground job", cmd))); } let curr_job_id = if let Some(id) = read_jobs(|j| j.curr_job()) { id } else { - return Err(ShErr::at(ShErrKind::ExecFail, blame, "No jobs found")); + return Err(ShErr::at(ShErrKind::ExecFail, cmd_span, "No jobs found")); }; let tabid = match argv.next() { @@ -111,7 +115,7 @@ fn parse_job_id(arg: &str, blame: Span) -> ShResult { None => Err(ShErr::at(ShErrKind::InternalErr, blame, "Found a job but no table id in parse_job_id()")), } } else { - Err(ShErr::at(ShErrKind::SyntaxErr, blame, format!("Invalid arg: {}", arg))) + Err(ShErr::at(ShErrKind::SyntaxErr, blame, format!("Invalid arg: {}", arg.fg(next_color())))) } } diff --git a/src/builtin/zoltraak.rs b/src/builtin/zoltraak.rs index 9d3cde7..5a3a969 100644 --- a/src/builtin/zoltraak.rs +++ b/src/builtin/zoltraak.rs @@ -3,7 +3,7 @@ use std::os::unix::fs::OpenOptionsExt; use crate::{ getopt::{Opt, OptSpec, get_opts_from_tokens}, jobs::JobBldr, - libsh::error::{Note, ShErr, ShErrKind, ShResult, ShResultExt}, + libsh::error::{ShErr, ShErrKind, ShResult, ShResultExt}, parse::{NdRule, Node}, prelude::*, procio::{IoStack, borrow_fd}, diff --git a/src/libsh/error.rs b/src/libsh/error.rs index 8b1bdd1..bfa4fae 100644 --- a/src/libsh/error.rs +++ b/src/libsh/error.rs @@ -3,7 +3,7 @@ use std::collections::{HashMap, VecDeque}; use std::fmt::Display; use ariadne::Color; use ariadne::{Report, ReportKind}; -use rand::{RngExt, TryRng}; +use rand::TryRng; use crate::{ libsh::term::{Style, Styled}, @@ -13,9 +13,7 @@ use crate::{ pub type ShResult = Result; -pub struct ColorRng { - last_color: Option, -} +pub struct ColorRng; impl ColorRng { fn get_colors() -> &'static [Color] { @@ -53,7 +51,7 @@ impl Iterator for ColorRng { } thread_local! { - static COLOR_RNG: RefCell = const { RefCell::new(ColorRng { last_color: None }) }; + static COLOR_RNG: RefCell = const { RefCell::new(ColorRng) }; } pub fn next_color() -> Color { diff --git a/src/libsh/term.rs b/src/libsh/term.rs index 49b860e..dec8148 100644 --- a/src/libsh/term.rs +++ b/src/libsh/term.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, fmt::Display, ops::BitOr}; +use std::{fmt::Display, ops::BitOr}; pub trait Styled: Sized + Display { fn styled>(self, style: S) -> String { diff --git a/src/parse/execute.rs b/src/parse/execute.rs index 1000793..735c1ad 100644 --- a/src/parse/execute.rs +++ b/src/parse/execute.rs @@ -3,7 +3,7 @@ use std::{ }; -use ariadne::{Fmt, Label, Span as AriadneSpan}; +use ariadne::Fmt; use crate::{ builtin::{ diff --git a/src/parse/lex.rs b/src/parse/lex.rs index e984380..a6d80e2 100644 --- a/src/parse/lex.rs +++ b/src/parse/lex.rs @@ -2,7 +2,7 @@ use std::{ collections::VecDeque, fmt::Display, iter::Peekable, - ops::{Bound, Deref, Range, RangeBounds}, + ops::{Bound, Range, RangeBounds}, str::Chars, sync::Arc, }; diff --git a/src/parse/mod.rs b/src/parse/mod.rs index ce27e35..7630c79 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -4,11 +4,10 @@ use ariadne::{Fmt, Label, Span as AriadneSpan}; use bitflags::bitflags; use fmt::Display; use lex::{LexFlags, LexStream, Span, SpanSource, Tk, TkFlags, TkRule}; -use yansi::Color; use crate::{ libsh::{ - error::{Note, ShErr, ShErrKind, ShResult, next_color}, + error::{ShErr, ShErrKind, ShResult, next_color}, utils::{NodeVecUtils, TkVecUtils}, }, prelude::*, diff --git a/src/readline/linebuf.rs b/src/readline/linebuf.rs index 7d3fd15..bc28b46 100644 --- a/src/readline/linebuf.rs +++ b/src/readline/linebuf.rs @@ -2173,11 +2173,11 @@ impl LineBuf { MotionCmd(_, Motion::BeginningOfLine) => MotionKind::On(self.start_of_line()), MotionCmd(count, Motion::EndOfLine) => { let pos = if count == 1 { - self.end_of_line() + self.end_of_line_exclusive() } else if let Some((_, end)) = self.select_lines_down(count) { end } else { - self.end_of_line() + self.end_of_line_exclusive() }; MotionKind::On(pos) diff --git a/src/shopt.rs b/src/shopt.rs index 9e78779..320b7a8 100644 --- a/src/shopt.rs +++ b/src/shopt.rs @@ -1,6 +1,6 @@ use std::{fmt::Display, str::FromStr}; -use crate::libsh::error::{Note, ShErr, ShErrKind, ShResult}; +use crate::libsh::error::{ShErr, ShErrKind, ShResult}; #[derive(Clone, Copy, Debug)] pub enum ShedBellStyle {