何も考えずに使ったらハマったのでメモ。
int? foo = null; (5 + foo ?? 0); // => "5"を期待したけど"0"になる
これは:
(5 + (foo ?? 0)); // => 5
と書きましょう。StyleCopで乗算や除算には問答無用で括弧を付けろと言われる環境なので油断していました(何も言われないので)。
何も考えずに使ったらハマったのでメモ。
int? foo = null; (5 + foo ?? 0); // => "5"を期待したけど"0"になる
これは:
(5 + (foo ?? 0)); // => 5
と書きましょう。StyleCopで乗算や除算には問答無用で括弧を付けろと言われる環境なので油断していました(何も言われないので)。
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(ファイル名));
でも開けて、こちらは拡張の読み込みを非同期で行ってくれるバージョンのようなので、こっちを使ったコマンドを作ってみました。
Power Tools - Visual Studio Marketplace
まずPower Toolsをインストールして、 ~/.vscode-powertools/直下にjournal.jsファイルを作ります。
// ~/.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')); // journal.locale const base = config.get('base'); // journal.base const ext = config.get('ext'); // journal.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'); // journal.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にコマンドを追加。
// 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を押すとメニューが表示され、選んだ日のファイルが開けます(なければ作る)。
ついでに「今開いているファイルの1日前のファイルを探して開く」コマンドも作りました。Ctrl+Shift+Alt+Pにショートカットを割り当てて、連打すると昨日のファイル、一昨日のファイル、一昨昨日のファイル…と辿って見られるようにしました。あれ何日前に書いたメモだっけ、みたいな捜し物をするときに使います。(こういうの、howmとかなら検索で解決するんだろうなぁ)
// ~/.vscode-powertools/journal-prev.js 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; // today if (currentFile) { // YYYYMMDD -> YYYY-MM-DD (決め打ち) 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)); } // 直近10日前まで遡って、最初に見つかったファイルを開く // (getJournalFileの効率が悪いし、1ヶ月空いてもいいようにしたいし、もうちょっとうまくやりたい) 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; } } };
// settings.json "ego.power-tools.user": { "commands": { "myjournal.previous": { "name": "Open Previous Journal file", "script": "journal-prev.js", } } }
// keybindings.json { // Ctrl+Shift+Alt+←(right) にしようとしたらなぜか動かない🤔 "key": "ctrl+shift+alt+P", "command": "myjournal.previous", }
角川文庫・ラノベ 読み放題|1万冊以上のライトノベル・角川文庫が月額760円(税抜)から読み放題!電子書籍ならBOOK☆WALKER
いわゆるサブスク。月760円+税で一定の本が読み放題になる。月2冊くらい読めば元が取れるので、結構お得なのではなかろうか。
しかし音楽にしろ動画にしろ、ユーザにとってはいいけど定額制でちゃんと儲かるんだろうか…と余計な事を気にしてしまう。このサービスの場合、シリーズものの最初の方だけ読めるようになっているものがあって、いわゆる体験版とか試し読みサービスとして考えるとアリなのかな? という気もする。
1月まで無料で試せると言うことでとりあえず加入してみたけど、今のところブラウザでしか読めないみたいで、AndroidのBook WalkerアプリでもWebView経由になってしまうのが惜しい。PCで読むならいいんだけど、スマホ版はもう少し使いやすくしてほしいな。アプリのリーダーで読ませる場合本のダウンロードが必要で、そうなると「読み放題でなくなった本をどう扱うか」みたいな問題がありそうで簡単ではないかもしれないけど。
小学生の頃は冬でも半袖みたいな子供だったけど、徐々に寒さに弱くなってきて着る物が増えていっています。常にセーターとか上着用意したり、最近は指の部分だけ露出した手袋という中二っぽいアイテムも買ってしまった。指先が出ていても、手の平や手首を暖められるだけでも結構違うみたいで、案外良いです。
フリーノット(FREE KNOT) レイヤーテック インナーグローブ LFサイズ ブラック Y4601A-LF-90
寒がりになったの、なぜか30過ぎてから平熱が37度代になったのも影響しているのだろうか。そのおかげか風邪は全然引かなくなりましたが、もともと暑いのがダメで夏が苦手なのに冬もダメになってきて困ります。
xyzzyというエディタのcalmemoという拡張を2009年くらいから、かれこれ10年使い続けている。
日記帳みたいなもので、コマンドを実行すると今日の日付のテキストファイルを作ってくれてそこに何か書ける、というもの。それに検索とかカレンダー機能などが付いている。xyzzy自体は学生の頃からなので20年近く使い続けているけど、そんな昔からあるアプリだけあって非常に軽量で使いやすく、日報とかまとめるのに使っていました。令和になった今でも、Windows 10でも当たり前のように動くし特に不満もなかったのですが、最近絵文字入れたいよなぁ……と思うようになり、VSCodeで書こうかな、と考え表題に。
vscode-journalはVSCodeの拡張で、これもコマンドを実行すると今日の日付のファイルを作ってくれるもの。ほぼ書くだけの用途にしか使っていなかったので、機能的には十分そうです。
アプリも何年も使っていると愛着が湧くのか乗り換えるのに妙に抵抗を感じてしまうものですが、フォルダ構成やファイル名のルールを合わせておけばこれまでのcalmemoのログと同じところにログを残せるし、エイヤで乗り換えてしまおう。
vscode-journalにカレンダーはないけど、vscode-jounal-viewという別の拡張を入れるとサイドバーにツリー形式で既存のログを一覧できるみたい。でも、ツリーは一覧性が微妙かな? 昨日の日報、一昨日の日報…と辿ってみたいという需要が希にあり、そういうのが面倒そう(昨日とか、特定の日に飛ぶコマンドはあるけど、連続しては飛べない)。まぁ、必要なら自分で作ればいいか。TypeScriptならCommon Lispより書けるし。
Assert.AreEqualは精度を指定できるメソッドがあるけれど、CollectionAssertにはないっぽい。まぁ、それはそうか。
// Assert.AreEqualのオーバーロード: public static void AreEqual (double expected, double actual, double delta);
IComparerを引数にとるメソッドがあるので、これが使えそう。しかし、どうせならIComparer<T>にしてほしかった…。
public class DoubleComparer : IComparer { public int Compare(object x, object y) { return (x, y) switch { (double dx, double dy) => Math.Abs(dx - dy) < double.Epsilon ? 0 : dx.CompareTo(dy), _ => -1 }; } } public void TestMethod() { double[] excepted = ...; double[] actual = ...; CollectionAssert.AreEqual(excepted, actual, new DoubleComparer()); }
React Hooksでタイマーで定期的にインクリメントされるカウンターみたいなのを作るのにrefを使っていましたが、もっと楽にできたみたいです。
function useTimer(): [number, React.Dispatch<React.SetStateAction<number>>] { const [count, setCount] = React.useState(0); const countRef = React.useRef(count); React.useEffect(() => { countRef.current = count; }, [count]); React.useEffect(() => { const timerId = setInterval(() => { setCount(countRef.current + 1); }, 1000); return () => clearInterval(timerId); }, []); return [ count, setCount ]; }
なんて書いていましたが、「関数型の更新」を使えば:
function useTimer(): [number, React.Dispatch<React.SetStateAction<number>>] { const [count, setCount] = React.useState(0); React.useEffect(() => { const timerId = setInterval(() => { setCount(c => c + 1); }, 1000); return () => clearInterval(timerId); }, []); return [ count, setCount ]; }
で済んでしまう。うーん、マニュアルはちゃんと読まないといけませんね。Reducerも使ってみないとだ。