縦書きエディタを作りました。いろんなこだわりが詰まっています。
DLはこちらから。
maybefix/Then: 縦書きエディタ(Tauriを使用。Windowsのみ)

きっかけ
Windows環境において縦書きができるフリーのテキストエディタは少ないです。そして、縦書きでタイプライタースクロールができるエディタとなるとさらに限られます。
僕の要件はさらに厳しくて、Typoraのような感じで「ファイル作成時からカーソル行が必ず中央になければならない」というものですが、この条件を満たすものが既製品にこれまで存在していませんでした。
昔ならここで「誰か出してくれないかなあ」と思うだけでしたが、そんなニッチなものは誰も出してくれません。しかし今はAIがあります。具体的には、CodexとClaude Codeがあります。だいたいこれに投げておけば実装してくれるので、僕はデザインと機能に集中して指摘を送ればいいものが作れるということで、縦書きエディタの開発を行うことに決めました。
開発期間はだいたい1ヶ月くらい? です。最初はCodex一本足打法でしたがすぐに足りなくなってClaude Codeを援用しました。
基本的な思想
基本機能はシンプルにしつつ、執筆を支援する機能を色々とつけたエディタスイート的な立ち位置のソフトにしようと思いました。
そのため、エディタ画面だけでなく、ファイル管理やアイデア管理、プロット支援、資料閲覧などの画面も備えています。
また、作成した作品は、Vivliostyleを経由してエクスポートすることもできます。(外部呼び出しを行っているのでライセンス的にはOKのはず)

Then という名前
ただの洒落です。
禅と、英語の「じゃあ」という意味の「Then」を組み合わせました。まあ、思いつきです。
エディタとしての考え方
AST(抽象構文木)の導入
私がこのエディタを作成するにあたり大きな影響を受けたのが、SF小説家の藤井太洋先生が作成されている、MacOS/iOS向けのエディタであるところの with です。
with については、藤井太洋先生御本人の記事でご確認ください。→ 小説用エディターwith story|藤井太洋
with の大きな特徴は、見出しやルビ、特殊記法のレンダリング箇所を、表示中の本文文字列に対する都度の検索だけで判定するのではなく、本文から生成したAST(抽象構文木)、つまりエディタ内部の構造化された文書モデルをもとに評価・表現している点です。どの範囲が見出しで、どこにルビや注記があり、それを画面上のどこにどう反映するかを、本文そのものの見た目ではなく、この内部構造を参照して決めています。
Then でもこの考え方を参考に、保存される本文そのものはプレーンテキストのままにしつつ、そこから見出し・行種別・ルビ・傍点・地付きなどを解析したASTを生成し、アウトライン表示、検索、表示装飾、見出し単位の移動に利用しています。ASTは保存形式ではなく、本文から再生成できる編集・表示用のキャッシュというわけです。
ASTを導入することによる副産物として、ファイル間の見出し移動が可能となっていたり、高速な検索を実現していたりします。
縦書きタイプライタースクロール
縦書きエディタにおいてタイプライタースクロールを行うのは至難の業(らしい)です。
そもそもタイプライタースクロールとは、入力中のカーソル位置を画面内の一定の箇所に保つ仕組みです。タイプライタースクロールをオンにすると、今の入力している文字が画面のどこに表示されているかを測定し、その位置が固定ラインに合うようにエディタ側で表示位置を動かしてくれます。
タイプライタースクロールを実現するためには、現在のカーソルが本文のどこにあるかだけでなく、それが実際の画面上でどの位置に描画されているかを正確に知る必要があります。横書きであれば比較的素直に実装できる場面でも、縦書きになるとスクロール方向や行の進み方が横書きと違っており位置を取ることが難しくなります。さらに日本語入力では IME の変換中テキストや候補ウィンドウも関わるため、入力中に表示位置を無理に動かすと、カーソルや変換状態が不安定になる問題があり、開発中も苦しみました。
先述したように、このエディタでは、ルビや禁則処理、見出し、リスト、行末記号などを装飾するために、本文を内部的に解析し、インデックス化する仕組みとしてAST(抽象構文木)を採用しています。全文を毎回装飾・描画すると処理が重くてパフォーマンスが落ちるので、実際にはカーソル周辺+いま画面に見えている範囲の近くを中心に処理している状態です。
問題になるのはカーソル行の扱いです。画面に出ているものだけを頼りにすれば、まだ装飾されていない行や、画面外にある行の情報を正しく検知できません。そこで、このエディタでは、「カーソルが本文のどこにあるか」「それが画面上のどこに見えているか」を別々の情報として処理しています。
まず、カーソルが何行目・何文字目にあるか、画面上の要素を探すのではなくて、エディタ内部にある文書データを元に取得します。次に、その位置がエディタ内のどこに描写するのかを測定します。そして、その測定結果をもとに、キャレットがタイプライタースクロール用の固定ラインに来るようにスクロール量を調整します。要するに、二段階の測定を行い、その測定値に対してスクロールを行う仕組みになっています。
……という仕組みを作ったのはClaude Fable5です。CodexのGPT-5.5は、こういう仕組みにしましょうよというところまで行き着くことができませんでした。Fable5しゅごい……。
書きやすさへのこだわり
日本語のテキストを書くためのエディタとして構築したので、とにかく自分が使いやすいエディタを作りたいなと思って設計しました。
そのひとつが禁則処理です。厳密な禁則処理ではありませんが、ある程度は「行の端が揃う」ような感じになったんじゃないかと思います。その結果、縦書きだけでなく横書きにおいても綺麗な表示を実現することができました。
エディタは基本的なMarkdown記法っぽいものに加えて、独自記法にはなりますが、ルビ、縦中横などにも対応しています。この記法については、自分好みのテキストレイアウトシステムを作る | click and magicを大いに参考にして実装しました。
たとえば、ルビを入れたければ [禅(rb,ぜん)] もしくは青空文庫形式で 憂鬱《ゆううつ》 、縦中横にしたければ [21(tcy)] とすることで実現可能です。
将来的には、字下げ挿入(自動挿入)、青空文庫形式やカクヨム記法などへのエクスポートも対応したいなあと思っています。
豊富なテーマ
アホみたいに豊富なテーマがあります。ライトテーマ29種類、ダークテーマ25種類です。なんでそんなに作ったんですか? さあ……
基本的には同じ形状の色違いですが、角丸をベースとしたデザインなどもあります。僕は Flat というテーマを使っています。

