use super::zle_keymap::KM_IMMUTABLE;
use super::zle_thingy::Thingy;
#[allow(unused_imports)]
use crate::ported::zle::{
deltochar::*, textobjects::*, zle_hist::*, zle_main::*, zle_misc::*, zle_move::*,
zle_params::*, zle_refresh::*, zle_tricky::*, zle_utils::*, zle_vi::*, zle_word::*,
};
#[allow(unused_imports)]
#[allow(unused_imports)]
pub fn getkeystring(s: &str) -> Vec<u8> {
let mut result = Vec::new();
let mut chars = s.chars().peekable();
while let Some(c) = chars.next() {
match c {
'^' => {
if let Some(&next) = chars.peek() {
chars.next();
if next == '?' {
result.push(0x7f); } else if next == '[' {
result.push(0x1b); } else {
result.push((next.to_ascii_uppercase() as u8).wrapping_sub(b'@'));
}
}
}
'\\' => {
match chars.peek() {
Some(&'a') => {
chars.next();
result.push(0x07); }
Some(&'b') => {
chars.next();
result.push(0x08); }
Some(&'e') | Some(&'E') => {
chars.next();
result.push(0x1b); }
Some(&'f') => {
chars.next();
result.push(0x0c); }
Some(&'n') => {
chars.next();
result.push(b'\n');
}
Some(&'t') => {
chars.next();
result.push(b'\t');
}
Some(&'r') => {
chars.next();
result.push(b'\r');
}
Some(&'v') => {
chars.next();
result.push(0x0b); }
Some(&'M') => {
chars.next();
if chars.peek() == Some(&'-') {
chars.next();
result.push(0x1b);
if let Some(next) = chars.next() {
result.push(next as u8);
}
}
}
Some(&'C') => {
chars.next();
if chars.peek() == Some(&'-') {
chars.next();
if let Some(next) = chars.next() {
result.push((next.to_ascii_uppercase() as u8).wrapping_sub(b'@'));
}
}
}
Some(&'x') => {
chars.next();
let mut hex = String::new();
for _ in 0..2 {
if let Some(&c) = chars.peek() {
if c.is_ascii_hexdigit() {
hex.push(c);
chars.next();
} else {
break;
}
}
}
if let Ok(n) = u8::from_str_radix(&hex, 16) {
result.push(n);
}
}
Some(&c) => {
chars.next();
result.push(c as u8);
}
None => {
result.push(b'\\');
}
}
}
_ => {
result.push(c as u8);
}
}
}
result
}
pub fn bindkey_by_name(keymap: &str, seq: &str, widget: &str) -> bool {
let seq_bytes = getkeystring(seq); let km_arc = {
let tab = crate::ported::zle::zle_keymap::keymapnamtab()
.lock()
.unwrap();
match tab.get(keymap) {
Some(n) => n.keymap.clone(),
None => return false,
}
};
let mut km = (*km_arc).clone();
let rc = crate::ported::zle::zle_keymap::bindkey(
&mut km,
&seq_bytes,
Some(crate::ported::zle::zle_thingy::Thingy::new(widget)),
None,
);
if rc != 0 {
return false;
}
crate::ported::zle::zle_keymap::linkkeymap(std::sync::Arc::new(km), keymap, 0);
true
}
pub fn bindlistout(keymap: &str) -> Vec<(String, String)> {
let mut bindings = Vec::new();
if let Some(map) = crate::ported::zle::zle_keymap::openkeymap(keymap) {
for (i, thingy) in map.first.iter().enumerate() {
if let Some(t) = thingy {
let seq = printbind(&[i as u8]);
bindings.push((seq, t.nam.clone()));
}
}
for (seq, binding) in &map.multi {
if let Some(t) = &binding.bind {
let seq_str = printbind(seq);
bindings.push((seq_str, t.nam.clone()));
} else if let Some(s) = &binding.str {
let seq_str = printbind(seq);
bindings.push((seq_str, format!("send-string \"{}\"", s)));
}
}
}
bindings.sort_by(|a, b| a.0.cmp(&b.0));
bindings
}
pub static EMACSBIND: [&str; 32] = [
"set-mark-command",
"beginning-of-line",
"backward-char",
"undefined-key",
"delete-char-or-list",
"end-of-line",
"forward-char",
"send-break",
"backward-delete-char",
"expand-or-complete",
"accept-line",
"kill-line",
"clear-screen",
"accept-line",
"down-line-or-history",
"accept-line-and-down-history",
"up-line-or-history",
"push-line",
"history-incremental-search-backward",
"history-incremental-search-forward",
"transpose-chars",
"kill-whole-line",
"quoted-insert",
"backward-kill-word",
"undefined-key",
"yank",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undo",
];
pub static METABIND: [&str; 128] = [
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"list-choices",
"undefined-key",
"undefined-key",
"send-break",
"backward-kill-word",
"self-insert-unmeta",
"self-insert-unmeta",
"undefined-key",
"clear-screen",
"self-insert-unmeta",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"copy-prev-word",
"expand-history",
"expand-history",
"quote-region",
"undefined-key",
"spell-word",
"undefined-key",
"undefined-key",
"quote-line",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"neg-argument",
"insert-last-word",
"undefined-key",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"undefined-key",
"undefined-key",
"beginning-of-buffer-or-history",
"undefined-key",
"end-of-buffer-or-history",
"which-command",
"undefined-key",
"accept-and-hold",
"backward-word",
"capitalize-word",
"kill-word",
"undefined-key",
"forward-word",
"get-line",
"run-help",
"undefined-key",
"undefined-key",
"undefined-key",
"down-case-word",
"undefined-key",
"history-search-forward",
"undefined-key",
"history-search-backward",
"push-line",
"undefined-key",
"spell-word",
"transpose-words",
"up-case-word",
"undefined-key",
"copy-region-as-kill",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"insert-last-word",
"undefined-key",
"accept-and-hold",
"backward-word",
"capitalize-word",
"kill-word",
"undefined-key",
"forward-word",
"get-line",
"run-help",
"undefined-key",
"undefined-key",
"undefined-key",
"down-case-word",
"undefined-key",
"history-search-forward",
"undefined-key",
"history-search-backward",
"push-line",
"undefined-key",
"spell-word",
"transpose-words",
"up-case-word",
"undefined-key",
"copy-region-as-kill",
"execute-named-cmd",
"yank-pop",
"execute-last-named-cmd",
"undefined-key",
"vi-goto-column",
"undefined-key",
"undefined-key",
"backward-kill-word",
];
pub static VIINSBIND: [&str; 32] = [
"undefined-key",
"self-insert",
"self-insert",
"self-insert",
"list-choices",
"self-insert",
"self-insert",
"list-expand",
"vi-backward-delete-char",
"expand-or-complete",
"accept-line",
"self-insert",
"clear-screen",
"accept-line",
"self-insert",
"self-insert",
"self-insert",
"vi-quoted-insert",
"redisplay",
"self-insert",
"self-insert",
"vi-kill-line",
"vi-quoted-insert",
"vi-backward-kill-word",
"undefined-key",
"self-insert",
"self-insert",
"vi-cmd-mode",
"self-insert",
"self-insert",
"self-insert",
"self-insert",
];
pub static VICMDBIND: [&str; 128] = [
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"list-choices",
"undefined-key",
"undefined-key",
"list-expand",
"vi-backward-char",
"undefined-key",
"accept-line",
"undefined-key",
"clear-screen",
"accept-line",
"down-history",
"undefined-key",
"up-history",
"undefined-key",
"redo",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"beep",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"vi-forward-char",
"undefined-key",
"vi-set-buffer",
"pound-insert",
"vi-end-of-line",
"vi-match-bracket",
"undefined-key",
"vi-goto-mark-line",
"undefined-key",
"undefined-key",
"undefined-key",
"vi-down-line-or-history",
"vi-rev-repeat-find",
"vi-up-line-or-history",
"vi-repeat-change",
"vi-history-search-backward",
"vi-digit-or-beginning-of-line",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"digit-argument",
"execute-named-cmd",
"vi-repeat-find",
"vi-unindent",
"list-choices",
"vi-indent",
"vi-history-search-forward",
"undefined-key",
"vi-add-eol",
"vi-backward-blank-word",
"vi-change-eol",
"vi-kill-eol",
"vi-forward-blank-word-end",
"vi-find-prev-char",
"vi-fetch-history",
"undefined-key",
"vi-insert-bol",
"vi-join",
"undefined-key",
"undefined-key",
"undefined-key",
"vi-rev-repeat-search",
"vi-open-line-above",
"vi-put-before",
"undefined-key",
"vi-replace",
"vi-change-whole-line",
"vi-find-prev-char-skip",
"undefined-key",
"visual-line-mode",
"vi-forward-blank-word",
"vi-backward-delete-char",
"vi-yank-whole-line",
"undefined-key",
"undefined-key",
"undefined-key",
"undefined-key",
"vi-first-non-blank",
"vi-first-non-blank",
"vi-goto-mark",
"vi-add-next",
"vi-backward-word",
"vi-change",
"vi-delete",
"vi-forward-word-end",
"vi-find-next-char",
"undefined-key",
"vi-backward-char",
"vi-insert",
"down-line-or-history",
"up-line-or-history",
"vi-forward-char",
"vi-set-mark",
"vi-repeat-search",
"vi-open-line-below",
"vi-put-after",
"undefined-key",
"vi-replace-chars",
"vi-substitute",
"vi-find-next-char-skip",
"undo",
"visual-mode",
"vi-forward-word",
"vi-delete-char",
"vi-yank",
"undefined-key",
"undefined-key",
"vi-goto-column",
"undefined-key",
"vi-swap-case",
"vi-backward-char",
];
pub const IWIDGET_NAMES: &[&str] = &[
"accept-and-hold",
"accept-line",
"accept-line-and-down-history",
"backward-char",
"backward-delete-char",
"backward-kill-word",
"backward-word",
"beep",
"beginning-of-buffer-or-history",
"beginning-of-line",
"capitalize-word",
"clear-screen",
"complete-word",
"copy-prev-word",
"copy-region-as-kill",
"delete-char-or-list",
"digit-argument",
"down-case-word",
"down-history",
"down-line-or-history",
"end-of-buffer-or-history",
"end-of-line",
"execute-last-named-cmd",
"execute-named-cmd",
"expand-history",
"expand-or-complete",
"forward-char",
"forward-word",
"get-line",
"history-incremental-search-backward",
"history-incremental-search-forward",
"history-search-backward",
"history-search-forward",
"insert-last-word",
"kill-line",
"kill-whole-line",
"kill-word",
"list-choices",
"list-expand",
"menu-complete",
"menu-expand-or-complete",
"neg-argument",
"pound-insert",
"push-line",
"quote-line",
"quote-region",
"quoted-insert",
"redisplay",
"redo",
"reverse-menu-complete",
"run-help",
"self-insert",
"self-insert-unmeta",
"send-break",
"set-mark-command",
"spell-word",
"transpose-chars",
"transpose-words",
"undefined-key",
"undo",
"up-case-word",
"up-history",
"up-line-or-history",
"vi-add-eol",
"vi-add-next",
"vi-backward-blank-word",
"vi-backward-char",
"vi-backward-delete-char",
"vi-backward-kill-word",
"vi-backward-word",
"vi-change",
"vi-change-eol",
"vi-change-whole-line",
"vi-cmd-mode",
"vi-delete",
"vi-delete-char",
"vi-digit-or-beginning-of-line",
"vi-down-line-or-history",
"vi-end-of-line",
"vi-fetch-history",
"vi-find-next-char",
"vi-find-next-char-skip",
"vi-find-prev-char",
"vi-find-prev-char-skip",
"vi-first-non-blank",
"vi-forward-blank-word",
"vi-forward-blank-word-end",
"vi-forward-char",
"vi-forward-word",
"vi-forward-word-end",
"vi-goto-column",
"vi-goto-mark",
"vi-goto-mark-line",
"vi-history-search-backward",
"vi-history-search-forward",
"vi-indent",
"vi-insert",
"vi-insert-bol",
"vi-join",
"vi-kill-eol",
"vi-kill-line",
"vi-match-bracket",
"vi-open-line-above",
"vi-open-line-below",
"vi-put-after",
"vi-put-before",
"vi-quoted-insert",
"vi-repeat-change",
"vi-repeat-find",
"vi-repeat-search",
"vi-replace",
"vi-replace-chars",
"vi-rev-repeat-find",
"vi-rev-repeat-search",
"vi-set-buffer",
"vi-set-mark",
"vi-substitute",
"vi-swap-case",
"vi-unindent",
"vi-up-line-or-history",
"vi-yank",
"vi-yank-whole-line",
"visual-line-mode",
"visual-mode",
"which-command",
"yank",
"yank-pop",
];
pub fn iwidget_lookup(name: &str) -> Option<super::zle_h::ZleIntFunc> {
match name {
"beep" => Some(|_| handlefeep()),
"accept-and-hold" => Some(|_| acceptandhold()),
"accept-line-and-down-history" => Some(|_| acceptlineanddownhistory()),
"accept-line" => Some(|_| acceptline()),
"backward-char" => Some(|_| backwardchar()),
"backward-delete-char" => Some(|_| backwarddeletechar()),
"backward-kill-word" => Some(backwardkillword),
"backward-word" => Some(backwardword),
"beginning-of-buffer-or-history" => Some(|_| beginningofbufferorhistory()),
"beginning-of-line" => Some(|_| beginningofline()),
"capitalize-word" => Some(capitalizeword),
"complete-word" => Some(completeword),
"menu-complete" => Some(menucomplete),
"menu-expand-or-complete" => Some(menuexpandorcomplete),
"reverse-menu-complete" => Some(reversemenucomplete),
"copy-prev-word" => Some(|_| copyprevword()),
"copy-region-as-kill" => Some(copyregionaskill),
"delete-char-or-list" => Some(deletecharorlist),
"digit-argument" => Some(|_| digitargument()),
"down-case-word" => Some(downcaseword),
"down-history" => Some(|_| downhistory()),
"down-line-or-history" => Some(|_| downlineorhistory()),
"end-of-buffer-or-history" => Some(|_| endofbufferorhistory()),
"end-of-line" => Some(|_| endofline()),
"expand-history" => Some(|_| expandhistory()),
"expand-or-complete" => Some(expandorcomplete),
"forward-char" => Some(|_| forwardchar()),
"forward-word" => Some(forwardword),
"history-incremental-search-backward" => Some(|_| historyincrementalsearchbackward()),
"history-incremental-search-forward" => Some(|_| historyincrementalsearchforward()),
"history-search-backward" => Some(|_| historysearchbackward()),
"history-search-forward" => Some(|_| historysearchforward()),
"insert-last-word" => Some(|_| insertlastword()),
"kill-line" => Some(|_| killline()),
"kill-whole-line" => Some(|_| killwholeline()),
"kill-word" => Some(killword),
"list-choices" => Some(listchoices),
"list-expand" => Some(listexpand),
"neg-argument" => Some(|_| negargument()),
"pound-insert" => Some(|_| poundinsert()),
"push-line" => Some(|_| pushline()),
"quote-line" => Some(|_| quoteline()),
"quote-region" => Some(|_| quoteregion()),
"quoted-insert" => Some(|_| quotedinsert()),
"redo" => Some(|_| redo()),
"self-insert-unmeta" => Some(selfinsertunmeta),
"self-insert" => Some(selfinsert),
"send-break" => Some(|_| sendbreak()),
"set-mark-command" => Some(|_| setmarkcommand()),
"spell-word" => Some(spellword),
"transpose-chars" => Some(|_| transposechars()),
"transpose-words" => Some(transposewords),
"undefined-key" => Some(|_| undefinedkey()),
"undo" => Some(undo),
"up-case-word" => Some(upcaseword),
"up-history" => Some(|_| uphistory()),
"up-line-or-history" => Some(|_| uplineorhistory()),
"vi-add-eol" => Some(|_| viaddeol()),
"vi-add-next" => Some(|_| viaddnext()),
"vi-backward-blank-word" => Some(vibackwardblankword),
"vi-backward-char" => Some(|_| vibackwardchar()),
"vi-backward-delete-char" => Some(|_| vibackwarddeletechar()),
"vi-backward-kill-word" => Some(vibackwardkillword),
"vi-backward-word" => Some(vibackwardword),
"vi-change-eol" => Some(|_| vichangeeol()),
"vi-change-whole-line" => Some(|_| vichangewholeline()),
"vi-change" => Some(|_| vichange()),
"vi-cmd-mode" => Some(|_| vicmdmode()),
"vi-delete-char" => Some(|_| videletechar()),
"vi-delete" => Some(|_| videlete()),
"vi-digit-or-beginning-of-line" => Some(|_| vidigitorbeginningofline()),
"vi-down-line-or-history" => Some(|_| vidownlineorhistory()),
"vi-end-of-line" => Some(|_| viendofline()),
"vi-fetch-history" => Some(|_| vifetchhistory()),
"vi-find-next-char-skip" => Some(|_| vifindnextcharskip()),
"vi-find-next-char" => Some(|_| vifindnextchar()),
"vi-find-prev-char-skip" => Some(|_| vifindprevcharskip()),
"vi-find-prev-char" => Some(|_| vifindprevchar()),
"vi-first-non-blank" => Some(|_| vifirstnonblank()),
"vi-forward-blank-word-end" => Some(viforwardblankwordend),
"vi-forward-blank-word" => Some(viforwardblankword),
"vi-forward-char" => Some(|_| viforwardchar()),
"vi-forward-word-end" => Some(viforwardwordend),
"vi-forward-word" => Some(viforwardword),
"vi-goto-column" => Some(|_| vigotocolumn()),
"vi-goto-mark-line" => Some(|_| vigotomarkline('\0')),
"vi-goto-mark" => Some(|_| vigotomark('\0')),
"vi-history-search-backward" => Some(|_| vihistorysearchbackward()),
"vi-history-search-forward" => Some(|_| vihistorysearchforward()),
"vi-indent" => Some(|_| viindent()),
"vi-insert-bol" => Some(|_| viinsertbol()),
"vi-insert" => Some(|_| viinsert()),
"vi-join" => Some(|_| vijoin()),
"vi-kill-eol" => Some(|_| vikilleol()),
"vi-kill-line" => Some(|_| vikillline()),
"vi-match-bracket" => Some(|_| vimatchbracket()),
"vi-open-line-above" => Some(|_| viopenlineabove()),
"vi-open-line-below" => Some(|_| viopenlinebelow()),
"vi-put-after" => Some(|_| viputafter()),
"vi-put-before" => Some(|_| viputbefore()),
"vi-quoted-insert" => Some(|_| viquotedinsert()),
"vi-repeat-change" => Some(|_| virepeatchange()),
"vi-repeat-find" => Some(|_| virepeatfind()),
"vi-repeat-search" => Some(|_| virepeatsearch()),
"vi-replace-chars" => Some(|_| vireplacechars()),
"vi-replace" => Some(|_| vireplace()),
"vi-rev-repeat-find" => Some(|_| virevrepeatfind()),
"vi-rev-repeat-search" => Some(|_| virevrepeatsearch()),
"vi-set-buffer" => Some(|_| visetbuffer()),
"vi-set-mark" => Some(|_| visetmark('\0')),
"vi-substitute" => Some(|_| visubstitute()),
"vi-swap-case" => Some(|_| viswapcase()),
"vi-unindent" => Some(|_| viunindent()),
"vi-up-line-or-history" => Some(|_| viuplineorhistory()),
"vi-yank-whole-line" => Some(|_| viyankwholeline()),
"visual-line-mode" => Some(|_| visuallinemode()),
"visual-mode" => Some(|_| visualmode()),
"yank-pop" => Some(|_| yankpop()),
"clear-screen" => Some(|_| {
use std::sync::atomic::Ordering;
let fd = crate::ported::init::SHTTY.load(Ordering::Relaxed);
let out = if fd >= 0 { fd } else { 1 };
let _ = crate::ported::utils::write_loop(out, b"\x1b[H\x1b[2J");
ZLE_RESET_NEEDED.store(1, Ordering::SeqCst);
0
}),
"redisplay" => Some(|_| {
ZLE_RESET_NEEDED.store(1, std::sync::atomic::Ordering::SeqCst);
0
}),
"yank" => Some(|_| {
let ring = KILLRING.lock().unwrap();
let text = match ring.front() {
Some(t) => t.clone(),
None => return 1,
};
drop(ring);
let cs = ZLECS.load(std::sync::atomic::Ordering::SeqCst);
let mut line = ZLELINE.lock().unwrap();
for (i, c) in text.iter().enumerate() {
line.insert(cs + i, *c);
}
let new_ll = line.len();
drop(line);
ZLELL.store(new_ll, std::sync::atomic::Ordering::SeqCst);
ZLECS.store(cs + text.len(), std::sync::atomic::Ordering::SeqCst);
0
}),
"vi-yank" => Some(viyank),
"which-command" => Some(super::zle_misc::processcmd),
"run-help" => Some(super::zle_misc::processcmd),
"get-line" => Some(|_| super::zle_hist::zgetline()),
"execute-named-cmd" => Some(|_| 0),
"execute-last-named-cmd" => Some(|_| 0),
_ => None,
}
}
pub static IWIDGET_FLAGS: &[(&str, i32)] = {
use super::zle_h::{
ZLE_ISCOMP, ZLE_KEEPSUFFIX, ZLE_KILL, ZLE_LASTCOL, ZLE_LINEMOVE, ZLE_MENUCMP,
ZLE_NOTCOMMAND, ZLE_VIOPER, ZLE_YANK, ZLE_YANKAFTER, ZLE_YANKBEFORE,
};
&[
("complete-word", ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP),
(
"delete-char-or-list",
ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP,
),
(
"expand-or-complete",
ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP,
),
(
"expand-or-complete-prefix",
ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP,
),
("menu-complete", ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP),
(
"menu-expand-or-complete",
ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP,
),
(
"reverse-menu-complete",
ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP,
),
(
"list-choices",
ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_ISCOMP,
),
("accept-and-menu-complete", ZLE_MENUCMP | ZLE_KEEPSUFFIX),
("backward-delete-char", ZLE_KEEPSUFFIX),
("backward-delete-word", ZLE_KEEPSUFFIX),
("backward-kill-line", ZLE_KILL | ZLE_KEEPSUFFIX),
("backward-kill-word", ZLE_KILL | ZLE_KEEPSUFFIX),
("beginning-of-buffer-or-history", ZLE_LINEMOVE),
("beginning-of-history", ZLE_LINEMOVE),
("end-of-buffer-or-history", ZLE_LINEMOVE),
("end-of-history", ZLE_LINEMOVE),
("down-history", ZLE_LINEMOVE),
("down-line-or-history", ZLE_LINEMOVE),
("down-line-or-search", ZLE_LINEMOVE),
("up-history", ZLE_LINEMOVE),
("up-line-or-history", ZLE_LINEMOVE),
("up-line-or-search", ZLE_LINEMOVE),
("kill-line", ZLE_KILL | ZLE_KEEPSUFFIX),
("kill-region", ZLE_KILL | ZLE_KEEPSUFFIX),
("kill-whole-line", ZLE_KILL | ZLE_KEEPSUFFIX),
("kill-word", ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-backward-kill-word", ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-change-eol", ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-change-whole-line", ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-delete-char", ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-kill-eol", ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-kill-line", ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-yank-eol", ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-yank-whole-line", ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-change", ZLE_VIOPER | ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-delete", ZLE_VIOPER | ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-yank", ZLE_VIOPER | ZLE_KILL | ZLE_KEEPSUFFIX),
("vi-oper-swap-case", ZLE_VIOPER | ZLE_KILL | ZLE_KEEPSUFFIX),
("yank", ZLE_YANK | ZLE_YANKAFTER),
("yank-pop", ZLE_YANK | ZLE_YANKBEFORE),
("argument-base", ZLE_NOTCOMMAND),
("digit-argument", ZLE_NOTCOMMAND),
("neg-argument", ZLE_NOTCOMMAND),
("auto-suffix-remove", ZLE_NOTCOMMAND),
("universal-argument", ZLE_NOTCOMMAND),
("auto-suffix-retain", ZLE_KEEPSUFFIX | ZLE_NOTCOMMAND),
]
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bindkey_returns_false_for_unknown_keymap() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
crate::ported::zle::zle_keymap::createkeymapnamtab();
crate::ported::zle::zle_keymap::default_bindings();
assert!(!bindkey_by_name("no-such-keymap", "^A", "self-insert"));
}
#[test]
fn bindkey_then_unbind_round_trips_through_emacs_keymap() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
crate::ported::zle::zle_keymap::createkeymapnamtab();
crate::ported::zle::zle_keymap::default_bindings();
assert!(bindkey_by_name("emacs", "\\ez", "self-insert"));
let listed = bindlistout("emacs");
let seq = printbind(&[0x1b, 0x7a]);
assert!(
listed.iter().any(|(k, v)| k == &seq && v == "self-insert"),
"bound sequence missing from list: {:?}",
listed
);
let seq_bytes = getkeystring("\\ez");
let mut tab = crate::ported::zle::zle_keymap::keymapnamtab()
.lock()
.unwrap();
let node = tab.get_mut("emacs").unwrap();
let inner = std::sync::Arc::make_mut(&mut node.keymap);
inner.unbind_seq(&seq_bytes);
drop(tab);
let listed = bindlistout("emacs");
assert!(
!listed.iter().any(|(k, _)| k == &seq),
"unbound sequence still present: {:?}",
listed
);
}
#[test]
fn getkeystring_decodes_canonical_escapes() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("\\e"), vec![0x1b]); assert_eq!(getkeystring("\\t"), vec![0x09]); assert_eq!(getkeystring("\\n"), vec![0x0a]); assert_eq!(getkeystring("\\r"), vec![0x0d]); }
#[test]
fn getkeystring_decodes_control_prefix() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("\\C-a"), vec![0x01]); assert_eq!(getkeystring("\\C-c"), vec![0x03]); }
#[test]
fn getkeystring_decodes_meta_prefix() {
let _g = crate::test_util::global_state_lock();
let b = getkeystring("\\M-a");
assert!(!b.is_empty(), "\\M-a must decode to at least 1 byte");
}
#[test]
fn getkeystring_passes_plain_ascii_through() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("abc"), b"abc".to_vec());
}
#[test]
fn iwidget_lookup_resolves_self_insert() {
let _g = crate::test_util::global_state_lock();
assert!(iwidget_lookup("self-insert").is_some());
}
#[test]
fn iwidget_lookup_resolves_every_completion_widget() {
let _g = crate::test_util::global_state_lock();
for w in [
"expand-or-complete",
"complete-word",
"menu-complete",
"menu-expand-or-complete",
"reverse-menu-complete",
"list-choices",
"delete-char-or-list",
] {
assert!(
iwidget_lookup(w).is_some(),
"completion widget `{w}` is registered in IWIDGET_NAMES but has no fn pointer",
);
}
}
#[test]
fn iwidget_lookup_returns_none_for_unknown_name() {
let _g = crate::test_util::global_state_lock();
assert!(iwidget_lookup("definitely-not-a-real-widget-zshrs").is_none());
}
#[test]
fn bindlistout_empty_for_unknown_keymap() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert!(bindlistout("does-not-exist").is_empty());
}
#[test]
fn getkeystring_empty_string_returns_empty() {
let _g = crate::test_util::global_state_lock();
assert!(getkeystring("").is_empty());
}
#[test]
fn getkeystring_decodes_backspace() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("\\b"), vec![0x08]);
}
#[test]
fn getkeystring_control_prefix_is_case_insensitive() {
let _g = crate::test_util::global_state_lock();
let lower = getkeystring("\\C-a");
let upper = getkeystring("\\C-A");
assert_eq!(lower, upper, r#"\\C-a and \\C-A must decode identically"#);
assert_eq!(lower, vec![0x01]);
}
#[test]
fn iwidget_lookup_resolves_accept_line() {
let _g = crate::test_util::global_state_lock();
assert!(
iwidget_lookup("accept-line").is_some(),
"accept-line is the canonical Enter-key widget; must resolve"
);
}
#[test]
fn iwidget_lookup_empty_name_returns_none() {
let _g = crate::test_util::global_state_lock();
assert!(iwidget_lookup("").is_none());
}
#[test]
fn bindkey_unknown_widget_binds_anyway_matching_c() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let ok = bindkey_by_name("main", "\\C-x", "user-widget-not-yet-defined");
assert!(
ok,
"C source resolves widgets at trigger time, so bind-time \
unknowns must SUCCEED"
);
}
#[test]
fn zle_bindings_corpus_getkeystring_caret_A_is_ctrl_a() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("^A"), vec![0x01]);
}
#[test]
fn zle_bindings_corpus_getkeystring_caret_question_is_del() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("^?"), vec![0x7f]);
}
#[test]
fn zle_bindings_corpus_getkeystring_caret_bracket_is_esc() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("^["), vec![0x1b]);
}
#[test]
fn zle_bindings_corpus_getkeystring_backslash_e_is_esc() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\e"), vec![0x1b]);
}
#[test]
fn zle_bindings_corpus_getkeystring_backslash_t_is_tab() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\t"), vec![0x09]);
}
#[test]
fn zle_bindings_corpus_getkeystring_backslash_n_is_lf() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\n"), vec![0x0a]);
}
#[test]
fn zle_bindings_corpus_getkeystring_backslash_r_is_cr() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\r"), vec![0x0d]);
}
#[test]
fn zle_bindings_corpus_getkeystring_empty_is_empty() {
let _g = crate::test_util::global_state_lock();
assert!(getkeystring("").is_empty());
}
#[test]
fn zle_bindings_corpus_getkeystring_plain_ascii_passthrough() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("abc"), vec![b'a', b'b', b'c']);
}
#[test]
fn getkeystring_backslash_a_is_bell() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\a"), vec![0x07]);
}
#[test]
fn getkeystring_backslash_b_is_backspace() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\b"), vec![0x08]);
}
#[test]
fn getkeystring_backslash_e_and_capital_E_both_esc() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\e"), vec![0x1b]);
assert_eq!(getkeystring(r"\E"), vec![0x1b]);
}
#[test]
fn getkeystring_backslash_f_is_form_feed() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\f"), vec![0x0c]);
}
#[test]
fn getkeystring_backslash_t_is_tab() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\t"), vec![0x09]);
}
#[test]
fn getkeystring_backslash_v_is_vt() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\v"), vec![0x0b]);
}
#[test]
fn getkeystring_caret_question_is_del() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("^?"), vec![0x7f]);
}
#[test]
fn getkeystring_caret_bracket_is_escape() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("^["), vec![0x1b]);
}
#[test]
fn getkeystring_caret_A_is_ctrl_a() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("^A"), vec![0x01]);
}
#[test]
fn getkeystring_caret_lowercase_a_is_ctrl_a() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring("^a"), vec![0x01]);
}
#[test]
fn getkeystring_meta_dash_X_is_esc_X() {
let _g = crate::test_util::global_state_lock();
let r = getkeystring(r"\M-X");
assert_eq!(r, vec![0x1b, b'X']);
}
#[test]
fn getkeystring_esc_plus_literals() {
let _g = crate::test_util::global_state_lock();
assert_eq!(getkeystring(r"\eOA"), vec![0x1b, b'O', b'A']);
}
#[test]
fn getkeystring_is_deterministic() {
let _g = crate::test_util::global_state_lock();
for input in [r"\a", r"\b", "^?", "^A", r"\eOA", "abc"] {
let first = getkeystring(input);
for _ in 0..5 {
assert_eq!(getkeystring(input), first, "{:?} must be pure", input);
}
}
}
#[test]
fn getkeystring_returns_vec_u8_type() {
let _: Vec<u8> = getkeystring("abc");
}
#[test]
fn getkeystring_empty_returns_empty_vec() {
assert_eq!(getkeystring(""), Vec::<u8>::new());
}
#[test]
fn getkeystring_single_ascii_passthrough() {
assert_eq!(getkeystring("a"), vec![b'a']);
}
#[test]
fn getkeystring_backslash_n_is_newline() {
assert_eq!(getkeystring(r"\n"), vec![b'\n']);
}
#[test]
fn getkeystring_backslash_r_is_carriage_return() {
assert_eq!(getkeystring(r"\r"), vec![b'\r']);
}
#[test]
fn bindkey_by_name_returns_bool_type() {
let _g = crate::test_util::global_state_lock();
let _g2 = zle_test_setup();
let _: bool = bindkey_by_name("emacs", "x", "self-insert");
}
#[test]
fn bindlistout_returns_vec_tuple_type() {
let _g = crate::test_util::global_state_lock();
let _g2 = zle_test_setup();
let _: Vec<(String, String)> = bindlistout("emacs");
}
#[test]
fn bindlistout_unknown_keymap_returns_empty() {
let _g = crate::test_util::global_state_lock();
let _g2 = zle_test_setup();
let r = bindlistout("__never_real_keymap_xyz__");
assert!(r.is_empty(), "unknown keymap → empty");
}
#[test]
fn bindlistout_empty_keymap_name_returns_empty() {
let _g = crate::test_util::global_state_lock();
let _g2 = zle_test_setup();
let r = bindlistout("");
assert!(r.is_empty(), "empty name → empty");
}
#[test]
fn iwidget_lookup_unknown_returns_none() {
let _g = crate::test_util::global_state_lock();
let _g2 = zle_test_setup();
assert!(iwidget_lookup("__never_a_real_widget_xyz__").is_none());
}
#[test]
fn iwidget_lookup_is_deterministic() {
let _g = crate::test_util::global_state_lock();
let _g2 = zle_test_setup();
let first = iwidget_lookup("self-insert").is_some();
for _ in 0..5 {
assert_eq!(iwidget_lookup("self-insert").is_some(), first);
}
}
#[test]
fn getkeystring_returns_vec_u8_pin_alt() {
let _: Vec<u8> = getkeystring("anything");
}
#[test]
fn getkeystring_backslash_a_is_bel() {
assert_eq!(getkeystring(r"\a"), vec![0x07], "\\a → BEL (0x07)");
}
#[test]
fn getkeystring_backslash_b_is_bs() {
assert_eq!(getkeystring(r"\b"), vec![0x08], "\\b → BS (0x08)");
}
#[test]
fn getkeystring_backslash_f_is_ff() {
assert_eq!(getkeystring(r"\f"), vec![0x0c], "\\f → FF (0x0c)");
}
#[test]
fn getkeystring_backslash_t_is_tab_alt() {
assert_eq!(getkeystring(r"\t"), vec![0x09], "\\t → TAB (0x09)");
}
#[test]
fn getkeystring_backslash_v_is_vt_alt() {
assert_eq!(getkeystring(r"\v"), vec![0x0b], "\\v → VT (0x0b)");
}
#[test]
fn getkeystring_backslash_e_is_esc() {
assert_eq!(getkeystring(r"\e"), vec![0x1b], "\\e → ESC (0x1b)");
}
#[test]
fn getkeystring_backslash_E_is_esc() {
assert_eq!(getkeystring(r"\E"), vec![0x1b], "\\E → ESC (0x1b)");
}
#[test]
fn getkeystring_caret_A_is_ctrl_a_alt() {
assert_eq!(getkeystring("^A"), vec![0x01], "^A → 0x01");
}
#[test]
fn getkeystring_caret_question_is_del_alt() {
assert_eq!(getkeystring("^?"), vec![0x7f], "^? → 0x7f (DEL)");
}
#[test]
fn getkeystring_caret_bracket_is_esc() {
assert_eq!(getkeystring("^["), vec![0x1b], "^[ → 0x1b (ESC)");
}
#[test]
fn getkeystring_is_deterministic_alt() {
for s in ["", "a", r"\n", "^A", r"\e^[abc"] {
let first = getkeystring(s);
for _ in 0..3 {
assert_eq!(getkeystring(s), first, "getkeystring({:?}) must be pure", s);
}
}
}
#[test]
fn bindkey_by_name_unknown_keymap_deterministic() {
let _g = crate::test_util::global_state_lock();
let _g2 = zle_test_setup();
let first = bindkey_by_name("__never_keymap__", "x", "self-insert");
for _ in 0..3 {
assert_eq!(
bindkey_by_name("__never_keymap__", "x", "self-insert"),
first,
"bindkey_by_name on unknown keymap must be deterministic"
);
}
}
}