ハクソク

世界を動かす技術を、日本語で。

自分専用のテキストエディタを作成し、日常的に使用する

概要

  • プログラマーにとってテキストエディタは不可欠なツールであり、理想的なものを求めて多くのエディタを試行錯誤
  • Howlというエディタの限界に直面し、自作エディタの開発を決意
  • 開発過程で機能の取捨選択やパフォーマンス改善、使い勝手の追求を重視
  • ファイルブラウザや正規表現エンジンなど、特徴的な実装ポイントを詳細に解説
  • 実用性と自分仕様を両立させるための工夫と反省点を共有

プログラマーのテキストエディタ遍歴と自作への道

  • テキストエディタはプログラマーにとって「城」そのもの
  • 理想的なエディタとは、現実世界のあらゆるデータを柔軟に扱えること
  • 長年愛用してきたHowlは軽量で効率的だが、いくつかの致命的な欠点
    • 開発停止状態が続き、自分でフォークして保守していたが、MoonScriptという言語の習得意欲が湧かず大規模な修正が困難
    • プロジェクト全体のファイル検索が遅く、フロー状態を妨げる
    • GUIエディタのため、SSH経由での利用や統合ターミナル機能が不十分
  • LSPの利用習慣がなく、grep検索に強く依存
  • ネットワーク越しの作業が増え、SFTPやGUIでは限界を感じる
  • 代替エディタを多数試す(Helix、VS Code、Sublime Text、Vim、Zed、Neovim、Emacs、Geany、Micro、Lite XL、Lapce、GNOME Builder、Kakoune)
    • 各エディタに長所はあるが、**求める「指先感覚」**が得られず
    • Helixを最長で使うも、決定的な魅力に欠けると感じて自作を決意

自作エディタ開発のはじめ方

  • スコープを徹底的に絞ることから開始
    • 自分以外のための機能は排除、全設定はハードコーディング
    • パフォーマンスは後回し、バッファは文字列管理
    • Unicodeグラフェム対応は最小限、主要言語のみサポート
  • 最初は進捗が遅く、TUIフレームワークの自作など過剰設計気味
    • 後にシンプルで細粒度なアプローチへ移行

実用投入と改善サイクル

  • nanoの代替として徹底的に自作エディタを利用
  • 不足機能やバグ、違和感をREADME.mdに全て記録
  • イライラした箇所は即時修正を徹底
  • この運用で開発時間が大幅増加、10,000行以上のコードを半年で実装

カーソル操作の難しさ

  • カーソル操作は直感的だが、実装は非常に複雑
  • 高度な入力操作は基本操作の組み合わせで実装推奨
    • 例:単語単位のバックスペースは、単語移動+範囲選択+削除の組み合わせ
  • Undo/Redoのグルーピングにも注意
  • モーダルエディタは基本操作を直接ユーザーに公開し、連携しやすい設計

ファイルブラウザのこだわり

  • Howlのファイルブラウザ体験が他エディタより圧倒的に優れている点に着目
    • インクリメンタルなファジーフィルタが非常に快適
    • ファイル新規作成やディレクトリ移動も直感的に操作可能
    • プレビュー機能も充実
  • 他エディタは多くがマウス操作や標準ダイアログ依存でストレス
  • 自作実装では、シンプルな検索アルゴリズム(前方一致・部分一致・最終更新日時)を採用
    • ケース一致で順位調整、実用性重視

正規表現エンジンの自作

  • 正規表現は全体検索・シンタックスハイライト・バッファ内検索に活用
  • 既存ライブラリでは文脈依存やネスト対応が不十分なため自作
  • 独自のパーサとASTを構築し、パフォーマンス最適化を重ねる
    • パターンの合成、共通プレフィックスの抽出、スレッドコードVM化、CPS変換、バイト単位処理
  • ベンチマーク結果、大規模ファイルのハイライトも10ms以下で完了

シンタックスハイライトの最適化

  • 全再描画方式から、オンデマンドチャンクハイライト+キャッシュ方式へ移行
  • 編集が発生した箇所のみ再ハイライト、複数ペインにも柔軟対応
  • 実用上、大規模ファイルでも十分高速

プロジェクト検索の実装

  • .git/ディレクトリ検出によるプロジェクトルート特定
  • ルート以下を再帰的に走査し、正規表現でマッチ
  • 実装詳細は省略されているが、シンプルかつ効率的な検索を重視