情報を管理する機能
執筆するにあたって白紙から書くのは難しいです。様々な方法があると思いますが、調べ物をした情報や考えついたことを集約して構築して展開していくことを支援する機能がエディタには必要だと思い、段階的に実装してきました。
右サイドバーには3つの機能が集約されています。アイデア、プロット、資料です。
アイデアは、X(私はこの名前が嫌いです。Twitterと呼ばれるべきです)のように、断片的なアイデアをつぶやいてストックしておくことができます。さらにそれを、スレッドという単位で束ねたり、後述するキャンバス機能で整理することも可能です。

プロットは、順序立てた文章構成を考案するのに向いている機能です。章とセクションという単位があって、基本的にはセクションを重ねていきます。章を追加してセクションをまとめると見やすくなります。

資料は、各プロジェクトの特定のフォルダに入っている txt/markdownファイル、画像(jpg/png)、PDFをポップオーバーの画面から確認することができます。後述のキャンバス画面に貼り付けることもできます。

さらに、キャンバス機能があります。これは、メモやアイデア、資料をカードとして並べることができる機能です。キャンバスからアイデア・プロット、逆にアイデアからキャンバスに持っていくこともできます。
キャンバスを見ながら本文を書くことは既定値だとできない(別ウィンドウで開く設定はあります)ので、基本はキャンバスで書いたものをプロットなどに落とし込んでいく想定です。

戻りたい、過去へ
過去の原稿に戻れる機能も作ってあります。スナップショット機能です。
作られた保存点に復元すると、今の状態を復元前の退避として置いといてくれる仕様です。

今後の展望
まだまだエディタとして足りていないところがあるので、これから埋めていこうかなというところです。
あとは、テーマや拡張機能についても今後どんどん拡充していきたいと思っています。API的な考え方を取り入れていきたいですね。たとえば、前述の With には、文節の移動(文節を形態素解析しているので、ショートカットキーで文中の文節を自在に移動できる)という機能があるのですが、これはあまり最初から盛り込むと過剰な機能にも思えたので、最初のリリースで見送っています。こういう、ちょっとした機能であれば、拡張機能化してリリースしても何の問題もないし、モジュールの疎結合化にも貢献しメンテナンスしやすいんじゃないかなって思ってます。
※このセクションで話していることは、あくまで予定なので真に受けないでください。