#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Prefix {
K,
Q,
O,
}
impl Prefix {
pub fn label(self) -> &'static str {
match self {
Prefix::K => "^K Block & File",
Prefix::Q => "^Q Quick",
Prefix::O => "^O Onscreen",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Cmd {
Up,
Down,
Left,
Right,
WordLeft,
WordRight,
ScrollUp,
ScrollDown,
PageUp,
PageDown,
LineStart,
LineEnd,
ScreenTop,
ScreenBottom,
DocStart,
DocEnd,
SentenceBack,
SentenceFwd,
ParaBack,
ParaFwd,
PrevPosition,
Outline,
NextMisspelling,
DeleteRight,
DeleteLeft,
DeleteWordRight,
DeleteLine,
DeleteToLineEnd,
InsertBlankLine,
TransposeWords,
TransposeChars,
Undo,
FindIncremental,
FindReplace,
FindNext,
MacroRecord,
MacroPlay,
Palette,
BlockBegin,
BlockEnd,
BlockCopy,
BlockMove,
BlockDelete,
BlockWrite,
BlockRead,
BlockHide,
BlockPrev,
Put,
JumpBlockBegin,
JumpBlockEnd,
JumpBlockSource,
Save,
SaveExit,
Quit,
ExportClean,
ExportManuscript,
CycleTheme,
RevealCodes,
ToggleWrap,
SetWrapMargin,
ToggleInsert,
CycleHelpLevel,
ToggleSpellcheck,
AddToDictionary,
ToggleTypewriter,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Chord {
Bare(char),
Pref(Prefix, char),
}
pub struct Binding {
pub cmd: Cmd,
pub chord: Chord,
pub name: &'static str,
}
use Chord::{Bare, Pref};
use Prefix::{K, O, Q};
pub const BINDINGS: &[Binding] = &[
Binding { cmd: Cmd::Up, chord: Bare('e'), name: "cursor up" },
Binding { cmd: Cmd::Down, chord: Bare('x'), name: "cursor down" },
Binding { cmd: Cmd::Left, chord: Bare('s'), name: "cursor left" },
Binding { cmd: Cmd::Right, chord: Bare('d'), name: "cursor right" },
Binding { cmd: Cmd::WordLeft, chord: Bare('a'), name: "word left" },
Binding { cmd: Cmd::WordRight, chord: Bare('f'), name: "word right" },
Binding { cmd: Cmd::ScrollUp, chord: Bare('w'), name: "scroll up" },
Binding { cmd: Cmd::ScrollDown, chord: Bare('z'), name: "scroll down" },
Binding { cmd: Cmd::PageUp, chord: Bare('r'), name: "page up" },
Binding { cmd: Cmd::PageDown, chord: Bare('c'), name: "page down" },
Binding { cmd: Cmd::DeleteRight, chord: Bare('g'), name: "delete char" },
Binding { cmd: Cmd::DeleteLeft, chord: Bare('h'), name: "delete left" },
Binding { cmd: Cmd::DeleteWordRight, chord: Bare('t'), name: "delete word" },
Binding { cmd: Cmd::DeleteLine, chord: Bare('y'), name: "delete line" },
Binding { cmd: Cmd::InsertBlankLine, chord: Bare('n'), name: "insert line" },
Binding { cmd: Cmd::Undo, chord: Bare('u'), name: "undo" },
Binding { cmd: Cmd::FindNext, chord: Bare('l'), name: "find next" },
Binding { cmd: Cmd::ToggleInsert, chord: Bare('v'), name: "insert/overtype" },
Binding { cmd: Cmd::LineStart, chord: Pref(Q, 's'), name: "line start" },
Binding { cmd: Cmd::LineEnd, chord: Pref(Q, 'd'), name: "line end" },
Binding { cmd: Cmd::ScreenTop, chord: Pref(Q, 'e'), name: "screen top" },
Binding { cmd: Cmd::ScreenBottom, chord: Pref(Q, 'x'), name: "screen bottom" },
Binding { cmd: Cmd::DocStart, chord: Pref(Q, 'r'), name: "document top" },
Binding { cmd: Cmd::DocEnd, chord: Pref(Q, 'c'), name: "document end" },
Binding { cmd: Cmd::SentenceBack, chord: Pref(Q, ','), name: "sentence back" },
Binding { cmd: Cmd::SentenceFwd, chord: Pref(Q, '.'), name: "sentence forward" },
Binding { cmd: Cmd::ParaBack, chord: Pref(Q, '['), name: "paragraph back" },
Binding { cmd: Cmd::ParaFwd, chord: Pref(Q, ']'), name: "paragraph forward" },
Binding { cmd: Cmd::PrevPosition, chord: Pref(Q, 'p'), name: "previous position" },
Binding { cmd: Cmd::Outline, chord: Pref(Q, 'o'), name: "outline / headings" },
Binding { cmd: Cmd::NextMisspelling, chord: Pref(Q, 'n'), name: "next misspelling" },
Binding { cmd: Cmd::FindIncremental, chord: Pref(Q, 'f'), name: "find" },
Binding { cmd: Cmd::FindReplace, chord: Pref(Q, 'a'), name: "find & replace" },
Binding { cmd: Cmd::DeleteToLineEnd, chord: Pref(Q, 'y'), name: "delete to line end" },
Binding { cmd: Cmd::TransposeWords, chord: Pref(Q, 't'), name: "transpose words" },
Binding { cmd: Cmd::TransposeChars, chord: Pref(Q, 'g'), name: "transpose chars" },
Binding { cmd: Cmd::MacroRecord, chord: Pref(Q, 'm'), name: "record macro" },
Binding { cmd: Cmd::MacroPlay, chord: Pref(Q, 'j'), name: "play macro" },
Binding { cmd: Cmd::JumpBlockBegin, chord: Pref(Q, 'b'), name: "to block begin" },
Binding { cmd: Cmd::JumpBlockEnd, chord: Pref(Q, 'k'), name: "to block end" },
Binding { cmd: Cmd::JumpBlockSource, chord: Pref(Q, 'v'), name: "to block source" },
Binding { cmd: Cmd::BlockBegin, chord: Pref(K, 'b'), name: "mark block begin" },
Binding { cmd: Cmd::BlockEnd, chord: Pref(K, 'k'), name: "mark block end" },
Binding { cmd: Cmd::BlockCopy, chord: Pref(K, 'c'), name: "copy block here" },
Binding { cmd: Cmd::BlockMove, chord: Pref(K, 'v'), name: "move block here" },
Binding { cmd: Cmd::BlockDelete, chord: Pref(K, 'y'), name: "delete block" },
Binding { cmd: Cmd::BlockWrite, chord: Pref(K, 'w'), name: "write block to file" },
Binding { cmd: Cmd::BlockRead, chord: Pref(K, 'r'), name: "read file here" },
Binding { cmd: Cmd::BlockHide, chord: Pref(K, 'h'), name: "hide/show block" },
Binding { cmd: Cmd::BlockPrev, chord: Pref(K, 'u'), name: "previous block" },
Binding { cmd: Cmd::Put, chord: Pref(K, 'p'), name: "put (cycle clippings)" },
Binding { cmd: Cmd::Save, chord: Pref(K, 'd'), name: "save" },
Binding { cmd: Cmd::Save, chord: Pref(K, 's'), name: "save" },
Binding { cmd: Cmd::SaveExit, chord: Pref(K, 'x'), name: "save & exit" },
Binding { cmd: Cmd::Quit, chord: Pref(K, 'q'), name: "quit" },
Binding { cmd: Cmd::ExportClean, chord: Pref(K, 'e'), name: "export (strip notes)" },
Binding { cmd: Cmd::ExportManuscript, chord: Pref(K, 'm'), name: "export manuscript RTF" },
Binding { cmd: Cmd::CycleTheme, chord: Pref(O, 'b'), name: "cycle theme" },
Binding { cmd: Cmd::RevealCodes, chord: Pref(O, 'd'), name: "reveal codes" },
Binding { cmd: Cmd::ToggleWrap, chord: Pref(O, 'w'), name: "word wrap on/off" },
Binding { cmd: Cmd::SetWrapMargin, chord: Pref(O, 'r'), name: "set wrap margin" },
Binding { cmd: Cmd::CycleHelpLevel, chord: Pref(O, 'h'), name: "cycle help level" },
Binding { cmd: Cmd::ToggleSpellcheck, chord: Pref(O, 's'), name: "spellcheck on/off" },
Binding { cmd: Cmd::AddToDictionary, chord: Pref(O, 'a'), name: "add word to dictionary" },
Binding { cmd: Cmd::ToggleTypewriter, chord: Pref(O, 't'), name: "typewriter scrolling on/off" },
];
pub fn chord_label(chord: Chord) -> String {
match chord {
Bare(c) => format!("^{}", c.to_ascii_uppercase()),
Pref(p, c) => {
let p = match p {
K => 'K',
Q => 'Q',
O => 'O',
};
format!("^{p}{}", c.to_ascii_uppercase())
}
}
}
pub fn filtered_entries(query: &str) -> Vec<(Cmd, &'static str, String)> {
let q = query.to_lowercase();
palette_entries()
.into_iter()
.filter(|(_, name, chord)| {
q.is_empty() || name.to_lowercase().contains(&q) || chord.to_lowercase().contains(&q)
})
.collect()
}
pub fn palette_entries() -> Vec<(Cmd, &'static str, String)> {
let mut seen = Vec::new();
let mut out = Vec::new();
for b in BINDINGS {
if !seen.contains(&b.cmd) {
seen.push(b.cmd);
out.push((b.cmd, b.name, chord_label(b.chord)));
}
}
out
}
pub fn lookup_bare(c: char) -> Option<Cmd> {
BINDINGS.iter().find_map(|b| match b.chord {
Bare(k) if k == c => Some(b.cmd),
_ => None,
})
}
pub fn lookup_prefixed(prefix: Prefix, c: char) -> Option<Cmd> {
BINDINGS.iter().find_map(|b| match b.chord {
Pref(p, k) if p == prefix && k == c => Some(b.cmd),
_ => None,
})
}
pub fn menu_entries(prefix: Prefix) -> Vec<(char, &'static str)> {
let mut seen = Vec::new();
let mut out = Vec::new();
for b in BINDINGS {
if let Pref(p, k) = b.chord {
if p == prefix && !seen.contains(&b.cmd) {
seen.push(b.cmd);
out.push((k, b.name));
}
}
}
out
}