Prompt now only redraws on completed jobs and new commands

Tab completion now finds env var names as well as internally set names
This commit is contained in:
2026-02-25 16:48:49 -05:00
parent df5f1d5778
commit 2d0d919e66
5 changed files with 21 additions and 13 deletions

View File

@@ -34,7 +34,7 @@ use crate::prelude::*;
use crate::prompt::get_prompt; use crate::prompt::get_prompt;
use crate::prompt::readline::term::{LineWriter, RawModeGuard, raw_mode}; use crate::prompt::readline::term::{LineWriter, RawModeGuard, raw_mode};
use crate::prompt::readline::{Prompt, ReadlineEvent, ShedVi}; use crate::prompt::readline::{Prompt, ReadlineEvent, ShedVi};
use crate::signal::{GOT_SIGWINCH, QUIT_CODE, check_signals, sig_setup, signals_pending}; use crate::signal::{GOT_SIGWINCH, JOB_DONE, QUIT_CODE, check_signals, sig_setup, signals_pending};
use crate::state::{read_logic, source_rc, write_jobs, write_meta}; use crate::state::{read_logic, source_rc, write_jobs, write_meta};
use clap::Parser; use clap::Parser;
use state::{read_vars, write_vars}; use state::{read_vars, write_vars};
@@ -186,7 +186,7 @@ fn shed_interactive() -> ShResult<()> {
match e.kind() { match e.kind() {
ShErrKind::ClearReadline => { ShErrKind::ClearReadline => {
// Ctrl+C - clear current input and show new prompt // Ctrl+C - clear current input and show new prompt
readline.reset(Prompt::new()); readline.reset();
} }
ShErrKind::CleanExit(code) => { ShErrKind::CleanExit(code) => {
QUIT_CODE.store(*code, Ordering::SeqCst); QUIT_CODE.store(*code, Ordering::SeqCst);
@@ -200,9 +200,14 @@ fn shed_interactive() -> ShResult<()> {
if GOT_SIGWINCH.swap(false, Ordering::SeqCst) { if GOT_SIGWINCH.swap(false, Ordering::SeqCst) {
log::info!("Window size change detected, updating readline dimensions"); log::info!("Window size change detected, updating readline dimensions");
readline.writer.update_t_cols(); readline.writer.update_t_cols();
readline.prompt_mut().refresh()?;
}
if JOB_DONE.swap(false, Ordering::SeqCst) {
// update the prompt so any job count escape sequences update dynamically
readline.prompt_mut().refresh()?;
} }
readline.prompt_mut().refresh();
readline.print_line(false)?; readline.print_line(false)?;
// Poll for stdin input // Poll for stdin input
@@ -265,7 +270,7 @@ fn shed_interactive() -> ShResult<()> {
readline.writer.flush_write("\n")?; readline.writer.flush_write("\n")?;
// Reset for next command with fresh prompt // Reset for next command with fresh prompt
readline.reset(Prompt::new()); readline.reset();
let real_end = start.elapsed(); let real_end = start.elapsed();
log::info!("Total round trip time: {:.2?}", real_end); log::info!("Total round trip time: {:.2?}", real_end);
} }

View File

@@ -256,8 +256,8 @@ impl ShedVi {
/// Reset readline state for a new prompt /// Reset readline state for a new prompt
pub fn reset(&mut self, prompt: Prompt) { pub fn reset(&mut self) {
self.prompt = prompt; self.prompt = Prompt::new();
self.editor = Default::default(); self.editor = Default::default();
self.mode = Box::new(ViInsert::new()); self.mode = Box::new(ViInsert::new());
self.old_layout = None; self.old_layout = None;
@@ -516,9 +516,7 @@ impl ShedVi {
let line = self.line_text(); let line = self.line_text();
let new_layout = self.get_layout(&line); let new_layout = self.get_layout(&line);
let pending_seq = self.mode.pending_seq(); let pending_seq = self.mode.pending_seq();
let mut prompt_string_right = env::var("PSR") let mut prompt_string_right = self.prompt.psr_expanded.clone();
.map(|psr| expand_prompt(&psr).unwrap())
.ok();
if prompt_string_right.as_ref().is_some_and(|psr| psr.lines().count() > 1) { if prompt_string_right.as_ref().is_some_and(|psr| psr.lines().count() > 1) {
log::warn!("PSR has multiple lines, truncating to one line"); log::warn!("PSR has multiple lines, truncating to one line");

View File

@@ -346,7 +346,6 @@ impl ViNormal {
} }
} }
/// End the parse and clear the pending sequence /// End the parse and clear the pending sequence
#[track_caller]
pub fn quit_parse(&mut self) -> Option<ViCmd> { pub fn quit_parse(&mut self) -> Option<ViCmd> {
self.clear_cmd(); self.clear_cmd();
None None
@@ -1137,7 +1136,6 @@ impl ViVisual {
} }
} }
/// End the parse and clear the pending sequence /// End the parse and clear the pending sequence
#[track_caller]
pub fn quit_parse(&mut self) -> Option<ViCmd> { pub fn quit_parse(&mut self) -> Option<ViCmd> {
self.clear_cmd(); self.clear_cmd();
None None

View File

@@ -16,6 +16,7 @@ static SIGNALS: AtomicU64 = AtomicU64::new(0);
pub static REAPING_ENABLED: AtomicBool = AtomicBool::new(true); pub static REAPING_ENABLED: AtomicBool = AtomicBool::new(true);
pub static SHOULD_QUIT: AtomicBool = AtomicBool::new(false); pub static SHOULD_QUIT: AtomicBool = AtomicBool::new(false);
pub static GOT_SIGWINCH: AtomicBool = AtomicBool::new(false); pub static GOT_SIGWINCH: AtomicBool = AtomicBool::new(false);
pub static JOB_DONE: AtomicBool = AtomicBool::new(false);
pub static QUIT_CODE: AtomicI32 = AtomicI32::new(0); pub static QUIT_CODE: AtomicI32 = AtomicI32::new(0);
const MISC_SIGNALS: [Signal; 22] = [ const MISC_SIGNALS: [Signal; 22] = [
@@ -285,6 +286,7 @@ pub fn child_exited(pid: Pid, status: WtStat) -> ShResult<()> {
if is_fg { if is_fg {
take_term()?; take_term()?;
} else { } else {
JOB_DONE.store(true, Ordering::SeqCst);
let job_order = read_jobs(|j| j.order().to_vec()); let job_order = read_jobs(|j| j.order().to_vec());
let result = read_jobs(|j| j.query(JobID::Pgid(pgid)).cloned()); let result = read_jobs(|j| j.query(JobID::Pgid(pgid)).cloned());
if let Some(job) = result { if let Some(job) = result {

View File

@@ -1,5 +1,5 @@
use std::{ use std::{
cell::RefCell, collections::{HashMap, HashSet, VecDeque}, fmt::Display, ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Deref}, os::unix::fs::PermissionsExt, str::FromStr, time::Duration cell::RefCell, collections::{HashMap, HashSet, VecDeque, hash_map::Entry}, fmt::Display, ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Deref}, os::unix::fs::PermissionsExt, str::FromStr, time::Duration
}; };
use nix::unistd::{User, gethostname, getppid}; use nix::unistd::{User, gethostname, getppid};
@@ -183,6 +183,12 @@ impl ScopeStack {
flat_vars.insert(var_name.clone(), var.clone()); flat_vars.insert(var_name.clone(), var.clone());
} }
} }
for var in env::vars() {
if let Entry::Vacant(e) = flat_vars.entry(var.0) {
e.insert(Var::new(VarKind::Str(var.1), VarFlags::EXPORT));
}
}
flat_vars flat_vars
} }
pub fn set_var(&mut self, var_name: &str, val: &str, flags: VarFlags) -> ShResult<()> { pub fn set_var(&mut self, var_name: &str, val: &str, flags: VarFlags) -> ShResult<()> {
@@ -953,7 +959,6 @@ pub fn get_status() -> i32 {
.parse::<i32>() .parse::<i32>()
.unwrap() .unwrap()
} }
#[track_caller]
pub fn set_status(code: i32) { pub fn set_status(code: i32) {
write_vars(|v| v.set_param(ShellParam::Status, &code.to_string())) write_vars(|v| v.set_param(ShellParam::Status, &code.to_string()))
} }