chore: extracted some logic in ShedVi into helpers, cleaned up compiler warnings
This commit is contained in:
@@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
@@ -1515,6 +1515,7 @@ impl ShedVi {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Annotates shell input with invisible Unicode markers for syntax highlighting
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user