use super::zle_thingy::Thingy;
#[allow(unused_imports)]
#[allow(unused_imports)]
use crate::ported::zle::zle_main::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_misc::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_hist::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_move::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_word::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_params::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_vi::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_utils::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_refresh::*;
#[allow(unused_imports)]
use crate::ported::zle::zle_tricky::*;
#[allow(unused_imports)]
use crate::ported::zle::textobjects::*;
#[allow(unused_imports)]
use crate::ported::zle::deltochar::*;
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(&'e') | Some(&'E') => {
chars.next();
result.push(0x1b); }
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(&'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 printbind(seq: &[u8]) -> String { let mut result = String::new();
let mut i = 0;
while i < seq.len() {
let b = seq[i];
match b {
0x1b => {
result.push_str("^[");
}
0x00..=0x1f => {
result.push('^');
result.push((b + b'@') as char);
}
0x7f => {
result.push_str("^?");
}
0x80..=0xff => {
result.push_str(&format!("\\x{:02x}", b));
}
_ => {
result.push(b as char);
}
}
i += 1;
}
result
}
pub fn bindkey(keymap: &str, seq: &str, widget: &str) -> bool { let seq_bytes = getkeystring(seq);
let mut tab = crate::ported::zle::zle_keymap::keymapnamtab().lock().unwrap();
let node = match tab.get_mut(keymap) {
Some(n) => n,
None => return false,
};
let inner = std::sync::Arc::make_mut(&mut node.keymap);
inner.bind_seq(&seq_bytes, Thingy::new(widget));
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",
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bindkey_returns_false_for_unknown_keymap() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
crate::ported::zle::zle_keymap::createkeymapnamtab();
crate::ported::zle::zle_keymap::default_bindings();
assert!(!bindkey("no-such-keymap", "^A", "self-insert"));
}
#[test]
fn bindkey_then_unbind_round_trips_through_emacs_keymap() {
let _g = crate::ported::zle::zle_main::zle_test_setup();
crate::ported::zle::zle_keymap::createkeymapnamtab();
crate::ported::zle::zle_keymap::default_bindings();
assert!(bindkey("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
);
}
}
pub fn iwidget_lookup(name: &str) -> Option<super::zle_h::ZleIntFunc> {
match name {
"beep" => Some(|_| super::zle_utils::handlefeep()),
"accept-and-hold" => Some(|_| super::zle_misc::acceptandhold()),
"accept-line-and-down-history" => Some(|_| super::zle_hist::acceptlineanddownhistory()),
"accept-line" => Some(|_| super::zle_misc::acceptline()),
"backward-char" => Some(|_| super::zle_move::backwardchar()),
"backward-delete-char" => Some(|_| super::zle_misc::backwarddeletechar()),
"backward-kill-word" => Some(super::zle_word::backwardkillword),
"backward-word" => Some(super::zle_word::backwardword),
"beginning-of-buffer-or-history" => Some(|_| super::zle_hist::beginningofbufferorhistory()),
"beginning-of-line" => Some(|_| super::zle_move::beginningofline()),
"capitalize-word" => Some(super::zle_word::capitalizeword),
"copy-prev-word" => Some(|_| super::zle_misc::copyprevword()),
"copy-region-as-kill" => Some(super::zle_misc::copyregionaskill),
"delete-char-or-list" => Some(|_| super::zle_tricky::deletecharorlist()),
"digit-argument" => Some(|_| super::zle_misc::digitargument()),
"down-case-word" => Some(super::zle_word::downcaseword),
"down-history" => Some(|_| super::zle_hist::downhistory()),
"down-line-or-history" => Some(|_| super::zle_hist::downlineorhistory()),
"end-of-buffer-or-history" => Some(|_| super::zle_hist::endofbufferorhistory()),
"end-of-line" => Some(|_| super::zle_move::endofline()),
"expand-history" => Some(|_| super::zle_tricky::expandhistory()),
"expand-or-complete" => Some(|_| super::zle_tricky::expandorcomplete()),
"forward-char" => Some(|_| super::zle_move::forwardchar()),
"forward-word" => Some(super::zle_word::forwardword),
"history-incremental-search-backward" => Some(|_| super::zle_hist::historyincrementalsearchbackward()),
"history-incremental-search-forward" => Some(|_| super::zle_hist::historyincrementalsearchforward()),
"history-search-backward" => Some(|_| super::zle_hist::historysearchbackward()),
"history-search-forward" => Some(|_| super::zle_hist::historysearchforward()),
"insert-last-word" => Some(|_| super::zle_hist::insertlastword()),
"kill-line" => Some(|_| super::zle_misc::killline()),
"kill-whole-line" => Some(|_| super::zle_misc::killwholeline()),
"kill-word" => Some(super::zle_word::killword),
"list-choices" => Some(|_| super::zle_tricky::listchoices()),
"list-expand" => Some(|_| super::zle_tricky::listexpand()),
"neg-argument" => Some(|_| super::zle_misc::negargument()),
"pound-insert" => Some(|_| super::zle_misc::poundinsert()),
"push-line" => Some(|_| super::zle_hist::pushline()),
"quote-line" => Some(|_| super::zle_misc::quoteline()),
"quote-region" => Some(|_| super::zle_misc::quoteregion()),
"quoted-insert" => Some(|_| super::zle_misc::quotedinsert()),
"redo" => Some(|_| super::zle_utils::redo()),
"self-insert-unmeta" => Some(|_| super::zle_misc::selfinsertunmeta()),
"self-insert" => Some(|_| super::zle_misc::selfinsert()),
"send-break" => Some(|_| super::zle_misc::sendbreak()),
"set-mark-command" => Some(|_| super::zle_move::setmarkcommand()),
"spell-word" => Some(|_| super::zle_tricky::spellword()),
"transpose-chars" => Some(|_| super::zle_misc::transposechars()),
"transpose-words" => Some(super::zle_word::transposewords),
"undefined-key" => Some(|_| super::zle_misc::undefinedkey()),
"undo" => Some(super::zle_utils::undo),
"up-case-word" => Some(super::zle_word::upcaseword),
"up-history" => Some(|_| super::zle_hist::uphistory()),
"up-line-or-history" => Some(|_| super::zle_hist::uplineorhistory()),
"vi-add-eol" => Some(|_| super::zle_vi::viaddeol()),
"vi-add-next" => Some(|_| super::zle_vi::viaddnext()),
"vi-backward-blank-word" => Some(super::zle_word::vibackwardblankword),
"vi-backward-char" => Some(|_| super::zle_move::vibackwardchar()),
"vi-backward-delete-char" => Some(|_| super::zle_vi::vibackwarddeletechar()),
"vi-backward-kill-word" => Some(super::zle_word::vibackwardkillword),
"vi-backward-word" => Some(super::zle_word::vibackwardword),
"vi-change-eol" => Some(|_| super::zle_vi::vichangeeol()),
"vi-change-whole-line" => Some(|_| super::zle_vi::vichangewholeline()),
"vi-change" => Some(|_| super::zle_vi::vichange()),
"vi-cmd-mode" => Some(|_| super::zle_vi::vicmdmode()),
"vi-delete-char" => Some(|_| super::zle_vi::videletechar()),
"vi-delete" => Some(|_| super::zle_vi::videlete()),
"vi-digit-or-beginning-of-line" => Some(|_| super::zle_vi::vidigitorbeginningofline()),
"vi-down-line-or-history" => Some(|_| super::zle_hist::vidownlineorhistory()),
"vi-end-of-line" => Some(|_| super::zle_move::viendofline()),
"vi-fetch-history" => Some(|_| super::zle_hist::vifetchhistory()),
"vi-find-next-char-skip" => Some(|_| super::zle_move::vifindnextcharskip()),
"vi-find-next-char" => Some(|_| super::zle_move::vifindnextchar()),
"vi-find-prev-char-skip" => Some(|_| super::zle_move::vifindprevcharskip()),
"vi-find-prev-char" => Some(|_| super::zle_move::vifindprevchar()),
"vi-first-non-blank" => Some(|_| super::zle_move::vifirstnonblank()),
"vi-forward-blank-word-end" => Some(super::zle_word::viforwardblankwordend),
"vi-forward-blank-word" => Some(super::zle_word::viforwardblankword),
"vi-forward-char" => Some(|_| super::zle_move::viforwardchar()),
"vi-forward-word-end" => Some(super::zle_word::viforwardwordend),
"vi-forward-word" => Some(super::zle_word::viforwardword),
"vi-goto-column" => Some(|_| super::zle_move::vigotocolumn()),
"vi-goto-mark-line" => Some(|_| super::zle_move::vigotomarkline('\0')),
"vi-goto-mark" => Some(|_| super::zle_move::vigotomark('\0')),
"vi-history-search-backward" => Some(|_| super::zle_hist::vihistorysearchbackward()),
"vi-history-search-forward" => Some(|_| super::zle_hist::vihistorysearchforward()),
"vi-indent" => Some(|_| super::zle_vi::viindent()),
"vi-insert-bol" => Some(|_| super::zle_vi::viinsertbol()),
"vi-insert" => Some(|_| super::zle_vi::viinsert()),
"vi-join" => Some(|_| super::zle_vi::vijoin()),
"vi-kill-eol" => Some(|_| super::zle_vi::vikilleol()),
"vi-kill-line" => Some(|_| super::zle_vi::vikillline()),
"vi-match-bracket" => Some(|_| super::zle_move::vimatchbracket()),
"vi-open-line-above" => Some(|_| super::zle_vi::viopenlineabove()),
"vi-open-line-below" => Some(|_| super::zle_vi::viopenlinebelow()),
"vi-put-after" => Some(|_| super::zle_misc::viputafter()),
"vi-put-before" => Some(|_| super::zle_misc::viputbefore()),
"vi-quoted-insert" => Some(|_| super::zle_vi::viquotedinsert()),
"vi-repeat-change" => Some(|_| super::zle_vi::virepeatchange()),
"vi-repeat-find" => Some(|_| super::zle_move::virepeatfind()),
"vi-repeat-search" => Some(|_| super::zle_hist::virepeatsearch()),
"vi-replace-chars" => Some(|_| super::zle_vi::vireplacechars()),
"vi-replace" => Some(|_| super::zle_vi::vireplace()),
"vi-rev-repeat-find" => Some(|_| super::zle_move::virevrepeatfind()),
"vi-rev-repeat-search" => Some(|_| super::zle_hist::virevrepeatsearch()),
"vi-set-buffer" => Some(|_| super::zle_vi::visetbuffer()),
"vi-set-mark" => Some(|_| super::zle_move::visetmark('\0')),
"vi-substitute" => Some(|_| super::zle_vi::visubstitute()),
"vi-swap-case" => Some(|_| super::zle_vi::viswapcase()),
"vi-unindent" => Some(|_| super::zle_vi::viunindent()),
"vi-up-line-or-history" => Some(|_| super::zle_hist::viuplineorhistory()),
"vi-yank-whole-line" => Some(|_| super::zle_vi::viyankwholeline()),
"visual-line-mode" => Some(|_| super::zle_move::visuallinemode()),
"visual-mode" => Some(|_| super::zle_move::visualmode()),
"yank-pop" => Some(|_| super::zle_misc::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");
crate::ported::zle::zle_main::ZLE_RESET_NEEDED.store(1, Ordering::SeqCst);
0
}),
"redisplay" => Some(|_| {
crate::ported::zle::zle_main::ZLE_RESET_NEEDED.store(1, std::sync::atomic::Ordering::SeqCst);
0
}),
"yank" => Some(|_| {
let ring = crate::ported::zle::zle_main::KILLRING.lock().unwrap();
let text = match ring.front() { Some(t) => t.clone(), None => return 1 };
drop(ring);
let cs = crate::ported::zle::zle_main::ZLECS.load(std::sync::atomic::Ordering::SeqCst);
let mut line = crate::ported::zle::zle_main::ZLELINE.lock().unwrap();
for (i, c) in text.iter().enumerate() { line.insert(cs + i, *c); }
let new_ll = line.len();
drop(line);
crate::ported::zle::zle_main::ZLELL.store(new_ll, std::sync::atomic::Ordering::SeqCst);
crate::ported::zle::zle_main::ZLECS.store(cs + text.len(), std::sync::atomic::Ordering::SeqCst);
0
}),
"vi-yank" => Some(super::zle_vi::viyank),
"which-command" => Some(super::zle_misc::processcmd),
"run-help" => Some(super::zle_misc::processcmd),
"get-line" => Some(super::zle_misc::zgetline),
"execute-named-cmd" => Some(|_| 0),
"execute-last-named-cmd" => Some(|_| 0),
_ => None,
}
}