記号が現れても文字がずれないようにした方法
リスト項目にカーソルを移しただけなのに、文字全体が一度横に揺れたことはありませんか。記号を隠したり表示したりするエディターなら、ほとんどすべてで起きることです。

リストを編集しようとキャレットを移すと、文字が横に押し出されました。キャレットが外れると、また元に戻りました。
動いたのは一行だけでしたが、段落全体が揺れているように見えました。小さな違いが、編集の流れを何度も途切れさせました。
原因はマーカーの幅でした。
通常の画面には、丸い箇条書き記号が表示されます。しかし、ファイルにはハイフンと空白が保存されています。キャレットがマーカーに触れたら、直接修正できるように元の記号を表示する必要があります。
問題は、二つの形が占める幅が異なることです。箇条書き記号は幅が決まったボックスですが、ハイフンと空白の幅はフォントによって変わります。moteでは、その差が4.9 pxありました。元の記号が現れるたびに、後ろにある文字がその分だけ押し出されていました。
幅の差だけ行を移動させます
二つの幅を同じにはしませんでした。代わりに、差を相殺します。
マーカーが元の記号に切り替わる瞬間、行全体を幅の差だけ反対方向へ移動させます。記号の形が変わっても、本文が始まる位置はそのままです。
ファイルには手を加えません。箇条書き記号はハイフンの上に重ねて描いた装飾であり、補正では画面上で行を描く位置だけを変えます。キャレットが入ったり出たりしても、保存されている内容はそのままです。
幅を計算する基準も一つにまとめました。以前は、マーカーを描画する場所と行を補正する場所に、それぞれ別の数値がありました。二つの値のわずかな違いが、まさにその4.9 pxでした。
今では、どちらも同じ関数にマーカーの幅を問い合わせます。基準が一つなので、ずれることもありません。
ただし、左の余白が足りない場合は補正しません。行を移動させた結果、文字がウィンドウの外に切れてしまう可能性があるためです。揺れることよりも、文字が消えることのほうが大きな問題だからです。
見出しと引用は押し出されるままにしました
最初は、見出しと引用にも同じ方法を適用しました。
しかし、見出しの # と引用の > が通常の画面で占める幅は0です。本文を固定するには、記号を左の余白へ追い出す必要がありました。
技術的にはうまく動作しました。文字は動きませんでした。ところが、画面に違和感がありました。記号だけが余白に浮いているように見えるのは、自然ではありませんでした。
そこで元に戻しました。現在は、見出しと引用の記号が現れると、本文が右に押し出されます。

最終的に、マーカーごとに異なる答えを選びました。
箇条書き記号やタスクのチェックボックスのように、画面上にボックスがあるマーカーでは本文を固定します。見出しや引用のように、通常の幅が0のマーカーでは本文を押し出します。
一つのルールよりも、自然に見える画面のほうが重要でした。
記号は本当に必要なときだけ表示します
揺れを減らす最善の方法は、記号が切り替わる瞬間そのものを減らすことです。
現在、箇条書き記号は、キャレットが記号の上にあるときだけ元の記号として表示されます。キャレットが空白を通過して本文へ移動すると、すぐに箇条書き記号へ戻ります。リストの内容を修正している間、ハイフンを表示し続ける必要はありません。
行が長くなって次の行へ折り返しても、整列は維持されます。マーカーが元の記号として表示されている間も、二行目は一行目の本文の下から始まります。
クリックが誤ってドラッグとして認識される問題も修正しました。マーカーが切り替わる瞬間にポインターが少し揺れると、文字が選択されることがあったからです。現在は、ポインターが8 pxを超えて動いた場合にのみ、ドラッグと判断します。
目ではなく数値で確認します
このような違いは、目だけで確認するのが困難です。少し見ただけでは問題がないように見えても、長く使うと気が散るように感じられます。
そこで、実際のアプリを起動するテストを作りました。キャレットをマーカーの内外へ移動させ、本文が始まるx座標を直接比較します。二つの値が同じでなければ、テストには合格しません。
箇条書き記号、タスクのチェックボックス、入れ子になったリストを、すべて同じ方法で検査します。
1ピクセルのずれは、バグとして報告されにくいものです。ユーザーは何が動いたのかを説明するよりも、「なぜか気が散る」と感じるからです。
だからこそ、このような動きは、人ではなく数値が見張る必要があります。
静かな画面とは、何も起こらない画面ではありません。必要な変化が、目障りにならない場所で起こる画面です。