the second field of history entries in the hist file now contain command runtime in seconds, instead of an id
updated rustfmt.toml and formatted codebase
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
max_width = 100
|
||||
tab_spaces = 2
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
newline_style = "Unix"
|
||||
|
||||
wrap_comments = true
|
||||
|
||||
@@ -1404,7 +1404,6 @@ impl FromStr for ParamExp {
|
||||
))
|
||||
};
|
||||
|
||||
|
||||
// Handle indirect var expansion: ${!var}
|
||||
if let Some(var) = s.strip_prefix('!') {
|
||||
if var.ends_with('*') || var.ends_with('@') {
|
||||
|
||||
102
src/main.rs
102
src/main.rs
@@ -37,7 +37,7 @@ use crate::prelude::*;
|
||||
use crate::readline::term::{LineWriter, RawModeGuard, raw_mode};
|
||||
use crate::readline::{Prompt, ReadlineEvent, ShedVi};
|
||||
use crate::signal::{GOT_SIGWINCH, JOB_DONE, QUIT_CODE, check_signals, sig_setup, signals_pending};
|
||||
use crate::state::{AutoCmdKind, read_logic, source_rc, write_jobs, write_meta};
|
||||
use crate::state::{AutoCmdKind, read_logic, read_shopts, source_rc, write_jobs, write_meta};
|
||||
use clap::Parser;
|
||||
use state::{read_vars, write_vars};
|
||||
|
||||
@@ -292,36 +292,9 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
|
||||
let action = km.action_expanded();
|
||||
readline.pending_keymap.clear();
|
||||
for key in action {
|
||||
if let Some(event) = readline.handle_key(key)? {
|
||||
match event {
|
||||
ReadlineEvent::Line(input) => {
|
||||
let start = Instant::now();
|
||||
write_meta(|m| m.start_timer());
|
||||
if let Err(e) = RawModeGuard::with_cooked_mode(|| {
|
||||
exec_input(input, None, true, Some("<stdin>".into()))
|
||||
}) {
|
||||
match e.kind() {
|
||||
ShErrKind::CleanExit(code) => {
|
||||
QUIT_CODE.store(*code, Ordering::SeqCst);
|
||||
return Ok(());
|
||||
}
|
||||
_ => e.print_error(),
|
||||
}
|
||||
}
|
||||
let command_run_time = start.elapsed();
|
||||
log::info!("Command executed in {:.2?}", command_run_time);
|
||||
write_meta(|m| m.stop_timer());
|
||||
readline.fix_column()?;
|
||||
readline.writer.flush_write("\n\r")?;
|
||||
readline.reset(true)?;
|
||||
break;
|
||||
}
|
||||
ReadlineEvent::Eof => {
|
||||
QUIT_CODE.store(0, Ordering::SeqCst);
|
||||
return Ok(());
|
||||
}
|
||||
ReadlineEvent::Pending => {}
|
||||
}
|
||||
let event = readline.handle_key(key).transpose();
|
||||
if let Some(event) = event {
|
||||
handle_readline_event(&mut readline, event)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -331,36 +304,9 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
|
||||
);
|
||||
let buffered = std::mem::take(&mut readline.pending_keymap);
|
||||
for key in buffered {
|
||||
if let Some(event) = readline.handle_key(key)? {
|
||||
match event {
|
||||
ReadlineEvent::Line(input) => {
|
||||
let start = Instant::now();
|
||||
write_meta(|m| m.start_timer());
|
||||
if let Err(e) = RawModeGuard::with_cooked_mode(|| {
|
||||
exec_input(input, None, true, Some("<stdin>".into()))
|
||||
}) {
|
||||
match e.kind() {
|
||||
ShErrKind::CleanExit(code) => {
|
||||
QUIT_CODE.store(*code, Ordering::SeqCst);
|
||||
return Ok(());
|
||||
}
|
||||
_ => e.print_error(),
|
||||
}
|
||||
}
|
||||
let command_run_time = start.elapsed();
|
||||
log::info!("Command executed in {:.2?}", command_run_time);
|
||||
write_meta(|m| m.stop_timer());
|
||||
readline.fix_column()?;
|
||||
readline.writer.flush_write("\n\r")?;
|
||||
readline.reset(true)?;
|
||||
break;
|
||||
}
|
||||
ReadlineEvent::Eof => {
|
||||
QUIT_CODE.store(0, Ordering::SeqCst);
|
||||
return Ok(());
|
||||
}
|
||||
ReadlineEvent::Pending => {}
|
||||
}
|
||||
let event = readline.handle_key(key).transpose();
|
||||
if let Some(event) = event {
|
||||
handle_readline_event(&mut readline, event)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -394,7 +340,18 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
|
||||
}
|
||||
|
||||
// Process any available input
|
||||
match readline.process_input() {
|
||||
let event = readline.process_input();
|
||||
match handle_readline_event(&mut readline, event)? {
|
||||
true => return Ok(()),
|
||||
false => { /* continue looping */ }
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_readline_event(readline: &mut ShedVi, event: ShResult<ReadlineEvent>) -> ShResult<bool> {
|
||||
match event {
|
||||
Ok(ReadlineEvent::Line(input)) => {
|
||||
let pre_exec = read_logic(|l| l.get_autocmds(AutoCmdKind::PreCmd));
|
||||
let post_exec = read_logic(|l| l.get_autocmds(AutoCmdKind::PostCmd));
|
||||
@@ -409,7 +366,7 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
|
||||
match e.kind() {
|
||||
ShErrKind::CleanExit(code) => {
|
||||
QUIT_CODE.store(*code, Ordering::SeqCst);
|
||||
return Ok(());
|
||||
return Ok(true);
|
||||
}
|
||||
_ => e.print_error(),
|
||||
}
|
||||
@@ -420,6 +377,11 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
|
||||
|
||||
post_exec.exec_with(&input);
|
||||
|
||||
if read_shopts(|s| s.core.auto_hist) && !input.is_empty() {
|
||||
readline.history.push(input.clone());
|
||||
readline.history.save()?;
|
||||
}
|
||||
|
||||
readline.fix_column()?;
|
||||
readline.writer.flush_write("\n\r")?;
|
||||
|
||||
@@ -428,24 +390,26 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
|
||||
|
||||
let real_end = start.elapsed();
|
||||
log::info!("Total round trip time: {:.2?}", real_end);
|
||||
Ok(false)
|
||||
}
|
||||
Ok(ReadlineEvent::Eof) => {
|
||||
// Ctrl+D on empty line
|
||||
QUIT_CODE.store(0, Ordering::SeqCst);
|
||||
return Ok(());
|
||||
Ok(true)
|
||||
}
|
||||
Ok(ReadlineEvent::Pending) => {
|
||||
// No complete input yet, keep polling
|
||||
Ok(false)
|
||||
}
|
||||
Err(e) => match e.kind() {
|
||||
ShErrKind::CleanExit(code) => {
|
||||
QUIT_CODE.store(*code, Ordering::SeqCst);
|
||||
return Ok(());
|
||||
Ok(true)
|
||||
}
|
||||
_ => {
|
||||
e.print_error();
|
||||
Ok(false)
|
||||
}
|
||||
_ => e.print_error(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ impl IoMode {
|
||||
Ok(self)
|
||||
}
|
||||
pub fn get_pipes() -> (Self, Self) {
|
||||
let (rpipe, wpipe) = pipe().unwrap();
|
||||
let (rpipe, wpipe) = nix::unistd::pipe2(OFlag::O_CLOEXEC).unwrap();
|
||||
(
|
||||
Self::Pipe {
|
||||
tgt_fd: STDIN_FILENO,
|
||||
@@ -220,6 +220,12 @@ impl<'e> IoFrame {
|
||||
let tgt_fd = io_mode.tgt_fd();
|
||||
let src_fd = io_mode.src_fd();
|
||||
dup2(src_fd, tgt_fd)?;
|
||||
// Close the original pipe fd after dup2 — it's been duplicated to
|
||||
// tgt_fd and keeping it open prevents SIGPIPE delivery in pipelines.
|
||||
// We replace the IoMode to drop the Arc<OwnedFd>, which closes the fd.
|
||||
if matches!(io_mode, IoMode::Pipe { .. }) {
|
||||
*io_mode = IoMode::Close { tgt_fd };
|
||||
}
|
||||
}
|
||||
Ok(RedirGuard::new(self))
|
||||
}
|
||||
|
||||
@@ -812,7 +812,9 @@ impl FuzzySelector {
|
||||
}
|
||||
|
||||
fn candidate_height(&self, idx: usize) -> usize {
|
||||
self.filtered.get(idx)
|
||||
self
|
||||
.filtered
|
||||
.get(idx)
|
||||
.map(|c| c.content.trim_end().lines().count().max(1))
|
||||
.unwrap_or(1)
|
||||
}
|
||||
@@ -930,7 +932,13 @@ impl FuzzySelector {
|
||||
let title = self.title.clone();
|
||||
let title_width = title.len() as u16;
|
||||
let number_candidates = self.number_candidates;
|
||||
let min_pad = self.candidates.len().to_string().len().saturating_add(1).max(6);
|
||||
let min_pad = self
|
||||
.candidates
|
||||
.len()
|
||||
.to_string()
|
||||
.len()
|
||||
.saturating_add(1)
|
||||
.max(6);
|
||||
let max_height = self.max_height;
|
||||
let visible = self.get_window();
|
||||
let mut rows: u16 = 0;
|
||||
@@ -995,10 +1003,22 @@ impl FuzzySelector {
|
||||
if !drew_number {
|
||||
let this_num = i + offset + 1;
|
||||
let right_pad = " ".repeat(min_pad.saturating_sub(this_num.to_string().len()));
|
||||
format!("{} {}\x1b[33m{}\x1b[39m{right_pad}{}\x1b[0m", Self::VERT_LINE, &selector,i + offset + 1, &line)
|
||||
format!(
|
||||
"{} {}\x1b[33m{}\x1b[39m{right_pad}{}\x1b[0m",
|
||||
Self::VERT_LINE,
|
||||
&selector,
|
||||
i + offset + 1,
|
||||
&line
|
||||
)
|
||||
} else {
|
||||
let right_pad = " ".repeat(min_pad);
|
||||
format!("{} {}{}{}\x1b[0m", Self::VERT_LINE, &selector,right_pad, &line)
|
||||
format!(
|
||||
"{} {}{}{}\x1b[0m",
|
||||
Self::VERT_LINE,
|
||||
&selector,
|
||||
right_pad,
|
||||
&line
|
||||
)
|
||||
}
|
||||
} else {
|
||||
format!("{} {}{}\x1b[0m", Self::VERT_LINE, &selector, &line)
|
||||
@@ -1100,7 +1120,9 @@ impl Default for FuzzyCompleter {
|
||||
|
||||
impl Completer for FuzzyCompleter {
|
||||
fn set_prompt_line_context(&mut self, line_width: u16, cursor_col: u16) {
|
||||
self.selector.set_prompt_line_context(line_width, cursor_col);
|
||||
self
|
||||
.selector
|
||||
.set_prompt_line_context(line_width, cursor_col);
|
||||
}
|
||||
fn reset_stay_active(&mut self) {
|
||||
self.selector.reset_stay_active();
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
use std::{
|
||||
cmp::Ordering, collections::HashSet, env, fmt::{Display, Write}, fs::{self, OpenOptions}, io::Write as IoWrite, path::{Path, PathBuf}, str::FromStr, time::{Duration, SystemTime, UNIX_EPOCH}
|
||||
cmp::Ordering,
|
||||
collections::HashSet,
|
||||
env,
|
||||
fmt::{Display, Write},
|
||||
fs::{self, OpenOptions},
|
||||
io::Write as IoWrite,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
libsh::error::{ShErr, ShErrKind, ShResult},
|
||||
readline::{complete::FuzzySelector, linebuf::LineBuf},
|
||||
state::read_meta,
|
||||
};
|
||||
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
@@ -28,16 +37,13 @@ impl SearchConstraint {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HistEntry {
|
||||
id: u32,
|
||||
runtime: Duration,
|
||||
timestamp: SystemTime,
|
||||
command: String,
|
||||
new: bool,
|
||||
}
|
||||
|
||||
impl HistEntry {
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
pub fn timestamp(&self) -> &SystemTime {
|
||||
&self.timestamp
|
||||
}
|
||||
@@ -73,24 +79,25 @@ impl FromStr for HistEntry {
|
||||
return err;
|
||||
};
|
||||
//248972349;148;echo foo; echo bar
|
||||
let Some((timestamp, id_and_command)) = cleaned.split_once(';') else {
|
||||
let Some((timestamp, runtime_and_cmd)) = cleaned.split_once(';') else {
|
||||
return err;
|
||||
};
|
||||
//("248972349","148;echo foo; echo bar")
|
||||
let Some((id, command)) = id_and_command.split_once(';') else {
|
||||
let Some((runtime, command)) = runtime_and_cmd.split_once(';') else {
|
||||
return err;
|
||||
};
|
||||
//("148","echo foo; echo bar")
|
||||
let Ok(ts_seconds) = timestamp.parse::<u64>() else {
|
||||
return err;
|
||||
};
|
||||
let Ok(id) = id.parse::<u32>() else {
|
||||
let Ok(runtime) = runtime.parse::<u64>() else {
|
||||
return err;
|
||||
};
|
||||
let runtime = Duration::from_secs(runtime);
|
||||
let timestamp = UNIX_EPOCH + Duration::from_secs(ts_seconds);
|
||||
let command = command.to_string();
|
||||
Ok(Self {
|
||||
id,
|
||||
runtime,
|
||||
timestamp,
|
||||
command,
|
||||
new: false,
|
||||
@@ -103,13 +110,14 @@ impl Display for HistEntry {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let command = self.with_escaped_newlines();
|
||||
let HistEntry {
|
||||
id,
|
||||
runtime,
|
||||
timestamp,
|
||||
command: _,
|
||||
new: _,
|
||||
} = self;
|
||||
let timestamp = timestamp.duration_since(UNIX_EPOCH).unwrap().as_secs();
|
||||
writeln!(f, ": {timestamp};{id};{command}")
|
||||
let runtime = runtime.as_secs();
|
||||
writeln!(f, ": {timestamp};{runtime};{command}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +231,11 @@ impl History {
|
||||
}
|
||||
let search_mask = dedupe_entries(&entries);
|
||||
let cursor = search_mask.len();
|
||||
let max_size = if max_hist < 0 { None } else { Some(max_hist as u32) };
|
||||
let max_size = if max_hist < 0 {
|
||||
None
|
||||
} else {
|
||||
Some(max_hist as u32)
|
||||
};
|
||||
Ok(Self {
|
||||
path,
|
||||
entries,
|
||||
@@ -245,7 +257,10 @@ impl History {
|
||||
Some(self.search_mask[0].command().to_string())
|
||||
} else {
|
||||
self.fuzzy_finder.set_query(initial.to_string());
|
||||
let raw_entries = self.search_mask.clone().into_iter()
|
||||
let raw_entries = self
|
||||
.search_mask
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|ent| ent.command().to_string());
|
||||
self.fuzzy_finder.activate(raw_entries.collect());
|
||||
None
|
||||
@@ -307,7 +322,9 @@ impl History {
|
||||
|
||||
pub fn resolve_hist_token(&self, token: &str) -> Option<String> {
|
||||
let token = token.strip_prefix('!').unwrap_or(token).to_string();
|
||||
if let Ok(num) = token.parse::<i32>() && num != 0 {
|
||||
if let Ok(num) = token.parse::<i32>()
|
||||
&& num != 0
|
||||
{
|
||||
match num.cmp(&0) {
|
||||
Ordering::Less => {
|
||||
if num.unsigned_abs() > self.entries.len() as u32 {
|
||||
@@ -315,14 +332,13 @@ impl History {
|
||||
}
|
||||
|
||||
let rev_idx = self.entries.len() - num.unsigned_abs() as usize;
|
||||
self.entries.get(rev_idx)
|
||||
.map(|e| e.command().to_string())
|
||||
self.entries.get(rev_idx).map(|e| e.command().to_string())
|
||||
}
|
||||
Ordering::Greater => {
|
||||
self.entries.get(num as usize)
|
||||
.map(|e| e.command().to_string())
|
||||
}
|
||||
_ => unreachable!()
|
||||
Ordering::Greater => self
|
||||
.entries
|
||||
.get(num as usize)
|
||||
.map(|e| e.command().to_string()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
let mut rev_search = self.entries.iter();
|
||||
@@ -332,13 +348,6 @@ impl History {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_new_id(&self) -> u32 {
|
||||
let Some(ent) = self.entries.last() else {
|
||||
return 0;
|
||||
};
|
||||
ent.id + 1
|
||||
}
|
||||
|
||||
pub fn ignore_dups(&mut self, yn: bool) {
|
||||
self.ignore_dups = yn
|
||||
}
|
||||
@@ -401,12 +410,12 @@ impl History {
|
||||
|
||||
pub fn push(&mut self, command: String) {
|
||||
let timestamp = SystemTime::now();
|
||||
let id = self.get_new_id();
|
||||
let runtime = read_meta(|m| m.get_time()).unwrap_or_default();
|
||||
if self.ignore_dups && self.is_dup(&command) {
|
||||
return;
|
||||
}
|
||||
self.entries.push(HistEntry {
|
||||
id,
|
||||
runtime,
|
||||
timestamp,
|
||||
command,
|
||||
new: true,
|
||||
|
||||
@@ -19,7 +19,10 @@ use crate::{
|
||||
},
|
||||
prelude::*,
|
||||
readline::{
|
||||
history::History, markers, register::{RegisterContent, write_register}, term::RawModeGuard
|
||||
history::History,
|
||||
markers,
|
||||
register::{RegisterContent, write_register},
|
||||
term::RawModeGuard,
|
||||
},
|
||||
state::{VarFlags, VarKind, read_shopts, write_meta, write_vars},
|
||||
};
|
||||
@@ -3335,7 +3338,8 @@ impl LineBuf {
|
||||
|
||||
while let Some((i, gr)) = graphemes.next() {
|
||||
match gr {
|
||||
"\\" => {
|
||||
"\\" | "$" => {
|
||||
// skip on dollars because '$!' is a shell parameter
|
||||
graphemes.next();
|
||||
}
|
||||
"'" => qt_state.toggle_single(),
|
||||
@@ -3362,7 +3366,9 @@ impl LineBuf {
|
||||
Some((j, gr)) if !is_whitespace(gr) => {
|
||||
let mut end = j + gr.len();
|
||||
while let Some((k, gr2)) = graphemes.next() {
|
||||
if is_whitespace(gr2) { break; }
|
||||
if is_whitespace(gr2) {
|
||||
break;
|
||||
}
|
||||
end = k + gr2.len();
|
||||
}
|
||||
let token = &self.buffer[j..end];
|
||||
|
||||
@@ -16,7 +16,8 @@ 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, VarFlags, VarKind, read_logic, read_shopts, with_vars, write_meta, write_vars
|
||||
AutoCmdKind, ShellParam, VarFlags, VarKind, read_logic, read_shopts, with_vars, write_meta,
|
||||
write_vars,
|
||||
};
|
||||
use crate::{
|
||||
libsh::error::ShResult,
|
||||
@@ -413,7 +414,9 @@ impl ShedVi {
|
||||
|
||||
self.editor.set_buffer(cmd.to_string());
|
||||
self.editor.move_cursor_to_end();
|
||||
self.history.update_pending_cmd((self.editor.as_str(), self.editor.cursor.get()));
|
||||
self
|
||||
.history
|
||||
.update_pending_cmd((self.editor.as_str(), self.editor.cursor.get()));
|
||||
self.editor.set_hint(None);
|
||||
self.history.fuzzy_finder.clear(&mut self.writer)?;
|
||||
self.history.fuzzy_finder.reset();
|
||||
@@ -422,7 +425,14 @@ impl ShedVi {
|
||||
post_cmds.exec_with(&cmd);
|
||||
});
|
||||
|
||||
write_vars(|v| v.set_var("SHED_VI_MODE", VarKind::Str(self.mode.report_mode().to_string()), VarFlags::NONE)).ok();
|
||||
write_vars(|v| {
|
||||
v.set_var(
|
||||
"SHED_VI_MODE",
|
||||
VarKind::Str(self.mode.report_mode().to_string()),
|
||||
VarFlags::NONE,
|
||||
)
|
||||
})
|
||||
.ok();
|
||||
self.prompt.refresh();
|
||||
self.needs_redraw = true;
|
||||
continue;
|
||||
@@ -433,7 +443,14 @@ impl ShedVi {
|
||||
|
||||
self.editor.set_hint(None);
|
||||
self.history.fuzzy_finder.clear(&mut self.writer)?;
|
||||
write_vars(|v| v.set_var("SHED_VI_MODE", VarKind::Str(self.mode.report_mode().to_string()), VarFlags::NONE)).ok();
|
||||
write_vars(|v| {
|
||||
v.set_var(
|
||||
"SHED_VI_MODE",
|
||||
VarKind::Str(self.mode.report_mode().to_string()),
|
||||
VarFlags::NONE,
|
||||
)
|
||||
})
|
||||
.ok();
|
||||
self.prompt.refresh();
|
||||
self.needs_redraw = true;
|
||||
continue;
|
||||
@@ -481,7 +498,14 @@ impl ShedVi {
|
||||
let hint = self.history.get_hint();
|
||||
self.editor.set_hint(hint);
|
||||
self.completer.clear(&mut self.writer)?;
|
||||
write_vars(|v| v.set_var("SHED_VI_MODE", VarKind::Str(self.mode.report_mode().to_string()), VarFlags::NONE)).ok();
|
||||
write_vars(|v| {
|
||||
v.set_var(
|
||||
"SHED_VI_MODE",
|
||||
VarKind::Str(self.mode.report_mode().to_string()),
|
||||
VarFlags::NONE,
|
||||
)
|
||||
})
|
||||
.ok();
|
||||
self.prompt.refresh();
|
||||
self.completer.reset();
|
||||
continue;
|
||||
@@ -532,7 +556,14 @@ impl ShedVi {
|
||||
}
|
||||
}
|
||||
if !self.completer.is_active() && !self.history.fuzzy_finder.is_active() {
|
||||
write_vars(|v| v.set_var("SHED_VI_MODE", VarKind::Str(self.mode.report_mode().to_string()), VarFlags::NONE)).ok();
|
||||
write_vars(|v| {
|
||||
v.set_var(
|
||||
"SHED_VI_MODE",
|
||||
VarKind::Str(self.mode.report_mode().to_string()),
|
||||
VarFlags::NONE,
|
||||
)
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
// Redraw if we processed any input
|
||||
@@ -546,7 +577,10 @@ impl ShedVi {
|
||||
|
||||
pub fn handle_key(&mut self, key: KeyEvent) -> ShResult<Option<ReadlineEvent>> {
|
||||
if self.should_accept_hint(&key) {
|
||||
log::debug!("Accepting hint on key {key:?} in mode {:?}", self.mode.report_mode());
|
||||
log::debug!(
|
||||
"Accepting hint on key {key:?} in mode {:?}",
|
||||
self.mode.report_mode()
|
||||
);
|
||||
self.editor.accept_hint();
|
||||
if !self.history.at_pending() {
|
||||
self.history.reset_to_pending();
|
||||
@@ -605,8 +639,6 @@ impl ShedVi {
|
||||
.update_pending_cmd((self.editor.as_str(), self.editor.cursor.get()));
|
||||
let hint = self.history.get_hint();
|
||||
self.editor.set_hint(hint);
|
||||
|
||||
|
||||
}
|
||||
Ok(None) => {
|
||||
let post_cmds = read_logic(|l| l.get_autocmds(AutoCmdKind::OnCompletionStart));
|
||||
@@ -615,7 +647,14 @@ impl ShedVi {
|
||||
|
||||
self.writer.send_bell().ok();
|
||||
if self.completer.is_active() {
|
||||
write_vars(|v| v.set_var("SHED_VI_MODE", VarKind::Str("COMPLETE".to_string()), VarFlags::NONE)).ok();
|
||||
write_vars(|v| {
|
||||
v.set_var(
|
||||
"SHED_VI_MODE",
|
||||
VarKind::Str("COMPLETE".to_string()),
|
||||
VarFlags::NONE,
|
||||
)
|
||||
})
|
||||
.ok();
|
||||
self.prompt.refresh();
|
||||
self.needs_redraw = true;
|
||||
self.editor.set_hint(None);
|
||||
@@ -636,7 +675,9 @@ impl ShedVi {
|
||||
|
||||
self.editor.set_buffer(entry);
|
||||
self.editor.move_cursor_to_end();
|
||||
self.history.update_pending_cmd((self.editor.as_str(), self.editor.cursor.get()));
|
||||
self
|
||||
.history
|
||||
.update_pending_cmd((self.editor.as_str(), self.editor.cursor.get()));
|
||||
self.editor.set_hint(None);
|
||||
}
|
||||
None => {
|
||||
@@ -645,7 +686,14 @@ impl ShedVi {
|
||||
|
||||
self.writer.send_bell().ok();
|
||||
if self.history.fuzzy_finder.is_active() {
|
||||
write_vars(|v| v.set_var("SHED_VI_MODE", VarKind::Str("SEARCH".to_string()), VarFlags::NONE)).ok();
|
||||
write_vars(|v| {
|
||||
v.set_var(
|
||||
"SHED_VI_MODE",
|
||||
VarKind::Str("SEARCH".to_string()),
|
||||
VarFlags::NONE,
|
||||
)
|
||||
})
|
||||
.ok();
|
||||
self.prompt.refresh();
|
||||
self.needs_redraw = true;
|
||||
self.editor.set_hint(None);
|
||||
@@ -695,12 +743,6 @@ impl ShedVi {
|
||||
self.print_line(true)?;
|
||||
self.writer.flush_write("\n")?;
|
||||
let buf = self.editor.take_buf();
|
||||
if read_shopts(|s| s.core.auto_hist) && !buf.is_empty() {
|
||||
self.history.push(buf.clone());
|
||||
if let Err(e) = self.history.save() {
|
||||
eprintln!("Failed to save history: {e}");
|
||||
}
|
||||
}
|
||||
self.history.reset();
|
||||
return Ok(Some(ReadlineEvent::Line(buf)));
|
||||
}
|
||||
@@ -942,7 +984,10 @@ impl ShedVi {
|
||||
.set_prompt_line_context(preceding_width, new_layout.cursor.col);
|
||||
self.completer.draw(&mut self.writer)?;
|
||||
|
||||
self.history.fuzzy_finder.set_prompt_line_context(preceding_width, new_layout.cursor.col);
|
||||
self
|
||||
.history
|
||||
.fuzzy_finder
|
||||
.set_prompt_line_context(preceding_width, new_layout.cursor.col);
|
||||
self.history.fuzzy_finder.draw(&mut self.writer)?;
|
||||
|
||||
self.old_layout = Some(new_layout);
|
||||
|
||||
@@ -54,15 +54,13 @@ impl ViMode for ViInsert {
|
||||
.set_motion(MotionCmd(1, Motion::ForwardChar));
|
||||
self.register_and_return()
|
||||
}
|
||||
E(K::ExMode, _) => {
|
||||
Some(ViCmd {
|
||||
E(K::ExMode, _) => Some(ViCmd {
|
||||
register: Default::default(),
|
||||
verb: Some(VerbCmd(1, Verb::ExMode)),
|
||||
motion: None,
|
||||
raw_seq: String::new(),
|
||||
flags: Default::default(),
|
||||
})
|
||||
}
|
||||
}),
|
||||
E(K::Char('W'), M::CTRL) => {
|
||||
self.pending_cmd.set_verb(VerbCmd(1, Verb::Delete));
|
||||
self.pending_cmd.set_motion(MotionCmd(
|
||||
|
||||
@@ -41,15 +41,13 @@ impl ViMode for ViReplace {
|
||||
.set_motion(MotionCmd(1, Motion::ForwardChar));
|
||||
self.register_and_return()
|
||||
}
|
||||
E(K::ExMode, _) => {
|
||||
Some(ViCmd {
|
||||
E(K::ExMode, _) => Some(ViCmd {
|
||||
register: Default::default(),
|
||||
verb: Some(VerbCmd(1, Verb::ExMode)),
|
||||
motion: None,
|
||||
raw_seq: String::new(),
|
||||
flags: Default::default(),
|
||||
})
|
||||
}
|
||||
}),
|
||||
E(K::Char('W'), M::CTRL) => {
|
||||
self.pending_cmd.set_verb(VerbCmd(1, Verb::Delete));
|
||||
self.pending_cmd.set_motion(MotionCmd(
|
||||
|
||||
Reference in New Issue
Block a user