added autocmd hooks for screensaver commands
added a landing page for the help command
This commit is contained in:
@@ -145,7 +145,20 @@ behavior without modifying the shell itself.
|
|||||||
Special variables:
|
Special variables:
|
||||||
`$_COMP_CANDIDATE` the selected completion candidate
|
`$_COMP_CANDIDATE` the selected completion candidate
|
||||||
|
|
||||||
2.8 Exit Event *autocmd-exit-event*
|
2.8 Screensaver Events *autocmd-screensaver-events*
|
||||||
|
|
||||||
|
`on-screensaver-exec` *autocmd-on-screensaver-exec*
|
||||||
|
|
||||||
|
Fires when the screensaver activates after the idle timeout.
|
||||||
|
The screensaver command (see `shopt prompt.screensaver_cmd`) is
|
||||||
|
available for pattern matching.
|
||||||
|
|
||||||
|
`on-screensaver-return` *autocmd-on-screensaver-return*
|
||||||
|
|
||||||
|
Fires when the shell returns from the screensaver command.
|
||||||
|
The screensaver command is available for pattern matching.
|
||||||
|
|
||||||
|
2.9 Exit Event *autocmd-exit-event*
|
||||||
|
|
||||||
`on-exit` *autocmd-on-exit*
|
`on-exit` *autocmd-on-exit*
|
||||||
|
|
||||||
|
|||||||
44
doc/help.txt
Normal file
44
doc/help.txt
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
*help*
|
||||||
|
|
||||||
|
#SHED HELP#
|
||||||
|
|
||||||
|
Shed is an experimental UNIX command interpreter (shell) usable as both an interactive login shell and as a shell script command preprocessor. Shed combines the functionality of `bash` with the UX and customizability of `vim`. Shed seeks to improve the interactive shell experience by providing:
|
||||||
|
* Programmable, dynamic prompts
|
||||||
|
* A hackable line editor similar to `zsh`'s `zle`
|
||||||
|
* Custom tab completion
|
||||||
|
* An event hook system
|
||||||
|
* Fuzzy history search/tab completion
|
||||||
|
* And many more features
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
1. Available Topics *help-topics*
|
||||||
|
|
||||||
|
`help arith` Arithmetic expansion: `$(( ))` syntax |arith|
|
||||||
|
`help autocmd` Autocmd hooks for shell events |autocmd|
|
||||||
|
`help ex` Ex mode (colon) commands |ex|
|
||||||
|
`help glob` Pathname expansion and wildcards |glob|
|
||||||
|
`help keybinds` Vi mode keys, motions, text objects |keybinds|
|
||||||
|
`help param` Parameter expansion: `${}` operators |param|
|
||||||
|
`help prompt` Prompt configuration, PS1, PSR, echo -p |prompt|
|
||||||
|
`help redirect` Redirection, pipes, heredocs |redirect|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
2. Navigating Help *help-nav*
|
||||||
|
|
||||||
|
`help {topic}` Open a help page by name. Prefix matches work,
|
||||||
|
so `help key` opens |keybinds|.
|
||||||
|
|
||||||
|
`help {tag}` Jump directly to a tagged section. Tags are the
|
||||||
|
words marked with `*asterisks*` in the help files.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
`help text-objects` jumps to |text-objects|
|
||||||
|
`help prompt-escapes` jumps to |prompt-escapes|
|
||||||
|
`help heredoc` jumps to |heredoc|
|
||||||
|
|
||||||
|
Cross-references like |prompt| are clickable tags. Search for them
|
||||||
|
with `help` followed by the reference name.
|
||||||
|
|
||||||
|
Inside the pager, use `/` to search and `q` to quit.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
@@ -388,7 +388,7 @@ mode on startup is Insert.
|
|||||||
|
|
||||||
When the buffer is taller than the terminal, the editor displays a
|
When the buffer is taller than the terminal, the editor displays a
|
||||||
scrolling viewport. The viewport follows the cursor and respects the
|
scrolling viewport. The viewport follows the cursor and respects the
|
||||||
`scrolloff` option (minimum lines visible above/below the cursor).
|
`line.scroll_offset` shopt (minimum lines visible above/below the cursor).
|
||||||
|
|
||||||
`Ctrl+D` scroll down half a screen
|
`Ctrl+D` scroll down half a screen
|
||||||
`Ctrl+U` scroll up half a screen
|
`Ctrl+U` scroll up half a screen
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ lib.concatLines [
|
|||||||
(lib.concatLines (lib.mapAttrsToList (name: value: "export ${name}=\"${value}\"") cfg.environmentVars))
|
(lib.concatLines (lib.mapAttrsToList (name: value: "export ${name}=\"${value}\"") cfg.environmentVars))
|
||||||
(lib.concatLines (lib.mapAttrsToList (name: value: "alias ${name}=\"${value}\"") cfg.aliases))
|
(lib.concatLines (lib.mapAttrsToList (name: value: "alias ${name}=\"${value}\"") cfg.aliases))
|
||||||
(lib.concatLines [
|
(lib.concatLines [
|
||||||
|
"shopt line.viewport_height=${toString cfg.settings.viewportHeight}"
|
||||||
|
"shopt line.scroll_offset=${toString cfg.settings.scrollOffset}"
|
||||||
|
|
||||||
"shopt core.dotglob=${boolToString cfg.settings.dotGlob}"
|
"shopt core.dotglob=${boolToString cfg.settings.dotGlob}"
|
||||||
"shopt core.autocd=${boolToString cfg.settings.autocd}"
|
"shopt core.autocd=${boolToString cfg.settings.autocd}"
|
||||||
"shopt core.hist_ignore_dupes=${boolToString cfg.settings.historyIgnoresDupes}"
|
"shopt core.hist_ignore_dupes=${boolToString cfg.settings.historyIgnoresDupes}"
|
||||||
|
|||||||
@@ -155,6 +155,18 @@
|
|||||||
description = "Additional completion scripts to source when shed starts (e.g. for custom tools or functions)";
|
description = "Additional completion scripts to source when shed starts (e.g. for custom tools or functions)";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
viewportHeight = {
|
||||||
|
type = lib.types.either lib.types.int lib.types.str;
|
||||||
|
default = "50%";
|
||||||
|
description = "Maximum viewport height for the line editor buffer";
|
||||||
|
};
|
||||||
|
|
||||||
|
scrollOffset = {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = "1";
|
||||||
|
description = "The minimum number of lines to keep visible above and below the cursor when scrolling (i.e. the 'scrolloff' option in vim)";
|
||||||
|
};
|
||||||
|
|
||||||
environmentVars = lib.mkOption {
|
environmentVars = lib.mkOption {
|
||||||
type = lib.types.attrsOf lib.types.str;
|
type = lib.types.attrsOf lib.types.str;
|
||||||
default = {};
|
default = {};
|
||||||
|
|||||||
@@ -8,6 +8,33 @@ use crate::parse::{Node, Redir, RedirType};
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::state::AutoCmd;
|
use crate::state::AutoCmd;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
/// Defines a two-way mapping between an enum and its string representation, implementing both Display and FromStr.
|
||||||
|
macro_rules! two_way_display {
|
||||||
|
($name:ident, $($member:ident <=> $val:expr;)*) => {
|
||||||
|
impl Display for $name {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
$(Self::$member => write!(f, $val),)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for $name {
|
||||||
|
type Err = ShErr;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
$($val => Ok(Self::$member),)*
|
||||||
|
_ => Err(ShErr::simple(
|
||||||
|
ShErrKind::ParseErr,
|
||||||
|
format!("Invalid {} kind: {}",stringify!($name),s),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub trait VecDequeExt<T> {
|
pub trait VecDequeExt<T> {
|
||||||
fn to_vec(self) -> Vec<T>;
|
fn to_vec(self) -> Vec<T>;
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/main.rs
11
src/main.rs
@@ -329,14 +329,21 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> {
|
|||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
// We timed out.
|
// We timed out.
|
||||||
if let Some(cmd) = exec_if_timeout {
|
if let Some(cmd) = exec_if_timeout {
|
||||||
let prepared = ReadlineEvent::Line(cmd);
|
let prepared = ReadlineEvent::Line(cmd.clone());
|
||||||
let saved_hist_opt = read_shopts(|o| o.core.auto_hist);
|
let saved_hist_opt = read_shopts(|o| o.core.auto_hist);
|
||||||
let _guard = scopeguard::guard(saved_hist_opt, |opt| {
|
let _guard = scopeguard::guard(saved_hist_opt, |opt| {
|
||||||
write_shopts(|o| o.core.auto_hist = opt);
|
write_shopts(|o| o.core.auto_hist = opt);
|
||||||
});
|
});
|
||||||
write_shopts(|o| o.core.auto_hist = false); // don't save screensaver command to history
|
write_shopts(|o| o.core.auto_hist = false); // don't save screensaver command to history
|
||||||
|
let pre_cmds = read_logic(|l| l.get_autocmds(AutoCmdKind::OnScreensaverExec));
|
||||||
|
pre_cmds.exec_with(&cmd);
|
||||||
|
|
||||||
match handle_readline_event(&mut readline, Ok(prepared))? {
|
let res = handle_readline_event(&mut readline, Ok(prepared))?;
|
||||||
|
|
||||||
|
let post_cmds = read_logic(|l| l.get_autocmds(AutoCmdKind::OnScreensaverReturn));
|
||||||
|
post_cmds.exec_with(&cmd);
|
||||||
|
|
||||||
|
match res {
|
||||||
true => return Ok(()),
|
true => return Ok(()),
|
||||||
false => continue,
|
false => continue,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -509,6 +509,12 @@ pub enum LoopKind {
|
|||||||
Until,
|
Until,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate::two_way_display!(LoopKind,
|
||||||
|
While <=> "while";
|
||||||
|
Until <=> "until";
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum TestCase {
|
pub enum TestCase {
|
||||||
Unary {
|
Unary {
|
||||||
@@ -638,29 +644,6 @@ impl TestCaseBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for LoopKind {
|
|
||||||
type Err = ShErr;
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
match s {
|
|
||||||
"while" => Ok(Self::While),
|
|
||||||
"until" => Ok(Self::Until),
|
|
||||||
_ => Err(ShErr::simple(
|
|
||||||
ShErrKind::ParseErr,
|
|
||||||
format!("Invalid loop kind: {s}"),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for LoopKind {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
LoopKind::While => write!(f, "while"),
|
|
||||||
LoopKind::Until => write!(f, "until"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum AssignKind {
|
pub enum AssignKind {
|
||||||
Eq,
|
Eq,
|
||||||
|
|||||||
@@ -925,7 +925,7 @@ impl LineBuf {
|
|||||||
}
|
}
|
||||||
Direction::Backward => {
|
Direction::Backward => {
|
||||||
let slice = self.line_to_cursor();
|
let slice = self.line_to_cursor();
|
||||||
for (i, gr) in slice.iter().rev().enumerate().skip(1) {
|
for (i, gr) in slice.iter().rev().enumerate() {
|
||||||
if gr == char {
|
if gr == char {
|
||||||
match dest {
|
match dest {
|
||||||
Dest::On => return -(i as isize) - 1,
|
Dest::On => return -(i as isize) - 1,
|
||||||
|
|||||||
72
src/state.rs
72
src/state.rs
@@ -631,59 +631,31 @@ pub enum AutoCmdKind {
|
|||||||
OnCompletionStart,
|
OnCompletionStart,
|
||||||
OnCompletionCancel,
|
OnCompletionCancel,
|
||||||
OnCompletionSelect,
|
OnCompletionSelect,
|
||||||
|
OnScreensaverExec,
|
||||||
|
OnScreensaverReturn,
|
||||||
OnExit,
|
OnExit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for AutoCmdKind {
|
crate::two_way_display!(AutoCmdKind,
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
PreCmd <=> "pre-cmd";
|
||||||
match self {
|
PostCmd <=> "post-cmd";
|
||||||
Self::PreCmd => write!(f, "pre-cmd"),
|
PreChangeDir <=> "pre-change-dir";
|
||||||
Self::PostCmd => write!(f, "post-cmd"),
|
PostChangeDir <=> "post-change-dir";
|
||||||
Self::PreChangeDir => write!(f, "pre-change-dir"),
|
OnJobFinish <=> "on-job-finish";
|
||||||
Self::PostChangeDir => write!(f, "post-change-dir"),
|
PrePrompt <=> "pre-prompt";
|
||||||
Self::OnJobFinish => write!(f, "on-job-finish"),
|
PostPrompt <=> "post-prompt";
|
||||||
Self::PrePrompt => write!(f, "pre-prompt"),
|
PreModeChange <=> "pre-mode-change";
|
||||||
Self::PostPrompt => write!(f, "post-prompt"),
|
PostModeChange <=> "post-mode-change";
|
||||||
Self::PreModeChange => write!(f, "pre-mode-change"),
|
OnHistoryOpen <=> "on-history-open";
|
||||||
Self::PostModeChange => write!(f, "post-mode-change"),
|
OnHistoryClose <=> "on-history-close";
|
||||||
Self::OnHistoryOpen => write!(f, "on-history-open"),
|
OnHistorySelect <=> "on-history-select";
|
||||||
Self::OnHistoryClose => write!(f, "on-history-close"),
|
OnCompletionStart <=> "on-completion-start";
|
||||||
Self::OnHistorySelect => write!(f, "on-history-select"),
|
OnCompletionCancel <=> "on-completion-cancel";
|
||||||
Self::OnCompletionStart => write!(f, "on-completion-start"),
|
OnCompletionSelect <=> "on-completion-select";
|
||||||
Self::OnCompletionCancel => write!(f, "on-completion-cancel"),
|
OnScreensaverExec <=> "on-screensaver-exec";
|
||||||
Self::OnCompletionSelect => write!(f, "on-completion-select"),
|
OnScreensaverReturn <=> "on-screensaver-return";
|
||||||
Self::OnExit => write!(f, "on-exit"),
|
OnExit <=> "on-exit";
|
||||||
}
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for AutoCmdKind {
|
|
||||||
type Err = ShErr;
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
match s {
|
|
||||||
"pre-cmd" => Ok(Self::PreCmd),
|
|
||||||
"post-cmd" => Ok(Self::PostCmd),
|
|
||||||
"pre-change-dir" => Ok(Self::PreChangeDir),
|
|
||||||
"post-change-dir" => Ok(Self::PostChangeDir),
|
|
||||||
"on-job-finish" => Ok(Self::OnJobFinish),
|
|
||||||
"pre-prompt" => Ok(Self::PrePrompt),
|
|
||||||
"post-prompt" => Ok(Self::PostPrompt),
|
|
||||||
"pre-mode-change" => Ok(Self::PreModeChange),
|
|
||||||
"post-mode-change" => Ok(Self::PostModeChange),
|
|
||||||
"on-history-open" => Ok(Self::OnHistoryOpen),
|
|
||||||
"on-history-close" => Ok(Self::OnHistoryClose),
|
|
||||||
"on-history-select" => Ok(Self::OnHistorySelect),
|
|
||||||
"on-completion-start" => Ok(Self::OnCompletionStart),
|
|
||||||
"on-completion-cancel" => Ok(Self::OnCompletionCancel),
|
|
||||||
"on-completion-select" => Ok(Self::OnCompletionSelect),
|
|
||||||
"on-exit" => Ok(Self::OnExit),
|
|
||||||
_ => Err(ShErr::simple(
|
|
||||||
ShErrKind::ParseErr,
|
|
||||||
format!("Invalid autocmd kind: {}", s),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AutoCmd {
|
pub struct AutoCmd {
|
||||||
|
|||||||
Reference in New Issue
Block a user