Markdown記号をカーソルが触れた単語だけに表示する理由
太字の単語を一つ直そうとカーソルを置いただけなのに、段落全体がMarkdownの原文に戻ったことはありませんか。moteは、カーソルが触れているその構文の記号だけを表示します。

ライブモードでは、カーソルの位置がそのまま画面の状態になります。Markdownの記号は普段は隠れ、修正するときだけ現れるべきです。
では、「修正するとき」はどうすれば分かるのでしょうか?
moteは当初、段落全体を基準にしていました。カーソルが段落の中に入ると、その段落にあるすべての記号を表示していました。
実装は簡単でしたが、画面が騒がしくなりました。太字を一つ直そうとカーソルを置いただけなのに、3行後のリンクやコードまで原文に変わりました。目は一か所を見ているのに、段落全体が動いたのです。
段落ではなく構文を見ます
今のmoteは、カーソルと接している構文だけを表示します。
カーソルが開始記号と終了記号の間にあるときだけ、原文が現れます。記号のすぐ前と後ろも範囲に含めます。そこにカーソルを置くことも、構文を修正しようとする操作だからです。
カーソルが一文字分でも外れると、再びレンダリングされた表示に戻ります。現れたり消えたりするときには、120 msの不透明度トランジションを使います。始まりと終わりのあるトランジションなので、終了すれば何も残りません。
段落に太字、リンク、インラインコードが一緒にあっても、ほかの部分は動きません。カーソルが触れた構文だけが変わり、再描画する範囲もその一行だけです。文書全体を再解析することはありません。
斜体、太字、取り消し線、蛍光ペン、下付き文字、上付き文字、コード、数式、リンク、画像、脚注参照にも同じ原則を適用します。
行頭記号は少し異なります。#と>は行全体の性質を決めるため、カーソルが行のどこにあっても同じように表示します。一方、リストの- は、カーソルが記号の上にあるときだけ現れます。空白を通り過ぎて本文へ移動すると、すぐに箇条書きへ戻ります。
テキストを選択したときも、選択範囲と重なる構文だけが原文に変わります。3文字を選択したのに行全体がソースへ変わってしまうと、何を選択したのか、かえって分かりにくくなるからです。
記号も文字の見た目に従います
表示された記号には、構文のスタイルがそのまま適用されます。
太字の**は太字で、斜体の*は傾いた状態で現れます。取り消し線の~~にも線が引かれます。

*だけが現れた画面。アスタリスクも一緒に傾いていて、同じ行の太字とインラインコードはレンダリングされた状態で残っています。以前は、すべての記号をグレーで表示していました。すると太字にカーソルを置いた瞬間、単語がグレーの括弧に閉じ込められたように見えました。今修正している文字が太字だという情報も、一時的に消えていました。
記号に文字のスタイルを適用すると、意味が明確になりました。単語は引き続き太字に見え、アスタリスクはその範囲を知らせる表示としてだけ残ります。
グレーは、#、>、箇条書き記号のようなブロック記号にだけ使います。これらの記号は、文字よりも行の性質を説明するものだからです。
原則は単純です。文字に付いた記号は文字の一部のように、行を定める記号は背景のように表示します。
アスタリスクだけを自動で対にします
アスタリスクを一つ入力すると、閉じるアスタリスクも一緒に作られます。もう一つアスタリスクを入力すると、太字用のペアに成長します。
内容を書いたあとに閉じるアスタリスクを入力すると、新しい記号を作らずに既存の記号を飛び越えます。アスタリスクが四つずつできてしまう問題も、この規則で解決しました。
ただし、文字やアスタリスクのすぐ後ろで入力したアスタリスクは、ユーザーが自分で構文を閉じている途中だとみなします。この場合はペアを作りません。
アンダースコアとチルダは、自動でペアにしません。snake_case、__init__、~/경로のように、日常的に入力する文字を邪魔する可能性があるためです。選択したテキストを囲むときだけ、ペアとして動作します。
キャレットは文字より目立たないようにします
当初、キャレットは強調色の青でした。現在は本文と同じインク色を使っています。
青いバーは短い入力欄にはよく似合います。しかし文書では、文字が主役です。キャレットはどこまで書いたのかを知らせるだけで十分です。強調色は、選択範囲と検索結果にだけ残しました。
幅は、キャレットの高さを本文のインクの高さで割り、整数に丸めて決めます。本文では1 pxになり、大きな見出しでだけ2 pxになります。小数の幅をそのまま使うと、二つのピクセル列に分かれ、細くなる代わりに太くぼやけてしまうからです。
高さは行間ではなく、文字の高さに合わせます。本文は18 px、h3は24 px、h2は29 px、h1は36 pxです。キャレットを見るだけで、カーソルが本文にあるのか見出しにあるのかが分かります。

点滅は、アイドル状態で反復ソースを置かないという規則の唯一の例外として記されています。ウィンドウがフォーカスを失うと点滅を止め、選択範囲もアルファ45 %まで後退します。
ずれは残しました
記号が現れると、後ろの文字が少しずれます。この動きはなくさないことにしました。
隠れた記号を薄いグレーで常に表示し、空間を確保する方法も試しました。しかし太字にはグレーの残像が残り、取り消し線は単語の外へ飛び出しました。レンダリングされた画面でも原文でもない、不自然な状態になりました。
その代わり、箇条書きやタスクボックスのように、描画されたボックスがある行頭記号は、原文とレンダリング後の幅の差だけ行を移動させ、記号が現れても本文の文字が動かないようにしています。見出しの#と引用の>は、本文を押すようにしました。そのように動作するエディターのほうが慣れ親しまれているという判断でした。
リンクはアドレスが長く、画面の変化がさらに大きくなることがあります。そのため、普段はリンクの文字だけを表示し、末尾に小さな矢印を付けます。リンクであることは分かりますが、アドレスは修正するときだけ現れます。
原文を正確に確認する必要があるなら、ソースモードを使えばよいのです。ライブモードはすべての記号を表示する場所ではなく、今修正する場所だけを開くための場所です。
moteはユーザーの意図を推測しません。カーソルが構文の中にあれば記号を表示し、外にあれば隠します。推測は当たれば便利ですが、外れたときには理由が分かりにくいものです。位置という一つの基準だけを使えば、いつでも結果を予測できます。
記号をいつ表示するかを決めることは、結局のところ、ユーザーの目をどこに留めるかを決めることなのです。