このように、自作エディタ開発は理想の操作感・機能・パフォーマンスを追求する過程で多くの学びと工夫が生まれる体験。既製品の限界を感じた時、自分の「城」を築く価値を実感できる。

Hackerたちの意見

90年代にエディターに手紙を書いたことを思い出すなぁ。COBOLやアセンブリファイルに「ms edit」を使いたくなかったから。シンタックスハイライト、速いバッファリング、さらにはスクリーンセーバーまであったんだよね。コンパイラも直接呼び出せたし。ペンティウム120で動いてたけど、今のVSCodeよりも何千倍も速く感じた。でも、VSCodeは複数のファイルを同時に編集できるんだよね…
古いノートパソコンでVSCodeを立ち上げたら、テキストエディターが全然動かなくなって、心の一部が死んだ気がした。自分はvimの時代から来たけど、今のツールでそれが正解だって人に言うのは難しいな。
> でも、VSCodeは複数のファイルを同時に編集できる。ボーランドのターボパスカルやターボCも同時に複数のファイルを開けたよね。
そういえば、VB6で動くエディターを書いたことがある。検索と置換がうまく動いたときはめっちゃ嬉しかった。2002年のマーケティングページのコピーもまだ持ってるよ。無制限のカスタマイズ可能なテンプレートファイル、カスタマイズ可能なシンタックスハイライト、非常にカスタマイズ可能なユーザーインターフェース、色分け印刷(オプション)、カラム選択機能、正規表現による検索/置換、ブロックインデント/アウトデント、通常のテキストをASCII、16進数、バイナリに変換、文字列をn回繰り返す、ウィンドウズエクスプローラー風のファイルビュー(ドッキングウィンドウ)、無制限のファイル履歴、お気に入りのグループとファイル、各オープンドキュメント用の無制限のプライベートクリップボード、このエディターで開くファイルタイプの関連付け、ドキュメントの表示を最大4分割、コード補完(つまりIntelliSense)、Windows XPテーマサポート。あの頃は大文字のHTMLタグを使ってたよね。
ジョシュ・バレットは、スーパーマリオ64のGBAポートの天才だよ。彼のエディターを使うのは全然嬉しい!
彼のSM64の動画、めっちゃ好き!興味ある人のために最新のリンク貼っとくね: https://www.youtube.com/watch?v=nS5rj80L-pk
これ大好き!「難しい部分を統計の箱に押しやる衝動を抑えよう」という一文が特に心に響いた!
エディターはこちらだよ: https://git.jsbarretto.com/zesterer/zte
このスレッドの人たちで、テキスト編集ライブラリのおすすめがあったりする?自分のやり方でテキストエディターを作りたいんだけど、GUIじゃないとダメなんだ。理由を話すのは面倒だから省略するけど、その要件があるせいで、フォントレンダラー(少なくとも1つ)やグラフィックスコンテキストなど、いろいろ持っていかなきゃいけない。これらを全部やりながらテキスト編集ライブラリを書くのは、夜や週末の時間じゃちょっと無理がある。テキストエディターだけを始めると、ターミナルコンソールでしか動かないから、自分のプロジェクトには使えないし、GUIだけを始めると、実際には動かないから使えない。だから、プロジェクトの中心にあるテキスト編集ライブラリをカスタムコードに置き換えるとしても、何か始めるためのものがないと、正直言ってスタートすらできない。ここで解決策を見つけるのがこんなに難しいとは思わなかった。見つかるものは、自己完結型のテキストエディターか、フルオンの「ミッションステートメント」GUI(「私たちのエディターの機能を使えば開発が楽になる」みたいな)ばかり。入力を与えて、テキストコンテンツの状態更新を返してくれるAPIを見つけるのが本当に大変だった。CRDTとかなんでも。みんな、単におもちゃのテキストエディターを書くか、フルブローのショーケース製品を書くかのどちらかだと思ってるのかな。そうなると、「ウィンドウズのメモ帳アプリを再構築したいけど、大量の行を扱っても遅くならない」っていう開発者は、こういうよく解決された問題のライブラリを使うんじゃなくて、実際に高度なテキスト編集の行管理を実装しなきゃいけなくなるんだよね。
いくつかの軽量GUIテキストエディタはScintillaをベースにしてるんだよね(https://scintilla.org/)。これ、GTKやWindows、MacのGUIアプリに組み込めるクロスプラットフォームの編集コンポーネントを提供してる。編集とプレゼンテーション両方を考えると、ちょっと機能が多すぎるかもね。
テキストエディタを作ってるときに驚いたのは、現代のターミナルエミュレーターがANSI拡張を考慮するとどれだけ優れているかってこと。ファーストクラスのクリップボードアクセス、マウスイベント、精密なテキストスタイリング、フォーカストラッキング、システム通知、キーの押下/解放イベントなど、現代のターミナルエミュレーターなら全部可能なんだ。これだけあれば、かなり優れたエルゴノミクスなエディタUIを作るのに他に何もいらないよ。trolleyみたいなツールを使えば、アプリ全体をghosttyで動かすシムに包み込んで、ネイティブUIアプリとして見せることもできるよ: https://github.com/weedonandscott/trolley
プラットフォームの詳細がわからないとおすすめするのは難しいけど、GUIレンダリングが目的じゃないなら、raylibみたいなのがクロスプラットフォームのGUI API、特にテキストレンダリングにいい選択かもしれないよ。 https://www.raylib.com/
stb_textedit.hのことを言いたいけど、あんまりおすすめはしないな。勉強するには面白いけど、ライブラリにはいろいろ欠点があって、統合して使うのが面倒なんだ。ImGuiで使われてるけど、ちょっと改造されてるよ。欠点を挙げると、utf-8バイトと簡単に使えないし、アクションをトリガーするためのキーボードショートカットが大きなスイッチになってて、スクリプトを書くためにキーボード入力を偽装しないといけない。デフォルトの単語境界検出もあんまり良くないし、ダブルクリックやトリプルクリックの選択をうまく提供する方法もない。注目すべき関数はstb_text_locate_coord()とstb_textedit_find_charpos()で、物理的なx,y座標とテキストバッファ内の位置を結びつけるんだ。両方ともテキストの行を反復処理して、y位置を蓄積し、最後の行の文字でx位置を蓄積する。ウィンドウ処理や描画、OS統合には、SDLとSDL_ttfが実際にかなり良いよ。SDL3_ttf APIは改善されて、ゼロ終端の文字列が必要なくなったから、毎回チャンクを再配置する必要がなくなった。
自分もゼロからテキストエディタを書く道を選んだんだ。いろいろな要素があって、できるだけ機能を外注しようとしたよ。LSPでインテリセンス、tree-sitterでハイライトや構文に応じた機能、fzfで検索やファイル処理など。シンプルなコード変更で自分のニーズに合わせて調整できるようにデザインしたんだ。最初の数週間は本当に大変だったけど、5分ごとにバグを見つけて修正しなきゃいけなかったから、他のプロジェクトに集中できなかった。でも、バグを修正すればするほど、残るバグは少なくなるから、いいニュースだよ。 https://github.com/ivanjermakov/hat
いい仕事だね!過去の修正や調整が未来の生産性に積み重なっていく感覚、ほんといいよね。
これ、読むのがすごく楽しかった!友達にも自分のエディタを作るように勧めてるんだ。自分のツールで作業するプロセスって、すごくいいんだよね。自分のテキストエディタ(Leftって呼んでる)をほぼ10年間使ってるけど、完璧にするのに時間がかかった。でも、何年もかけて改良してきた(Leftを使ってLeftを編集してた)から、その時間は朝に開いて作業する喜びで20倍返しされてるよ。もしまたやり直すことになっても、全部やりたいな。
自分のエディタ("aoeui")を使い始めて19年になるけど、これが自分の生産性にとって最高の選択の一つだった。
あなたのテキストエディタで最も重要だった機能は何ですか?複数のワークフロータイプに対応するように作ろうとしましたか?
作者が「nanoに置き換えられた」と書いたとき、思わず笑っちゃったよ。何十ものエディタを試して、捨てて、結局nanoを日常使いにしてるって言ってるの?それが本当なら、この人は面白いキャラだね。
いや、作者は普段の作業にはHowlを使って、たまにNanoを使ってたみたい。ターミナルで作業してるときじゃないかな。
「古い言い伝えがある:人生で一度は家を建て、木を植え、エディタを書くべきだ。私は最後のことから始めることにした。」 - Vip - Vi-Style Editor in PicoLisp https://picolisp.com/wiki/?vip
antirezの「kilo」エディタを再実装するのが楽しかったよ。 https://github.com/antirez/kilo いいチュートリアルもあるし、 https://viewsourcecode.org/snaptoken/kilo/ ターミナルモードについてもっと学んだり、素のCを書くのにいい方法だよ。