Skip to content

Instantly share code, notes, and snippets.

@qix
Created November 25, 2017 18:39
Show Gist options
  • Save qix/fd20fdf6660b3a41e5dd8144b3e8f0b5 to your computer and use it in GitHub Desktop.
Save qix/fd20fdf6660b3a41e5dd8144b3e8f0b5 to your computer and use it in GitHub Desktop.
{
const {
commands,
extensions,
} = options;
const {
CancelCommand,
ClickCommand,
ExecCommand,
I3Command,
KeyCommand,
KeyHoldCommand,
ModeCommand,
MultiCommand,
NoopCommand,
PreviousCommand,
PriorityCommand,
RecordCommand,
RepeatCommand,
SleepCommand,
VscodeCommand,
WaitCommand,
RelativePathCommand,
} = options.commands;
function relpath(path) {
return new RelativePathCommand(path);
}
function cancel() {
return new CancelCommand();
}
function noop() {
return new NoopCommand();
}
function bash(command) {
return new ExecCommand(command, {
shell: true,
});
}
function wait(delay) {
return new WaitCommand(delay);
}
function exec(command) {
return new ExecCommand(command);
}
function i3(command) {
return new I3Command(command);
}
function vscodeMode(test) {
return extensions.vscode.modeTest(options.mode, test);
}
function vscode(command, args) {
return new VscodeCommand(command, args);
}
function vscodeSelectable(command, args) {
if (vscodeMode('editorHasSelection')) {
command += 'Select';
}
return new VscodeCommand(command, args);
}
function vscodeType(command) {
return VscodeCommand.fromTypeCommand(command);
}
function vscodeVim(command) {
return vscode('extension.vim-command.run', {command});
}
function repeat(count, command) {
if (count === 1) {
return command;
}
return new RepeatCommand(count, command);
}
function mode(name) {
return new ModeCommand([name], []);
}
function modeOff(name) {
return new ModeCommand([], [name]);
}
function multi(...commands) {
if (commands.length === 0) {
return noop();
} else if (commands.length === 1) {
return commands[0];
}
return new MultiCommand(commands);
}
function key(name) {
return new KeyCommand(name);
}
function type(keys) {
const names = {'\n': 'enter'};
if (typeof keys === 'string') {
keys = keys.split('').map(key => {
return names[key] || key;
});
}
return multi(...keys.map(name => key(name)));
}
function typeLine(keys) {
return multi(type(keys), key('enter'));
}
function camel(words, big=false) {
let first = words.shift();
first = big ? upperFirst(first) : first;
return first + words.map(upperFirst).join('');
}
function snake(words) {
return words.join('_');
}
function vimex(command) {
return escaped(typeLine(`:${command}`));
}
function upperFirst(word) {
return word.substring(0, 1).toUpperCase() + word.substring(1);
}
function escaped(command) {
return multi(key('escape'), command);
}
function extractList(list, index) {
return list.map(element => element[index]);
}
function extractOptional(optional, index, def=null) {
return optional ? optional[index] : def;
}
function optional(v, def=null) {
return extractOptional(v, 1, def);
}
function flatten(arr) {
return arr.reduce((flat, next) => (
flat.concat(Array.isArray(next) ? flatten(next) : next)
), []);
}
}
wake_up => new SleepCommand(false);
go_to_sleep => new SleepCommand(true);
snore => new SleepCommand(true);
restart voice => exec('~/bin/voice');
close voice => bash("xdotool search --name '^pegvoice$' | xargs -n 1 xdotool windowkill");
stop voice => bash("xdotool search --name '^pegvoice$' | xargs -n 1 xdotool windowkill");
record on => new RecordCommand(true);
record off => new RecordCommand(false);
click => new ClickCommand();
move window :direction => i3(`move ${direction}`);
close window => i3('kill');
window ...{
float => i3('floating toggle');
:direction => i3(`focus ${direction}`);
move :direction => i3(`move ${direction}`);
close => i3('kill');
}
window? move screen :i3screen => i3(`move container to workspace ${i3screen}`);
window move :i3screen => i3(`move container to workspace ${i3screen}`);
focus floating => i3('focus floating');
focus tiling => i3('focus tiling');
screen ...{
lock => multi(exec('lock'), new SleepCommand(true));
:i3screen => i3(`workspace ${i3screen}, focus tiling`);
brightness :number => exec(`brightness ${number}`);
previous => i3(`workspace prev, focus tiling`);
left => i3(`workspace prev, focus tiling`);
right => i3(`workspace next, focus tiling`);
move :i3screen => i3(`move container to workspace ${i3screen}`);
}
screen next? => i3(`workspace next, focus tiling`);
open terminal :folder? => exec(
`gnome-terminal --hide-menubar ` +
`--working-directory="${optional(folder, '/home/josh')}"`
);
open monitor grammar => exec(`gnome-terminal --hide-menubar -e "bash -i -c '~/pegvoice/src/check-results.js --watch'"`);
open monitor voice => exec(`gnome-terminal --hide-menubar -e "bash -i -c '~/pegvoice/src/check-results.js --watch'"`);
open grammar monitor => exec(`gnome-terminal --hide-menubar -e "bash -i -c '~/pegvoice/src/check-results.js --watch'"`);
open code grammar => exec('code --new-window ~/.pegvoice/grammar.pgv');
open code :folder? => exec(`code --new-window ${optional(folder, '/home/josh')}`);
open editor grammar => exec('code --new-window ~/.pegvoice/grammar.pgv');
open editor :folder? => exec(`code --new-window ${optional(folder, '/home/josh')}`);
open chrome? incognito => exec('google-chrome -incognito');
open chrome => exec('google-chrome');
call :ident => multi(type(`${ident}()`), key('left'));
string :keys => type("'" + keys + "'");
console log => type('console.log(');
arrow function => multi(type(' => '), key('shift-['), key('enter'));
arrow => type(' => ');
&slack ...{
pizza party => type(
':party-dino: ' +
':pizzaspin: :pizzaspin2: :antipizza: :pizzaspin3: :pizzaspin4:' +
' :party-dino:'
);
}
&bash ...{
copy => key('ctrl-shift-c');
paste => key('ctrl-shift-v');
delete line => multi(key('home'), key('ctrl-k'));
k:modified_key => key(k);
source rebase => type('git rebase -i HEAD~25');
source commit all => multi(type('git commit -a -m \'\''), key('left'));
source commit => multi(type('git commit -m \'\''), key('left'));
source diff letter => type('git diff --word-diff-regex=.');
source => type('git ');
def => type('diff ');
big option => type(' --');
option => type(' -');
equal => type('=');
less => type('less ');
ls => type('ls ');
run test => multi(type('authbox-test '), relpath('~/authbox/authbox-api/tests/~~'), key('tab'));
page up => key('shift-pageup');
page down? => key('shift-pagedown');
}
vscode_multi_select = ...{
multi_select all => vscode('editor.action.selectHighlights');
multi_select up => vscode('editor.action.insertCursorAbove');
multi_select down => vscode('editor.action.insertCursorBelow');
multi_select next? => vscode('editor.action.addSelectionToNextFindMatch');
}
vscode_edit_repeatable = ...{
dir:direction => vscodeSelectable('cursor' + upperFirst(dir));
cmd:vscode_multi_select => cmd;
paste => vscode('editor.action.clipboardPasteAction');
line above => vscode('editor.action.insertLineBefore');
line before => vscode('editor.action.insertLineBefore');
line_up => vscode('editor.action.insertLineBefore');
line below => vscode('editor.action.insertLineAfter');
line after => vscode('editor.action.insertLineAfter');
line down => vscode('editor.action.insertLineAfter');
move line_up => vscode('editor.action.moveLinesUpAction');
move line down => vscode('editor.action.moveLinesDownAction');
dedent => vscode('editor.action.outdentLines');
indent => vscode('editor.action.indentLines');
change word left => vscode('deleteWordLeft');
change word right? => vscode('deleteWordRight');
delete line => vscode('editor.action.deleteLines');
copy line ...{
down => vscode('editor.action.copyLinesDownAction');
up => vscode('editor.action.copyLinesUpAction');
}
}
vscode_select_command = ...{
grow => vscode(`editor.action.smartSelect.grow`);
shrink => vscode(`editor.action.smartSelect.shrink`);
line up => multi(vscode('cursorUpSelect'), vscode('cursorHomeSelect'));
line left => vscode(`cursorHomeSelect`);
line right => vscode(`cursorEndSelect`);
line down? => vscode('expandLineSelection');
dir:direction => vscode('cursor' + upperFirst(dir) + 'Select');
word left => vscode('cursorWordEndLeftSelect');
word right => vscode('cursorWordEndRightSelect');
column dir:direction => vscode('cursorColumnSelect' + upperFirst);
column => vscode('columnSelect');
}
&vscode ...{
save => vscode('workbench.action.files.save');
new => vscode('workbench.action.files.newUntitledFile');
select all => vscode('editor.action.selectAll');
explorer => vscode('workbench.files.action.focusFilesExplorer');
increment => vscodeVim('<C-a>');
decrement => vscodeVim('<C-x>');
close editor => vscode('workbench.action.closeActiveEditor');
close file => vscode('workbench.action.closeActiveEditor');
close messages => vscode('workbench.action.closeMessages');
editor group one => vscode('workbench.action.focusFirstEditorGroup');
editor group two => vscode('workbench.action.focusSecondEditorGroup');
editor group three => vscode('workbench.action.focusThirdEditorGroup');
toggle_any ...{
menu => vscode('workbench.action.toggleMenuBar');
terminal => vscode('workbench.action.terminal.toggleTerminal');
}
&=>vscodeMode('terminalFocus') ...{
terminal => vscode('workbench.action.terminal.toggleTerminal');
}
terminal => vscode('workbench.action.terminal.focus');
editor => vscode('workbench.action.focusActiveEditorGroup');
delete inside => multi(
vscode(`editor.action.smartSelect.grow`),
vscode('deleteRight')
);
focus ...{
explorer => vscode('workbench.view.explorer');
editor => vscode('workbench.action.focusActiveEditorGroup');
terminal => vscode('workbench.action.terminal.focus');
}
find => multi(
vscode('actions.find'),
modeOff('vscode-editorTextFocus'),
mode('vscode-findWidgetVisible')
);
&=>vscodeMode('suggestWidgetMultipleSuggestions') ...{
c:count dir:direction => repeat(c, key(dir));
dir:direction => key(dir);
tab => multi(
key('tab'),
modeOff('vscode-suggestWidgetMultipleSuggestions')
);
}
:count? again => repeat(optional(count, 1), new PreviousCommand());
multi select lines => vscode('editor.action.insertCursorAtEndOfEachLineSelected');
&=>vscodeMode('findWidgetVisible') ...{
regex => vscode('toggleFindRegex');
case_sensitive => vscode('toggleFindCaseSensitive');
next => vscode('editor.action.nextMatchFindAction');
previous => vscode('editor.action.previousMatchFindAction');
cmd:vscode_multi_select => cmd;
}
open next => vscode('workbench.action.nextEditorInGroup');
open => multi(
vscode('workbench.action.quickOpen'),
modeOff('vscode-editorTextFocus')
);
&=>vscodeMode('editorHasSelection') ...{
:count? cmd:vscode_select_command => repeat(optional(count, 1), cmd);
}
&=>vscodeMode('editorTextFocus') ...{
copy => vscode('editor.action.clipboardCopyAction');
jump => vscode('editor.action.jumpToBracket');
page up => vscode('cursorPageUp');
page down? => vscode('cursorPageDown');
}
&=>vscodeMode('editorTextFocus && !editorReadonly') ...{
undo => vscode('undo');
redo => vscode('redo');
cut => vscode('editor.action.clipboardCutAction');
home => vscodeSelectable('cursorHome');
end => vscodeSelectable('cursorEnd');
:count? cmd:vscode_edit_repeatable => repeat(optional(count, 1), cmd);
first_line => vscodeSelectable('cursorTop');
last line => vscodeSelectable('cursorBottom');
go to ...{
top => vscodeSelectable('cursorTop');
bottom => vscodeSelectable('cursorBottom');
line :number => multi(
vscode('workbench.action.gotoLine'),
type(`${number}\n`)
);
}
:count? select cmd:vscode_select_command => multi(
repeat(optional(count, 1), cmd),
mode('vscode-editorHasSelection')
);
comment line => vscode('editor.action.commentLine');
cmd:dictate_command => vscodeType(cmd);
}
!{vscodeMode('inDebugMode')} ...{
start debugging => vscode('workbench.action.debug.start');
}
cmd:dictate_command => cmd;
}
&chrome ...{
tab :number => key(`ctrl-${number}`);
switch tab => key('ctrl-9');
search :say? => multi(key('ctrl-k'), optional(say, noop()), say ? key('enter') : noop());
google :say? => multi(key('ctrl-k'), optional(say, noop()), say ? key('enter') : noop());
open tools => key('ctrl-shift-j');
close tools => key('ctrl-shift-j');
link => escaped(key('f'));
big link => escaped(key('F'));
close tab? => key('ctrl-w');
open tab? :website => multi(key('ctrl-t'), type(website), key('enter'));
open tab? => key('ctrl-t');
undo => key('ctrl-z');
tab => key('tab');
go_to ...{
top => type('gg');
bottom => type('G');
line :number => type(`:${number}`);
:website => multi(key('ctrl-l'), type(website), key('enter'));
:dictate => multi(key('ctrl-l'), dictate);
}
new tab :website => multi(key('ctrl-t'), type(website), key('enter'));
new tab => key('ctrl-t');
select all => key('ctrl-a');
next tab => key('ctrl-tab');
previous tab => key('ctrl-shift-tab');
reopen tab => key('ctrl-shift-t');
reopened at => key('ctrl-shift-t');
back => key('H');
forward => key('L');
refresh => key('ctrl-r');
l:letter => key(l);
k:modified_key => key(k);
hold key k:key => new KeyHoldCommand(k, true);
escape => multi(cancel(), key('escape'));
find :dictate? => multi(key('ctrl-f'), optional(dictate, noop()));
:dictate => dictate;
}
hold key k:key => new KeyHoldCommand(k, true);
cancel => cancel();
key k:key => key(k);
k:modified_key => key(k);
page up => key('pageup');
page down? => key('pagedown');
type :ascii_string => type(ascii_string);
dictate :dictate => dictate;
word :word => type(word);
&vimVisual ...{
swap corner => key('O');
swap => key('o');
change => multi(key('c'), modeOff('vim-visual'), mode('vim-insert'));
delete => multi(key('d'), modeOff('vim-visual'));
indent => multi(key('>'), modeOff('vim-visual'));
dedent => multi(key('<'), modeOff('vim-visual'));
format => multi(key('='), modeOff('vim-visual'));
replace k:key => multi(key('r'), key(k), modeOff('vim-visual'));
surround s:surrounder => multi(type(`S${s}`), modeOff('vim-visual'));
cut => multi(key('x'), modeOff('vim-visual'));
global yank => multi(type('"+y'), modeOff('vim-visual'));
sort => multi(type(':!sort\n'), modeOff('vim-visual'));
yank => multi(key('y'), modeOff('vim-visual'));
unique => multi(type(':!sort\ngv:!uniq\n'), modeOff('vim-visual'));
d:vim_direction => type(d);
undo => noop();
}
&vim ...{
exit without save => vimex('q!');
save exit => vimex('wq');
save as => escaped(type(':w '));
save => vimex('w');
switch buffer => escaped(repeat(2, key('ctrl-w')));
close buffer => vimex('bd');
flip => escaped(key('ctrl-6'));
}
&vimNotInsert ...{
f:vim_find empty line => type(`${f}^$\n`);
f:vim_find :dictate? => multi(type(f), optional(dictate, noop()));
previous => type('N');
next => type('n');
word => key('w');
forward until? c:ascii => type(`f${c}`);
back until? c:ascii => type(`F${c}`);
:direction :count => repeat(count, key(direction));
// Jumps to other side [bracket/etc]
jump => key('%');
mark :letter => type(`m${letter}`);
go_to ...{
top => type('gg');
bottom => type('G');
:letter => type(`'${letter}`);
}
}
&vimNormal ...{
open above => multi(type('O'), mode('vim-insert'));
open => multi(type('o'), mode('vim-insert'));
above => multi(type('O'), mode('vim-insert'));
append end => multi(type('A'), mode('vim-insert'));
append => multi(type('a'), mode('vim-insert'));
insert => multi(type('i'), mode('vim-insert'));
big replace => multi(type('R'), mode('vim-insert'));
:number => type(`${number}`);
create macro :letter => type(`q${letter}`);
macro :letter => type(`q${letter}`);
play :letter => type(`@${letter}`);
end macro => type(`q`);
big cut => type('x');
cut => type('x');
replace k:key => multi(key('r'), key(k));
paste from k:ascii => type(`${k}+p`);
big paste => type('P');
paste above => type('P');
paste => type('p');
repeat => type('.');
undo => type('u');
visual dir:vim_direction => multi(type(`v${dir}`), mode('vim-visual'));
visual block => multi(key('ctrl-v'), mode('vim-visual'));
visual line => multi(type('V'), mode('vim-visual'));
visual => multi(type('v'), mode('vim-visual'));
reselect => multi(type('gv'), mode('vim-visual'));
tree :folder? => vimex(`NERDTree ${optional(folder, '/home/josh')}`);
file :folder? => vimex(`FZF ${optional(folder, '/home/josh')}`);
big change => key('C');
change ...{
surrounding a:surrounder b:surrounder => type(`cs${a}${b}`);
line => multi(type('cc'), mode('vim-insert'));
dir:vim_direction => multi(type(`c${dir}`), mode('vim-insert'));
}
big delete => key('D');
delete ...{
line => type('dd');
surrounding s:surrounder => type(`ds${s}`);
dir:vim_direction => type(`d${dir}`);
}
big yank => key('Y');
yank ...{
line => type('yy');
dir:vim_direction => type(`y${dir}`);
}
indent ...{
line => type('>>');
dir:vim_direction => type(`>${dir}`);
}
dedent ...{
line => type('<<');
dir:vim_direction => type(`<${dir}`);
}
:editor_movement => editor_movement;
:ascii => key(ascii);
}
&vimTree ...{
change :number => type(`:${number}\nC`);
change => type('C');
open :number => type(`:${number}\no`);
open => type('o');
tree :folder? => vimex(`NERDTree ${optional(folder, '/home/josh')}`);
}
&vimRebase ...{
cmd:rebase_command => multi(type(`cw${cmd}`), key('escape'), key('enter'));
}
&vimInsert ...{
node require :ident => typeLine(`const ${ident} = require('${ident}');`);
delete => key('delete');
paste editor => multi(key('ctrl-r'), key('"'));
paste clipboard? => multi(key('ctrl-r'), key('*'));
escape => multi(cancel(), key('escape'));
:dictate => dictate;
}
enter => key('enter');
undo => key('ctrl-z');
redo => key('ctrl-r');
escape => multi(cancel(), key('escape'));
slap it? => key('enter');
&bash cmd:dictate_command => cmd;
/*****
HELPERS
*****/
folder = ...{
box :authbox_folder => `/home/josh/authbox${authbox_folder}`;
box => `/home/josh/authbox`;
voice => "/home/josh/pegvoice/src";
}
authbox_folder = ...{
lib => "/authbox-api/lib";
tests => "/authbox-api/tests";
apps => "/apps";
s => "/apps/s";
sierra => "/apps/s";
config => "/config";
}
i3screen = ...{
dash => '-';
equal => '=';
:number => number;
}
website = ...{
calendar => 'https://google.com/calendar';
news => 'https://news.ycombinator.com';
fast mail => 'https://www.fastmail.com';
google calendar => 'https://google.com/calendar';
google flights => 'https://www.google.com/flights';
google => 'https://www.google.com';
gmail => 'https://mail.google.com';
reddit :word? => (
"https://www.reddit.com" + (word ? `/r/${optional(word)}` : '')
);
slack => 'https://smyte.slack.com/messages';
}
:editor_movement => editor_movement;
/***
DEFINITIONS
***/
_modified_key
= capital _ k:_key { return `shift-${k}`; }
/ alt _ k:_key { return `alt-${k}`; }
/ control _ alt _ k:_key { return `ctrl-alt-${k}`; }
/ control _ k:_key { return `ctrl-${k}`; }
/ shift k_ :_key { return `shift-${k}`; }
_editor_movement = count:(_count _) k:(_direction / backspace / space / slap) {
return repeat(extractOptional(count, 0, 1), key({
slap: 'enter',
}[k] || k));
}
:direction => key(direction);
:count :direction => repeat(count, key(direction));
backspace => key('backspace');
:count backspace => repeat(count, key('backspace'));
_vim_find = find prev:(_ previous)? {
return prev ? '?' : '/';
}
_vim_direction = pos:((_vim_inside / _vim_around) _)? dir:(
word / _paren / _vim_until / _vim_including / _surrounder
) {
return extractOptional(pos, 0, '') + ({
word: 'w',
}[dir] || dir);
}
_vim_inside = (inner / inside / in) { return 'i'; }
_vim_around = (around / outside) { return 'a'; }
_vim_including = (including) _ code:_ascii {
return `f${code}`;
}
_vim_until = (to / until) _ code:_ascii {
return `t${code}`;
}
_vscode = &{
return options.mode.has('vscode');
};
_chrome = &{
return options.mode.has('chrome');
};
_slack = &{
return options.mode.has('slack');
};
_vim = &{
return options.mode.has('vim');
};
_vimNormal = &{
return (
options.mode.has('vim') &&
!options.mode.has('vim-insert') &&
!options.mode.has('vim-tree') &&
!options.mode.has('vim-visual')
);
};
_vimNotInsert = &{
return (
options.mode.has('vim') &&
!options.mode.has('vim-insert')
);
};
_bash = &{
return (
options.mode.has('terminal') ||
options.mode.has('vscode-terminalFocus')
);
};
_vimInsert = &{
return options.mode.has('vim-insert');
};
_vimVisual = &{
return options.mode.has('vim-visual');
};
_vimTree = &{
return options.mode.has('vim-tree');
};
_vimRebase = &{
return options.mode.has('vim-rebase');
};
_direction = (up / down / left / right);
_keys = head:_key "."? tail:(_ _key "."?)* {
return [head, ...extractList(tail, 1)];
}
_say = words:_say_words {
return type(words.join(' '));
}
_say_words = head:_word tail:_say_word* (_ unsay)? {
return [head, ...tail];
}
_say_word = _ !unsay w:_word { return w; }
_dictate = head:_dictate_command tail:(_ _dictate_command &_)* {
return multi(head, ...extractList(tail, 1));
}
_dictate_command
= d:_special_dictate { return d; }
/ k:_dictate_keys { return k; }
/ joiner:_dictate_joiner _ words:_say_words {
words = flatten(words.map(w => w.toLowerCase().split('-')));
return type(joiner(words));
}
/ i:_ident_word { return type(i); }
_dictate_joiner
= big:(big _)? camel {
return (words => camel(words, big || false));
}
/ snake { return snake; }
_dictate_compare = w:(greater / less) equal:((_ or)? _ equal)? {
return type(' ' + ({
greater: '>',
less: '<',
}[w]) + (equal ? '=' : '') + ' ');
}
dictate_keys = ...{
k:modified_key => key(k);
:count d:dictate_repeatable => repeat(count, d);
k:non_digit_key => key(k);
page => key('pagedown');
d:dictate_repeatable => d;
}
special_dictate = ...{
:special_word => type(special_word);
:dictate_compare => dictate_compare;
say :say => say;
word :word => type(word);
type s:ascii_string => type(s);
key k:key => key(k);
at me => type('@yud.co.za');
ellipsis => type('...');
comma slap => type(',\n');
comma => type(', ');
lee => type('let ');
const => type('const ');
finish => type(';\n');
class words:say_words => type('class ' + camel(words, true));
}
special_word = ...{
dotcom => '.com';
equal_to => ' === ';
equal => ' = ';
not_equal => ' !== ';
greater => ' > ';
less => ' < ';
arrow => ' => ';
or => ' || ';
and => ' && ';
comment => '// ';
to do => '@TODO';
}
_dictate_repeatable = k:(_direction / backspace / space / slap / delete) {
return key({
slap: 'enter',
}[k] || k);
}
_ident = _ident_word
_ident_word
= n:_ident_number { return n; }
/ w:_word { return w.toLowerCase(); };
_ident_number = (number _)? head:_number tail:(_ _number)* &_ {
return [head, ...extractList(tail, 1)].join('');
}
word = ...{
smyte => 'smyte';
trace => 'trc';
:anything => anything;
}
_anything = (!_ .)+ &_ {
// Take the first entry dragon returns
return text().split('\\')[0].toLowerCase();
}
_rebase_command = (pick / squash / reword / edit / drop);
_key "<key>"
= _non_digit_key
/ _digit;
_non_digit_key "<key>"
= enter
/ escape
/ backspace
/ home
/ end
/ pageup
/ pagedown
/ _paren
/ _direction
/ _non_digit_ascii;
paren = ...{
left_curly => '{' || 'balance }';
left_paren => '(';
left_square => '[';
left_triangle => '<';
right_curly => !'balance {' || '}';
right_paren => ')';
right_square => ']';
right_triangle => '>';
}
_ascii_string = head:_ascii tail:(_ _ascii)* {
return [head, ...extractList(tail, 1)].join('');
}
_ascii "<ascii>" = _digit / _non_digit_ascii;
non_digit_ascii "<ascii nd>" = ...{
and => '&';
at => '@';
backslash => '\\';
backtick => '`';
big_quote => '"';
caret => '^';
colon => ':';
comma => ',';
dash => '-';
dollar => '$';
equal => '=';
exclamation => '!';
greater => '>';
hash => '#';
less => '<';
percent => '%';
period => '.';
pipe => '|';
plus => '+';
question => '?';
quote => '\'';
semicolon => ';';
slash => '/';
space => ' ';
star => '*';
tab => '\t';
tilde => '~';
underscore => '_';
:paren => paren;
:right_paren => right_paren;
:letter => letter;
}
_letter = _phonetic_letter / _alphabet_letter;
_phonetic_letter = capital:((big / capital) _)? code:(
alfa /
bravo /
charlie /
delta /
echo /
foxtrot /
golf /
hotel /
india /
juliett /
kilo /
lima /
mike /
november /
oscar /
papa /
quebec /
romeo /
sierra /
tango /
uniform /
victor /
whiskey /
xray /
yankee /
zulu
) &_ {
const letter = code.charAt(0).toLowerCase();
return capital ? letter.toUpperCase() : letter;;
};
_alphabet_letter = capital:((big / capital) _)? letter:(
a / b / c / d / e / f / g / h / i / j / k / l / m /
n / o / p / q / r / s / t / u / v / w / x / y / z
) {
if (text().includes('uppercase-letter')) {
capital = true;
}
return capital ? letter.toUpperCase() : letter.toLowerCase();
};
// @TODO: This doesn't work unfortunately
_repeat = count:(_count _)? {
if (count) {
return ((cmd) => repeat(count[0], cmd));
} else {
return (cmd => cmd);
}
}
_count = _tuple_length / _number;
_tuple_length = length:(single / double / triple) &_ {
return {
"single": 1,
"double": 2,
"triple": 3,
}[length];
}
_number = _number_hundred_word / _number_hundred / _number_ten;
_number_hundred_word = a _ hundred { return 100; }
_number_hundred = hundred:(_number_ten _ "hundred" (_ "and")?) ten:(_ _number_ten)? {
let number = 0;
if (hundred) {
number += hundred[0] * 100;
}
return number + (ten ? ten[1] : 0);
}
_number_ten = _number_ten_word / _number_ten_combo / _digit;
number_ten_word = ...{
ten => 10;
eleven => 11;
twelve => 12;
thirteen => 13;
fourteen => 14;
fifteen => 15;
sixteen => 16;
seventeen => 17;
eighteen => 18;
nineteen => 19;
}
number_ten_combo_word = ...{
twenty => 20;
thirty => 30;
fourty => 40;
fifty => 50;
sixty => 60;
seventy => 70;
eighty => 80;
ninety => 90;
}
_number_ten_combo = word:_number_ten_combo_word digit:(_ _digit)? {
return word + (extractOptional(digit, 1) || 0);
}
_digit = word:(
one / two / three / four / five /
six / seven / eight / nine / naught / zero /
"1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "0"
) _dragon? {
const digits = {
"one": 1,
"two": 2,
"three": 3,
"four": 4,
"five": 5,
"six": 6,
"seven": 7,
"eight": 8,
"nine": 9,
"zero": 0,
"naught": 0,
};
return digits.hasOwnProperty(word) ? digits[word] : parseInt(word, 10);
}
surrounder = ...{
p:right_paren => p;
backtick => '`';
quote => "'";
big quote => '"';
}
_right_paren = char:(
curly /
paren /
square /
triangle
) &_ {
return {
/* { <= needed for peg rule parsing bug */
curly: '}',
paren: ')',
square: ']',
triangle: '>',
}[char];
}
left_curly = (left _ curly / "{" _dragon?) &_ { return "left_curly"; }
left_paren = (left _ paren / "(" _dragon?) &_ { return "left_paren"; }
left_square = (left _ square / "[" _dragon?) &_ { return "left_square"; }
left_triangle = (left _ triangle / "<" _dragon?) &_ { return "left_triangle"; }
right_curly = (right _ curly / "}" _dragon?) &_ { return "right_curly"; }
right_paren = (right _ paren / ")" _dragon?) &_ { return "right_paren"; }
right_square = (right _ square / "]" _dragon?) &_ { return "right_square"; }
right_triangle = (right _ triangle / ">" _dragon?) &_ { return "right_triangle"; }
spell exit / x it;
spell undo / and do / under;
spell equal_to / equal to;
spell big_quote / big quote;
spell not_equal / not equal;
spell a;
spell alt;
spell and;
spell apps;
spell around;
spell arrow;
spell assign / the sign / and signed;
spell at;
spell backslash / "\\" / "\\backslash\\backslash";
spell backspace / back space / that space / backtrace;
spell backtick / "`\\backquote\\back tick";
spell b / be;
spell box;
spell capital;
spell caret / carrot / "^\\caret\\caret";
spell close / closed;
spell colon / ":";
spell comma / ",";
spell config;
spell control;
spell create / great / created;
spell c / see;
spell curly;
spell d;
spell dash / "-" / "–\\dash\\dash";
spell dedent / decent / "didn't" / the dent;
spell dictate / dictates;
spell diff / def / differential / dif / diffs;
spell do;
spell dollar;
spell dotcom / ".com\\\\dot com";
spell double;
spell down / dance;
spell drop;
spell e;
spell edit;
spell eight / it;
spell eighty;
spell ellipsis / "…";
spell end;
spell enter / inter / into / "\\new-line\\new line";
spell equal / equals;
spell escape / escaped;
spell exclamation;
spell f;
spell fifty;
spell find;
spell five;
spell focus / focused;
spell forward;
spell four / for;
spell fourty / forty;
spell g;
spell gmail;
spell go_to / go to / good;
spell go_to_sleep / go to sleep / good asleep;
spell greater / grader / grade or;
spell h;
spell hash;
spell home;
spell hundred;
spell i;
spell in;
spell including;
spell indent;
spell inner / in a;
spell inside;
spell j;
spell k;
spell key / he;
spell l / al;
spell lee / leigh / li / leave;
spell left;
spell less;
spell letter / letters;
spell lib / lab;
spell line / lines;
spell m;
spell me;
spell n;
spell naught / nought;
spell news / new / new is;
spell nine;
spell ninety;
spell not;
spell number;
spell one;
spell o / oh;
spell open / opened;
spell or;
spell outside;
spell p;
spell pagedown / page down;
spell pageup / page up;
spell paren / parental / prevent;
spell paste / based;
spell percent;
spell period / "." / ".\\dot\\dot";
spell pick / pip;
spell pipe;
spell plus;
spell q;
spell question;
spell quote / quotes;
spell r / are;
spell rebase / "we base";
spell reddit / redick;
spell reopen / reopened;
spell reword;
spell right / write / rights;
spell s;
spell save / safe / saved;
spell say / save;
spell screen / green;
spell semicolon / ";";
spell seven;
spell seventy;
spell shift;
spell single;
spell six;
spell sixty;
spell slash / "/" / "/\\slash\\slash";
spell smyte / smite;
spell space;
spell square;
spell squash;
spell star;
spell t;
spell tab / "\\tab-key\\tab key";
spell ten;
spell tests;
spell than;
spell thirty;
spell three;
spell tilde / "~\\tilde\\tilde";
spell to / do;
spell tree / treat;
spell triangle;
spell triple;
spell twenty;
spell two / to;
spell u;
spell under;
spell underscore / "_" / "_\\underscore\\underscore";
spell unsay / under say / and say;
spell until;
spell up;
spell v / the;
spell voice;
spell w;
spell wake_up / wake up / "wake-up" / "wake up";
spell window / windows;
spell word / words;
spell x;
spell y;
spell yank / copy;
spell zero;
spell z / said;
spell ls / ellis;
spell multi / "multi-";
spell regex / rejects;
spell case_sensitive / "case-sensitive";
spell camel;
spell snake;
spell line_up / line up / lineup;
spell multi_select / multi cursor / multi select;
spell visual / select;
spell commit / comma it;
spell first_line / "first-line" / first line;
spell toggle_any / toggle / open / close / show;
spell alfa / alpha / offer / of the;
spell bravo / brother;
spell charlie;
spell delta;
spell echo / easy;
spell foxtrot;
spell golf;
spell hotel;
spell india;
spell juliett / juliet;
spell kilo;
spell lima;
spell mike;
spell november;
spell oscar;
spell papa / pepper;
spell quebec / "québec";
spell romeo;
spell sierra / c error / ciera;
spell tango;
spell uniform;
spell victor;
spell whiskey;
spell xray / "x-ray";
spell yankee;
spell zulu / sooner;
_dragon = "\\" (!_ [ -~])+ &_;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment