VSCodeを起動してjournal.todayコマンドを実行すると、数秒待たされる。原因はmdファイルを初めて開いた時にMarkdown関係の拡張が有効化されるが、それが終わるまでコマンドが完了しないため。
普通にmdファイルを開くと、ファイルを開いて編集可能になってから拡張の読み込みが始まるので待たされていると感じない。この快適さがほしい。
vscode-journalで使うファイルの拡張子をmd以外にするとか、Markdownの拡張を減らすという回避策もあるけど、それは残念感が強い。Emacsのごとく最初だけなんだから気にしない、というのがベターっぽいけども、暇なので少し調べてみた。
ソースを見るとどうやら:
const doc = await vscode.workspace.openTextDocument(path);
vscode.window.showTextDocument(doc);
みたいなコードを実行すると拡張の読み込みが終わるまで処理を返さないらしい。VSCodeにわかなので何もわからないのだけど、openTextDocumentを待たずにonDidOpenTextDocumentイベントを使うといいのだろうか?
いっちょvscode-journalのソース書き換えてPRでも送ってみようかと思ったけど、ソースを読むとopenTextDocumentの戻り値で得られるドキュメントにテンプレート書き込んだりしていて、案外変更量多くなりそう……と気付いたらvscode-powertoolsで自前のコマンドを作ってしまいました。VSCodeではファイルを開く方法がいくつかあるみたいで、上記の他に
vscode.commands.executeCommand("vscode.open", vscode.Uri.file(ファイル名));
でも開けて、こちらは拡張の読み込みを非同期で行ってくれるバージョンのようなので、こっちを使ったコマンドを作ってみました。
journal.js
Power Tools - Visual Studio Marketplace
まずPower Toolsをインストールして、 ~/.vscode-powertools/直下にjournal.jsファイルを作ります。
function getJournalFile(args, offset) {
const vscode = args.require('vscode');
const path = args.require('path');
const moment = args.require('moment');
const config = vscode.workspace.getConfiguration("journal");
moment.locale(config.get('locale'));
const base = config.get('base');
const ext = config.get('ext');
const day = moment(Date.now()).add(offset, 'days');
const parent = path.join(base, day.format('YYYY'), day.format('MM'));
return [day, parent, path.join(parent, `${day.format('YYYYMMDD')}.${ext}`)];
}
async function openJournal(args, offset) {
const vscode = args.require('vscode');
const fs = args.require('fs');
const fsExtra = args.require('fs-extra');
const [day, parent, fileName] = getJournalFile(args, offset);
if (!fs.existsSync(fileName)) {
fsExtra.mkdirpSync(parent);
const config = vscode.workspace.getConfiguration("journal");
let template = config.get('tpl-entry');
template = template.replace('${localDate}', day.format('LL'));
template = template.replace('${weekday}', day.format('dddd'));
fs.writeFileSync(fileName, template, err => console.error(err));
}
await vscode.commands.executeCommand("vscode.open", vscode.Uri.file(fileName));
}
async function pickJournalOffset(args) {
const disposables = [];
try {
return await new Promise((resolve, _) => {
const vscode = args.require('vscode');
const input = vscode.window.createQuickPick();
input.items = [
{label: 'Today', parsedInput: 0, alwaysShow: true},
{label: 'Yesterday', parsedInput: -1, alwaysShow: true},
{label: 'Tomorrow', parsedInput: +1, alwaysShow: true}
];
input.onDidAccept(() => {
const offset = input.value.length === 0 ? input.selectedItems[0].parsedInput : parseInt(input.value);
resolve(offset);
}, disposables);
input.onDidHide(() => {
input.dispose();
}, disposables);
input.show();
});
} finally {
disposables.forEach(d => d.dispose());
}
}
exports.getJournalFile = (args, offset) => {
const arr = getJournalFile(args, offset);
return arr[arr.length - 1];
}
exports.open = async (args, offset) => {
openJournal(args, offset);
};
exports.execute = async args => {
const offset = await pickJournalOffset(args);
openJournal(args, offset);
};
settings.jsonにコマンドを追加。
"ego.power-tools.user": {
"commands": {
"myjournal.open": {
"name": "Open Journal file",
"script": "journal.js",
},
}
}
keybindings.jsonにショートカットを追加。
{
"key": "ctrl+shift+j",
"command": "myjournal.open"
},
これでCtrl+Shift+Jを押すとメニューが表示され、選んだ日のファイルが開けます(なければ作る)。
journal-prev.js
ついでに「今開いているファイルの1日前のファイルを探して開く」コマンドも作りました。Ctrl+Shift+Alt+Pにショートカットを割り当てて、連打すると昨日のファイル、一昨日のファイル、一昨昨日のファイル…と辿って見られるようにしました。あれ何日前に書いたメモだっけ、みたいな捜し物をするときに使います。(こういうの、howmとかなら検索で解決するんだろうなぁ)
exports.execute = async args => {
const vscode = args.require('vscode');
const fs = args.require('fs');
const path = args.require('path');
const journal = require('./journal.js');
const currentFile = vscode.window.activeTextEditor.document.uri.path;
let offsetDays = 0;
if (currentFile) {
const fileName = path.basename(currentFile, path.extname(currentFile));
const date = new Date(`${fileName.substr(0, 4)}-${fileName.substr(4, 2)}-${fileName.substr(6, 2)}`);
offsetDays = Math.round((Date.now() - date.getTime()) / (1000*60*60*24));
}
for (let i = 1; i <= 10; ++i) {
const offset = -(i + offsetDays);
const fileName = journal.getJournalFile(args, offset);
if (fs.existsSync(fileName)) {
vscode.commands.executeCommand("vscode.open", vscode.Uri.file(fileName));
return;
}
}
};
"ego.power-tools.user": {
"commands": {
"myjournal.previous": {
"name": "Open Previous Journal file",
"script": "journal-prev.js",
}
}
}
{
"key": "ctrl+shift+alt+P",
"command": "myjournal.previous",
}