概要
ふと、VSCode の潤沢なテキストエリアに sl を走らせたくなったので、拡張を作った。
実行したときの絶望感を高めるため、 sl が通ったところの文章は消滅する仕様とした。(※ Undo で復活可)
余談: UNIX コマンド sl(1) の生い立ち
lsコマンドを実行しようとしてslとミスタイプすることがしばしばある。そのような場合、コンピュータは「sl」という存在しないコマンドを求めてシステムを全検索してしまい、70年代から80年代当時の処理能力の遅いコンピュータではそれにしばらく時間がかかり、作業が中断してしまうことがあった。そこでそれを防ぐため、「sl」と言う名のダミーのプログラムを用意することがあった[要出典]。
このslも、そういったダミープログラムの一つであるといえるが、ミスタイプによってロスする時間(現代においては殆ど一瞬である)よりも、SLが走り抜けるのを待っている時間のほうが長いなど、ジョークプログラムとしての性格が強い。
当時と比べるとマシン性能が格段に速くなったため、ミスタイプで「作業が中断」する光景がなかなか想像しにくい昨今ではある。だからこそ sl の歴史を深ぼっていくことで、「ダミープログラムを作って回避する」といった当時の知恵・工夫に思いを馳せたいところである。(ダミープログラム云々は要出典ではあるが)
本題: VSCode で走らせる
ソースコード
実装のポイント
TextEditorEdit.edit() をループさせるときは async/await
edit() をループして sl を動かすために、edit() を await する必要がある。
let editor = vscode.window.activeTextEditor;
for (...) {
editor.edit(...); // NG
await editor.edit(...); // OK
await setTimeout(config.refreshRateMs);
}
TextEditorEdit.edit() の undoStopBefore を適切に設定する
デフォルトでは 100 回分ループしてテキストエリアを書き換えているが、Undo してもとに戻したい場合は 100 回 Undo する必要があり、不便。
そこで edit() の第二引数 options
に undoStopBefore = false を渡すことで、このときの edit の結果を Undo の対象から外すことができる。
sl-vscode では、初回 (i=0) のループ時のみ undoStopBefore = true とし、それ以降は false とすることで、Undo 1 回で sl 前の状態に戻すことができる。
await editor.edit(..., { undoStopBefore: i == 0 });
TextEdit.replace() で複数行 replace する場合は Range の行数と書き換えテキストの行数を合わせる
TextrEditorEdit.edit() のコールバック内で使うことの多い replace() だが、第一引数には Range オブジェクトを指定する。
Range は一行にすることも複数行にすることも可能だが、
- Range の行数
- 書き換えテキストの行数
が一致しないと、書き換えの挙動がおかしくなることがある。例えば「書き換え後に不要な空行が追加される」など。
むすび
VSCode で sl が動かせたからといって何も得することはないのだが、冒頭で述べたように当時の時代背景と sl の関わりについて知ることができたのはよかった。
本家 sl には ls と同様のオプション (e.g. -a
, -l
, -F
) が用意されており、オプションによって登場する汽車に変化が生じるギミックとなっているため、今後の予定としてこれらオプションの実装をしていきたい。