Stackを使ってscrapVimを作れないか
試したこと
何がだめだったか
dd
と d
など、一部が重複するキーの区別ができない
esc
キーが効かない
考えたこと
keyboardのemulation
これは別機能として設計・テストする
classの設計
keyをためるとこ
キーを監視するとこ
キーからコマンドを解釈するとこ
コマンドを実行するとこ
実際のカーソル操作をやるとこ
その他
レジスタ
key mapの読み込み
どうコマンドを実行するか
コマンドの実行は別phaseだ
classを分けよう
完全一致する候補がひとつだけのとき
直ちにコマンドを確定・実行する
複数の候補があるとき
しばらく経ったら最初にマッチした候補で確定する
例: j
と jj
という2つのコマンドを定義していたとき
operatorの範囲入力待ち
入力されるまで待つ
commandの並びが無効、つまりどれとも一致しなかったら終了する
stackを空にする
予めコマンド候補を作っておく必要がある
mock2.jsconst commandList =[
['h'],
['d','d']
]
↑これはだめだ
operatorやmotionと、色んな種類のcommandがある
commandごとに分けたほうが良い
構文解析っぽくやる?
e.g d
の後はmotionか d
かtext objectのどれかがくる。それ以外の場合は終了
設定ファイルでカスタマイズしたmappingも反映させる
これは一旦後回しにしよう
stackはリスト形式にする
Vim記法のkey codeでどんどんためていく
コマンド実行後にクリアする
mock1.jsimport {isMobile} from '/api/code/takker/mobile版scrapboxの判定/script.js';
export class KeyStack {
constructor() {
if (isMobile()) {
this._enabled = false;
return;
}
this._enabled = true;
this._stack = [];
this._editor = document.getElementById('editor');
this.onstackupdate = undefined;
this.onflush = undefined;
}
// keyの監視を開始。
start() {
if (!this._enabled) return;
this._editor.addEventListener('keydown', e =>{
const keymap = convertKeyCode(e.key, e);
if (keymap === '') return;
this.push(keymap);
});
this._editor.addEventListener('stackupdate', e => this.onstackupdate(e));
this._editor.addEventListener('stackflush', e => this.onflush(e));
}
stop(){}
// keyをstackする
// 配列を使って複数のkeysを一度に入れられる
push(...keys) {
this._stack.push(keys);
// キーが追加されたというeventを発火する
this._editor.dispatchEvent(
new CustomEvent('stackupdate', {
bubbles: true,
detail: { stack: [...this._stack], newKeys: [...keys] } }));
}
// stackの中身を出しつつ、this_stackを空っぽにする
flush() {
this._editor.dispatchEvent(
new CustomEvent('stackflush', {
bubbles: true,
detail: { stack: [...this._stack] } }));
this._stack = [];
}
}
printable key以外は無視
mock1.jsexport function convertKeyCode(key, {ctrlKey,shiftKey,altKey}) {
// 文字入力の場合
if (key.length === 1 && key !== ' ') {
// どれか一つのmeta keyしか有効にしない
if (altKey) return `<A-${key}>`;
if (ctrlKey) return `<C-${key}>`;
return key;
// Shift keyの情報は文字に反映されているので何もしない
}
// 特殊なキー
const specialKeys = {
Backspace: 'BS',
Tab: 'Tab',
Enter: 'CR',
Delete: 'Del',
Escape: 'Esc',
' ': 'Space',
PageUp: 'PageUp',
PageDown: 'PageDown',
End: 'End',
Home: 'Home',
ArrowLeft: 'Left',
ArrowUp: 'Up',
ArrowRight: 'Right',
ArrowDown: 'Down',
F1: 'F1',
F2: 'F2',
F3: 'F3',
F4: 'F4',
F5: 'F5',
F6: 'F6',
F7: 'F7',
F8: 'F8',
F9: 'F9',
F10: 'F10',
F11: 'F11',
F12: 'F12',
};
if (specialKeys[key]) {
// どれか一つのmeta keyしか有効にしない
if (altKey) return `<A-${specialKeys[key]}>`;
if (ctrlKey) return `<C-${specialKeys[key]}>`;
if (shiftKey) return `<S-${specialKeys[key]}>`;
return `<${specialKeys[key]}>`;
}
return '';
}
見た目
mock1.css#scrapvim-status-bar.status-bar {
border: solid 1px #888;
color: #b5b5b5;
}
mock1.js
のテストコード
mock1-test.jsimport {KeyStack} from '/api/code/takker/Stackを使ってscrapVimを作れないか/mock1.js';
const app = document.getElementsByClassName('app')[0];
app.insertAdjacentHTML('beforeend', `
<style>
@import '/api/code/takker/Stackを使ってscrapVimを作れないか/mock1.css';
</style>
`);
const scrapVimStatusBar = document.createElement('div');
scrapVimStatusBar.id = 'scrapvim-status-bar';
scrapVimStatusBar.classList.add('status-bar');
app.appendChild(scrapVimStatusBar);
const keyStack = new KeyStack();
keyStack.onstackupdate = e => {
// Escapeを押したらflushする
if (e.detail.newKeys.includes('<Esc>')) {
keyStack.flush();
return;
}
console.log(e);
scrapVimStatusBar.textContent = e.detail.stack.join('');
};
keyStack.onflush = e => {
console.log(e);
scrapVimStatusBar.textContent = '';
};
keyStack.start();
11:33:34 stackはこれでよさそう
実行方法
1文字移動→矢印キー
単語移動→ ctrl
+ ←
→
ただこれをやると、visual modeで <
>
をつかったインデントの上げ下げが難しくなる
W/E/f/text object
特定の文字を探す
探した文字がcursorから何文字前/後ろにあるかを計算する
削除
Delete
と Backspace
連打
切り取り
Shift
+矢印キーで範囲選択してから Delete
貼り付け
レジスタの値を流し込む
ctrl
+ v
を実行できないので、clipboardから貼り付けるのは困難かも
リンクをクリック
DOMから検索
cursorの位置と座標を比較する
一番近い文字を探す
範囲選択
ふつうの & 行選択
Shift
+矢印キー
<
>
用に、選択されている行を記憶しておく必要がある
実装するコマンド
d
y
c
p
~
<>
hjkl
gg
G
^0$
wWbBeE
ge
gE
(){}
%HML
f{char}
.
a
i
s
scroll
<c-d><c-f>
<c-u><c-b>
register
"a, "b, ...