chore: extracted some logic in ShedVi into helpers, cleaned up compiler warnings

This commit is contained in:
2026-03-21 01:19:55 -04:00
parent 4b07990fc5
commit 1c42a36810
6 changed files with 389 additions and 393 deletions

View File

@@ -1,7 +1,6 @@
use std::{env, io::Write, path::Path};
use ariadne::Span as ASpan;
use nix::libc::STDIN_FILENO;
use crate::{
libsh::{
@@ -9,11 +8,10 @@ use crate::{
guards::RawModeGuard,
},
parse::{
NdRule, Node, Redir, RedirType,
NdRule, Node,
execute::{exec_input, prepare_argv},
lex::{QuoteState, Span},
},
procio::{IoFrame, IoMode},
readline::{complete::ScoredCandidate, markers},
state,
};
@@ -100,13 +98,12 @@ pub fn help(node: Node) -> ShResult<()> {
let expanded = expand_help(&unescaped);
let tags = read_tags(&expanded);
for (tag, line) in &tags {}
for (_tag, _line) in &tags {}
if let Some((matched_tag, line)) = get_best_match(&topic, &tags) {
if let Some((_matched_tag, line)) = get_best_match(&topic, &tags) {
open_help(&expanded, Some(line), Some(filename))?;
state::set_status(0);
return Ok(());
} else {
}
}
}

View File

@@ -13,7 +13,7 @@ use crate::{
prelude::*,
procio::{IoMode, borrow_fd},
signal::{disable_reaping, enable_reaping},
state::{self, ShellParam, Var, VarFlags, VarKind, set_status, write_jobs, write_vars},
state::{self, ShellParam, VarFlags, VarKind, set_status, write_jobs, write_vars},
};
pub const SIG_EXIT_OFFSET: i32 = 128;

View File

@@ -26,7 +26,6 @@ use crate::{
state::{self, VarFlags, VarKind, read_shopts, read_vars, write_meta, write_vars},
};
const PUNCTUATION: [&str; 3] = ["?", "!", "."];
const DEFAULT_VIEWPORT_HEIGHT: usize = 40;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -551,6 +550,7 @@ impl Default for LineBuf {
}
}
#[allow(dead_code,unused_variables)]
impl LineBuf {
pub fn new() -> Self {
Self::default()
@@ -2432,7 +2432,7 @@ impl LineBuf {
self.insert_str(&contents);
}
ReadSrc::Cmd(cmd) => {
let output = match expand_cmd_sub(&cmd) {
let output = match expand_cmd_sub(cmd) {
Ok(out) => out,
Err(e) => {
e.print_error();
@@ -2582,11 +2582,10 @@ impl LineBuf {
let new_cursor = self.cursor.pos;
// Stop merging on any non-char-insert command, even if buffer didn't change
if !is_char_insert && !is_undo_op {
if let Some(edit) = self.undo_stack.last_mut() {
if !is_char_insert && !is_undo_op
&& let Some(edit) = self.undo_stack.last_mut() {
edit.merging = false;
}
}
if self.lines != before && !is_undo_op {
self.redo_stack.clear();
@@ -2607,13 +2606,12 @@ impl LineBuf {
} else {
self.handle_edit(before, new_cursor, old_cursor);
// Change starts a new merge chain so subsequent InsertChars merge into it
if starts_merge {
if let Some(edit) = self.undo_stack.last_mut() {
if starts_merge
&& let Some(edit) = self.undo_stack.last_mut() {
edit.merging = true;
}
}
}
}
self.fix_cursor();
res
@@ -3040,7 +3038,7 @@ impl Display for LineBuf {
}
cloned[e].push_char(markers::VISUAL_MODE_END);
}
SelectMode::Block(pos) => todo!(),
SelectMode::Block(_pos) => todo!(),
}
let mut lines = vec![];
for line in &cloned {

View File

@@ -1,6 +1,6 @@
use history::History;
use keys::{KeyCode, KeyEvent, ModKeys};
use linebuf::{LineBuf, SelectMode};
use linebuf::LineBuf;
use std::collections::VecDeque;
use std::fmt::Write;
use term::{KeyReader, Layout, LineWriter, PollReader, TermWriter, get_win_size};
@@ -10,14 +10,13 @@ use vimode::{CmdReplay, ModeReport, ViInsert, ViMode, ViNormal, ViReplace, ViVis
use crate::builtin::keymap::{KeyMapFlags, KeyMapMatch};
use crate::expand::expand_prompt;
use crate::libsh::error::{ShErr, ShErrKind};
use crate::libsh::utils::AutoCmdVecUtils;
use crate::parse::lex::{LexStream, QuoteState};
use crate::readline::complete::{FuzzyCompleter, SelectorResponse};
use crate::readline::term::{Pos, TermReader, calc_str_width};
use crate::readline::vimode::{ViEx, ViVerbatim};
use crate::state::{
AutoCmdKind, ShellParam, Var, VarFlags, VarKind, read_logic, read_meta, read_shopts, with_vars, write_meta, write_vars
AutoCmdKind, ShellParam, Var, VarFlags, VarKind, read_logic, read_shopts, with_vars, write_meta, write_vars
};
use crate::{
libsh::error::ShResult,
@@ -278,45 +277,24 @@ pub struct ShedVi {
impl ShedVi {
pub fn new(prompt: Prompt, tty: RawFd) -> ShResult<Self> {
let mut new = Self {
reader: PollReader::new(),
writer: TermWriter::new(tty),
prompt,
tty,
completer: Box::new(FuzzyCompleter::default()),
highlighter: Highlighter::new(),
mode: Box::new(ViInsert::new()),
saved_mode: None,
pending_keymap: Vec::new(),
old_layout: None,
repeat_action: None,
repeat_motion: None,
editor: LineBuf::new(),
history: History::new()?,
ex_history: History::empty(),
needs_redraw: true,
ctrl_d_warning_counter: 0,
status_msgs: VecDeque::new()
};
write_vars(|v| {
v.set_var(
"SHED_VI_MODE",
VarKind::Str(new.mode.report_mode().to_string()),
VarFlags::NONE,
)
})?;
new.prompt.refresh();
new.writer.flush_write("\n")?; // ensure we start on a new line, in case the previous command didn't end with a newline
new.print_line(false)?;
Ok(new)
Self::new_private(prompt, tty, true)
}
pub fn new_no_hist(prompt: Prompt, tty: RawFd) -> ShResult<Self> {
Self::new_private(prompt, tty, false)
}
fn new_private(prompt: Prompt, tty: RawFd, with_hist: bool) -> ShResult<Self> {
let history = if with_hist {
History::new()?
} else {
History::empty()
};
let mut new = Self {
reader: PollReader::new(),
writer: TermWriter::new(tty),
tty,
prompt,
tty,
completer: Box::new(FuzzyCompleter::default()),
highlighter: Highlighter::new(),
mode: Box::new(ViInsert::new()),
@@ -326,7 +304,7 @@ impl ShedVi {
repeat_action: None,
repeat_motion: None,
editor: LineBuf::new(),
history: History::empty(),
history,
ex_history: History::empty(),
needs_redraw: true,
ctrl_d_warning_counter: 0,
@@ -677,8 +655,7 @@ impl ShedVi {
Ok(ReadlineEvent::Pending)
}
pub fn handle_key(&mut self, key: KeyEvent) -> ShResult<Option<ReadlineEvent>> {
if self.should_accept_hint(&key) {
fn accept_hint(&mut self) -> ShResult<Option<ReadlineEvent>> {
self.editor.accept_hint();
if !self.history.at_pending() {
self.history.reset_to_pending();
@@ -687,10 +664,15 @@ impl ShedVi {
.history
.update_pending_cmd((&self.editor.joined(), self.editor.cursor_to_flat()));
self.needs_redraw = true;
return Ok(None);
Ok(None)
}
if let KeyEvent(KeyCode::Tab, mod_keys) = key {
fn handle_tab(&mut self, key: KeyEvent) -> ShResult<Option<ReadlineEvent>> {
let KeyEvent(KeyCode::Tab, mod_keys) = key else {
return Ok(None)
};
if self.mode.report_mode() != ModeReport::Ex
&& self.editor.attempt_history_expansion(&self.history)
{
@@ -789,10 +771,10 @@ impl ShedVi {
}
self.needs_redraw = true;
return Ok(None);
} else if let KeyEvent(KeyCode::Char('R'), ModKeys::CTRL) = key
&& matches!(self.mode.report_mode(), ModeReport::Insert | ModeReport::Ex)
{
Ok(None)
}
fn start_hist_search(&mut self) {
let initial = self.focused_editor().joined();
match self.focused_history().start_search(&initial) {
Some(entry) => {
@@ -854,6 +836,34 @@ impl ShedVi {
}
}
fn submit(&mut self) -> ShResult<Option<ReadlineEvent>> {
if self.editor.attempt_history_expansion(&self.history) {
// If history expansion occurred, don't submit yet
// allow the user to see the expanded command and accept or edit it before submitting
return Ok(None);
}
self.editor.set_hint(None);
self.editor.set_cursor_from_flat(self.editor.cursor_max());
self.print_line(true)?;
self.writer.flush_write("\n")?;
let buf = self.editor.take_buf();
self.history.reset();
Ok(Some(ReadlineEvent::Line(buf)))
}
pub fn handle_key(&mut self, key: KeyEvent) -> ShResult<Option<ReadlineEvent>> {
if self.should_accept_hint(&key) {
return self.accept_hint();
}
if let KeyEvent(KeyCode::Tab, _) = key {
return self.handle_tab(key);
} else if let KeyEvent(KeyCode::Char('R'), ModKeys::CTRL) = key
&& matches!(self.mode.report_mode(), ModeReport::Insert | ModeReport::Ex) {
self.start_hist_search();
}
let Ok(cmd) = self.mode.handle_key_fallible(key) else {
// it's an ex mode error
self.swap_mode(&mut (Box::new(ViNormal::new()) as Box<dyn ViMode>));
@@ -872,21 +882,8 @@ impl ShedVi {
if cmd.is_submit_action()
&& !self.editor.cursor_is_escaped()
&& (self.should_submit()? || !read_shopts(|o| o.prompt.linebreak_on_incomplete))
{
if self.editor.attempt_history_expansion(&self.history) {
// If history expansion occurred, don't submit yet
// allow the user to see the expanded command and accept or edit it before submitting
return Ok(None);
}
self.editor.set_hint(None);
self.editor.set_cursor_from_flat(self.editor.cursor_max());
self.print_line(true)?;
self.writer.flush_write("\n")?;
let buf = self.editor.take_buf();
self.history.reset();
return Ok(Some(ReadlineEvent::Line(buf)));
&& (self.should_submit()? || !read_shopts(|o| o.prompt.linebreak_on_incomplete)) {
return self.submit();
}
if (cmd.verb().is_some_and(|v| v.1 == Verb::EndOfFile)
@@ -1354,14 +1351,7 @@ impl ShedVi {
}
}
pub fn exec_cmd(&mut self, mut cmd: ViCmd, from_replay: bool) -> ShResult<()> {
if cmd.verb().is_some() && let Some(range) = self.editor.select_range() {
cmd.motion = Some(MotionCmd(1, range))
};
if cmd.is_mode_transition() {
return self.exec_mode_transition(cmd, from_replay);
} else if cmd.is_cmd_repeat() {
pub fn handle_cmd_repeat(&mut self, cmd: ViCmd) -> ShResult<()> {
let Some(replay) = self.repeat_action.clone() else {
return Ok(());
};
@@ -1423,8 +1413,10 @@ impl ShedVi {
}
_ => unreachable!("motions should be handled in the other branch"),
}
return Ok(());
} else if cmd.is_motion_repeat() {
Ok(())
}
pub fn handle_motion_repeat(&mut self, cmd: ViCmd) -> ShResult<()> {
match cmd.motion.as_ref().unwrap() {
MotionCmd(count, Motion::RepeatMotion) => {
let Some(motion) = self.repeat_motion.clone() else {
@@ -1437,7 +1429,7 @@ impl ShedVi {
raw_seq: format!("{count};"),
flags: CmdFlags::empty(),
};
return self.editor.exec_cmd(repeat_cmd);
self.editor.exec_cmd(repeat_cmd)
}
MotionCmd(count, Motion::RepeatMotionRev) => {
let Some(motion) = self.repeat_motion.clone() else {
@@ -1452,12 +1444,23 @@ impl ShedVi {
raw_seq: format!("{count},"),
flags: CmdFlags::empty(),
};
return self.editor.exec_cmd(repeat_cmd);
self.editor.exec_cmd(repeat_cmd)
}
_ => unreachable!(),
}
}
pub fn exec_cmd(&mut self, mut cmd: ViCmd, from_replay: bool) -> ShResult<()> {
if cmd.verb().is_some() && let Some(range) = self.editor.select_range() {
cmd.motion = Some(MotionCmd(1, range))
};
if cmd.is_mode_transition() {
self.exec_mode_transition(cmd, from_replay)
} else if cmd.is_cmd_repeat() {
self.handle_cmd_repeat(cmd)
} else if cmd.is_motion_repeat() {
self.handle_motion_repeat(cmd)
} else {
if self.mode.report_mode() == ModeReport::Visual && self.editor.select_range().is_none() {
self.editor.stop_selecting();
let mut mode: Box<dyn ViMode> = Box::new(ViNormal::new());
@@ -1484,10 +1487,7 @@ impl ShedVi {
self.editor.exec_cmd(cmd.clone())?;
if self.mode.report_mode() == ModeReport::Visual
&& cmd
.verb()
.is_some_and(|v| v.1.is_edit() || v.1 == Verb::Yank)
{
&& cmd.verb().is_some_and(|v| v.1.is_edit() || v.1 == Verb::Yank) {
self.editor.stop_selecting();
let mut mode: Box<dyn ViMode> = Box::new(ViNormal::new());
self.swap_mode(&mut mode);
@@ -1516,6 +1516,7 @@ impl ShedVi {
Ok(())
}
}
}
/// Annotates shell input with invisible Unicode markers for syntax highlighting
///

View File

@@ -69,7 +69,7 @@ pub fn get_win_size(fd: RawFd) -> (Col, Row) {
}
}
fn enumerate_lines(s: &str, left_pad: usize, show_numbers: bool, offset: usize, total_buf_lines: usize) -> String {
fn enumerate_lines(s: &str, left_pad: usize, show_numbers: bool, offset: usize, _total_buf_lines: usize) -> String {
let lines: Vec<&str> = s.split('\n').collect();
let visible_count = lines.len();
let max_num_len = (offset + visible_count).to_string().len();

View File

@@ -5,10 +5,9 @@ use std::str::Chars;
use itertools::Itertools;
use crate::bitflags;
use crate::expand::{Expander, expand_raw};
use crate::expand::Expander;
use crate::libsh::error::{ShErr, ShErrKind, ShResult};
use crate::parse::lex::TkFlags;
use crate::readline::complete::SimpleCompleter;
use crate::readline::history::History;
use crate::readline::keys::KeyEvent;
use crate::readline::linebuf::LineBuf;
@@ -17,7 +16,7 @@ use crate::readline::vicmd::{
WriteDest,
};
use crate::readline::vimode::{ModeReport, ViInsert, ViMode};
use crate::state::{get_home, write_meta};
use crate::state::write_meta;
bitflags! {
#[derive(Debug,Clone,Copy,PartialEq,Eq)]
@@ -83,7 +82,7 @@ impl ExEditor {
}
}
pub fn handle_key(&mut self, key: KeyEvent) -> ShResult<()> {
let Some(mut cmd) = self.mode.handle_key(key) else {
let Some(cmd) = self.mode.handle_key(key) else {
return Ok(());
};
log::debug!("ExEditor got cmd: {:?}", cmd);
@@ -268,6 +267,7 @@ fn parse_ex_command(chars: &mut Peekable<Chars<'_>>) -> Result<Option<Verb>, Opt
}
_ if "help".starts_with(&cmd_name) => {
let cmd = "help ".to_string() + chars.collect::<String>().trim();
log::debug!("Parsed help command: {}", cmd);
Ok(Some(Verb::ShellCmd(cmd)))
}
"normal!" => parse_normal(chars),