Add screensaver idle command support, autocd directory completion, and unused import cleanup
This commit is contained in:
34
src/main.rs
34
src/main.rs
@@ -31,6 +31,7 @@ use nix::unistd::read;
|
|||||||
use crate::builtin::keymap::KeyMapMatch;
|
use crate::builtin::keymap::KeyMapMatch;
|
||||||
use crate::builtin::trap::TrapTarget;
|
use crate::builtin::trap::TrapTarget;
|
||||||
use crate::libsh::error::{self, ShErr, ShErrKind, ShResult};
|
use crate::libsh::error::{self, ShErr, ShErrKind, ShResult};
|
||||||
|
use crate::libsh::guards::scope_guard;
|
||||||
use crate::libsh::sys::TTY_FILENO;
|
use crate::libsh::sys::TTY_FILENO;
|
||||||
use crate::libsh::utils::AutoCmdVecUtils;
|
use crate::libsh::utils::AutoCmdVecUtils;
|
||||||
use crate::parse::execute::{exec_dash_c, exec_input};
|
use crate::parse::execute::{exec_dash_c, exec_input};
|
||||||
@@ -39,7 +40,7 @@ use crate::procio::borrow_fd;
|
|||||||
use crate::readline::term::{LineWriter, RawModeGuard, raw_mode};
|
use crate::readline::term::{LineWriter, RawModeGuard, raw_mode};
|
||||||
use crate::readline::{Prompt, ReadlineEvent, ShedVi};
|
use crate::readline::{Prompt, ReadlineEvent, ShedVi};
|
||||||
use crate::signal::{GOT_SIGWINCH, JOB_DONE, 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::{AutoCmdKind, read_logic, read_shopts, source_rc, write_jobs, write_meta};
|
use crate::state::{AutoCmdKind, read_logic, read_shopts, source_rc, write_jobs, write_meta, write_shopts};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use state::{read_vars, write_vars};
|
use state::{read_vars, write_vars};
|
||||||
|
|
||||||
@@ -264,14 +265,38 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
|
|||||||
PollFlags::POLLIN,
|
PollFlags::POLLIN,
|
||||||
)];
|
)];
|
||||||
|
|
||||||
|
let mut exec_if_timeout = None;
|
||||||
|
|
||||||
let timeout = if readline.pending_keymap.is_empty() {
|
let timeout = if readline.pending_keymap.is_empty() {
|
||||||
PollTimeout::MAX
|
let screensaver_cmd = read_shopts(|o| o.prompt.screensaver_cmd.clone());
|
||||||
|
let screensaver_idle_time = read_shopts(|o| o.prompt.screensaver_idle_time);
|
||||||
|
if screensaver_idle_time > 0 && !screensaver_cmd.is_empty() {
|
||||||
|
exec_if_timeout = Some(screensaver_cmd);
|
||||||
|
PollTimeout::from((screensaver_idle_time * 1000) as u16)
|
||||||
|
} else {
|
||||||
|
PollTimeout::MAX
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
PollTimeout::from(1000u16)
|
PollTimeout::from(1000u16)
|
||||||
};
|
};
|
||||||
|
|
||||||
match poll(&mut fds, timeout) {
|
match poll(&mut fds, timeout) {
|
||||||
Ok(_) => {}
|
Ok(0) => {
|
||||||
|
// We timed out.
|
||||||
|
if let Some(cmd) = exec_if_timeout {
|
||||||
|
let prepared = ReadlineEvent::Line(cmd);
|
||||||
|
let saved_hist_opt = read_shopts(|o| o.core.auto_hist);
|
||||||
|
let _guard = scopeguard::guard(saved_hist_opt, |opt| {
|
||||||
|
write_shopts(|o| o.core.auto_hist = opt);
|
||||||
|
});
|
||||||
|
write_shopts(|o| o.core.auto_hist = false); // don't save screensaver command to history
|
||||||
|
|
||||||
|
match handle_readline_event(&mut readline, Ok(prepared))? {
|
||||||
|
true => return Ok(()),
|
||||||
|
false => continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(Errno::EINTR) => {
|
Err(Errno::EINTR) => {
|
||||||
// Interrupted by signal, loop back to handle it
|
// Interrupted by signal, loop back to handle it
|
||||||
continue;
|
continue;
|
||||||
@@ -280,6 +305,7 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
|
|||||||
eprintln!("poll error: {e}");
|
eprintln!("poll error: {e}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Ok(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timeout — resolve pending keymap ambiguity
|
// Timeout — resolve pending keymap ambiguity
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
fmt::{Debug, Write},
|
fmt::{Debug, Write},
|
||||||
path::PathBuf,
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ use crate::{
|
|||||||
term::{LineWriter, TermWriter, calc_str_width, get_win_size},
|
term::{LineWriter, TermWriter, calc_str_width, get_win_size},
|
||||||
vimode::{ViInsert, ViMode},
|
vimode::{ViInsert, ViMode},
|
||||||
},
|
},
|
||||||
state::{VarFlags, VarKind, read_jobs, read_logic, read_meta, read_vars, write_vars},
|
state::{VarFlags, VarKind, read_jobs, read_logic, read_meta, read_shopts, read_vars, write_vars},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn complete_signals(start: &str) -> Vec<String> {
|
pub fn complete_signals(start: &str) -> Vec<String> {
|
||||||
@@ -173,6 +173,11 @@ fn complete_commands(start: &str) -> Vec<String> {
|
|||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if read_shopts(|o| o.core.autocd) {
|
||||||
|
let dirs = complete_dirs(start);
|
||||||
|
candidates.extend(dirs);
|
||||||
|
}
|
||||||
|
|
||||||
candidates.sort();
|
candidates.sort();
|
||||||
candidates
|
candidates
|
||||||
}
|
}
|
||||||
|
|||||||
28
src/shopt.rs
28
src/shopt.rs
@@ -360,6 +360,8 @@ pub struct ShOptPrompt {
|
|||||||
pub linebreak_on_incomplete: bool,
|
pub linebreak_on_incomplete: bool,
|
||||||
pub leader: String,
|
pub leader: String,
|
||||||
pub line_numbers: bool,
|
pub line_numbers: bool,
|
||||||
|
pub screensaver_cmd: String,
|
||||||
|
pub screensaver_idle_time: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShOptPrompt {
|
impl ShOptPrompt {
|
||||||
@@ -431,6 +433,18 @@ impl ShOptPrompt {
|
|||||||
};
|
};
|
||||||
self.line_numbers = val;
|
self.line_numbers = val;
|
||||||
}
|
}
|
||||||
|
"screensaver_cmd" => {
|
||||||
|
self.screensaver_cmd = val.to_string();
|
||||||
|
}
|
||||||
|
"screensaver_idle_time" => {
|
||||||
|
let Ok(val) = val.parse::<usize>() else {
|
||||||
|
return Err(ShErr::simple(
|
||||||
|
ShErrKind::SyntaxErr,
|
||||||
|
"shopt: expected a positive integer for screensaver_idle_time value",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
self.screensaver_idle_time = val;
|
||||||
|
}
|
||||||
"custom" => {
|
"custom" => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
@@ -496,6 +510,16 @@ impl ShOptPrompt {
|
|||||||
output.push_str(&format!("{}", self.line_numbers));
|
output.push_str(&format!("{}", self.line_numbers));
|
||||||
Ok(Some(output))
|
Ok(Some(output))
|
||||||
}
|
}
|
||||||
|
"screensaver_cmd" => {
|
||||||
|
let mut output = String::from("Command to execute as a screensaver after idle timeout\n");
|
||||||
|
output.push_str(&self.screensaver_cmd);
|
||||||
|
Ok(Some(output))
|
||||||
|
}
|
||||||
|
"screensaver_idle_time" => {
|
||||||
|
let mut output = String::from("Idle time in seconds before running screensaver_cmd (0 = disabled)\n");
|
||||||
|
output.push_str(&format!("{}", self.screensaver_idle_time));
|
||||||
|
Ok(Some(output))
|
||||||
|
}
|
||||||
_ => Err(ShErr::simple(
|
_ => Err(ShErr::simple(
|
||||||
ShErrKind::SyntaxErr,
|
ShErrKind::SyntaxErr,
|
||||||
format!("shopt: Unexpected 'prompt' option '{query}'"),
|
format!("shopt: Unexpected 'prompt' option '{query}'"),
|
||||||
@@ -519,6 +543,8 @@ impl Display for ShOptPrompt {
|
|||||||
));
|
));
|
||||||
output.push(format!("leader = {}", self.leader));
|
output.push(format!("leader = {}", self.leader));
|
||||||
output.push(format!("line_numbers = {}", self.line_numbers));
|
output.push(format!("line_numbers = {}", self.line_numbers));
|
||||||
|
output.push(format!("screensaver_cmd = {}", self.screensaver_cmd));
|
||||||
|
output.push(format!("screensaver_idle_time = {}", self.screensaver_idle_time));
|
||||||
|
|
||||||
let final_output = output.join("\n");
|
let final_output = output.join("\n");
|
||||||
|
|
||||||
@@ -537,6 +563,8 @@ impl Default for ShOptPrompt {
|
|||||||
linebreak_on_incomplete: true,
|
linebreak_on_incomplete: true,
|
||||||
leader: "\\".to_string(),
|
leader: "\\".to_string(),
|
||||||
line_numbers: true,
|
line_numbers: true,
|
||||||
|
screensaver_cmd: String::new(),
|
||||||
|
screensaver_idle_time: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user