Appleテキストエディタの技術的内部
TextView ベースのテキストエディタとしてのPaperの動作の詳細を扱う。
- Paperは現在TextKit 1フレームワークを基盤に構築されており、TextKit 2でも概念、抽象化、原則は維持されるか、より良いAPIへと置き換えられている。
テキストビュー
TextView クラスはAppleテキストエディタにおけるテキスト編集処理の中核。
NSTextView と UITextView には違いがあるが、APIが似ているため、ひとつの TextView クラスとして扱う。
TextView はOSのリリースごとに複雑さが増している大規模コンポーネント。
- Appleは
TextView を複数のレイヤーに細分化し、テキスト編集体験を提供している。
NSTextStorage
- 生のテキスト文字列を保存する。
- テキスト範囲に割り当てられた属性(文字列-値のペア)を保存する。
- テキストと属性の変更に関するイベントを発生させる。
NSTextContainer
- テキスト記号(グリフ)を保持する領域の形状とサイズを定義する。
NSLayoutManager
NSTextStorage のテキスト文字列に適用された属性範囲を見て、グリフのサイズと間隔を計算する。
- グリフをレイアウトし、テキストの各行がどこで始まりどこで終わるか、テキスト全体の高さを計算する。
TextView
NSLayoutManager によって生成されたグリフレイアウトを描画する。
- ビューの高さをレイアウト済みテキストの現在の高さと同期する。
- テキスト選択、キャレット、新たに挿入されたテキストに適用されるタイピング属性を管理する。
ScrollView
TextView の表示されている部分を表示する。
- スクロール、スクロールバー、ズームを管理する。
属性
NSAttributedString はAppleフレームワークにおけるリッチテキスト編集の基盤。
- 通常のテキスト文字列と、テキスト範囲に付与された属性(文字列-値のペア)で構成される。
- 属性は主にスタイリング目的で使われるが、カスタムの文字列-値ペアを割り当てることに制限はない。
スタイリング
- スタイリングとは、テキスト範囲に特別なフレームワーク定義属性を適用することを意味する。
- Paperはメタ属性を使ってテキスト構造を識別したうえでスタイリングを適用する。
- 属性は、ユーザー入力によって変更される
NSTextStorage の Markdownテキスト と、ユーザーがメニュー項目、スライダー、ジェスチャーで調整する テキスト影響設定 と同期される。
パフォーマンス
- メタ属性、レイアウト属性、装飾属性の分離は、特定のエディタ変更を高速に維持するのに役立つ。
- タイピング速度はテキストエディタで最も重要なパフォーマンス要素。
- Markdownの仕組みにより、テキスト変更は段落全体のスタイリングに影響を与えることがある。
メタ属性
- ハイライト処理のロジック以外にも、メタ属性はテキスト構造を把握する必要があるさまざまな機能で重要な役割を果たす。
フォーマット用ショートカット
- 選択されたMarkdownテキストのスタイルを切り替えるために必要な詳細情報を提供する。
章間移動
- キャレット位置に対して相対的な見出しを見つけるのに役立つ。
アウトライン
章の並べ替え
フォーマット変換
- MarkdownコンテンツをRTF、HTML、DOCXに変換するには構造を把握する必要がある。
テキストコンテナの数学
- テキストコンテナでは、好ましい行長を維持することが最も重要なルール。
- 見出しタグが通常のテキストフローの外に配置される場合のように、対称性を装う必要があることもある。
選択のアンカリング
- テキスト選択には常にアンカーポイントがある。
- Macではクリックしてドラッグしてテキストを選択し、iOSでは選択範囲の片端をドラッグできる。
選択親和性
- テキスト編集には 選択親和性 という興味深い概念がある。
- キャレットを矢印キーで移動すると単純に行が切り替わるが、ショートカットで行末へ移動すると同じ行に留まりつつ右側に付く。
Uniform Type Identifiers (UTIs)
- アプリ間データ交換の基盤システムであるUTIについて議論する。
- データ型が親データ型に conform to(継承)する階層システム。
ペーストボード
- ペーストボードは、UTIがシリアライズ済みデータにマッピングされた辞書。
- 単一の コピー 操作で、同じデータの複数の表現を同時に書き込む。
- 公開UTIとプライベートUTIを扱うのは比較的簡単だが、Appleによって定義されていない広く受け入れられた形式を扱うのはより複雑。
まとめ
- 最初の記事を確認すると、アプリと開発プロセスについてさらに多くの情報を得られる。
GN⁺のコメント
- この記事は、Appleプラットフォームにおける
TextView ベースのテキストエディタの複雑な内部動作を詳しく説明しており、ソフトウェア開発者や関心のあるユーザーに興味深い情報を提供する。
- テキストエディタのパフォーマンス最適化のためのアルゴリズムと属性管理の方法は、開発者が自らのアプリケーションを設計する際に参考にできる好例である。
- テキストエディタの性能を高めるために使われた技術的アプローチは、他の開発者が類似の問題を解決する際に参考にできる有用な指針を提供する。
- Markdownのようなテキストフォーマットを扱うアプリケーションを開発する際、UTIの理解はデータ交換と互換性のために重要である。
- この記事はテキストエディタの内部構造への理解を深める助けになるが、実際にこの複雑さを管理することは開発者にとってかなりの挑戦になり得る。
1件のコメント
Hacker Newsのコメント
これは本当に素晴らしい記事だ。TextKitの基本的な入門資料として、https://www.objc.io に取って代わりそうだ。
編集トランザクションの外で行われる装飾的属性について少し混乱している。"そしてそれはトランザクションを認識しない。なぜならそれはNSTextStorageではなく、NSLayoutManager自体に存在するからだ" とある。だが、色のような装飾的属性は普通NSTextStorageに存在するはずだ! 著者は、Markdown文字に適用された色がNSLayoutManagerの一時的属性のサポート(通常はスペルミスの単語に色を付けるのに使われる)によって実現されていることを示唆しているのだろうか? だとしたら、その目的は何だろう?
本当に素晴らしい記事だ(そして個人的にもタイムリーだ。今まさにNSTextViewを扱っている)。この情報はどうやって得たのか? 他人のコード? 苦労して得た経験? developer.apple.com?
DOMドキュメントの時代に(例: notion、gitbook)、私はよく属性付き文字列を使ってテキストのパースや操作に魔法のようなことをしている。これはとてもエレガントな構造で、なぜこれほど知られていないのか理解できない。ちなみに記事は驚くほど素晴らしい。
以前、ゼロから独自のテキストエディタを書こうとしたことがあるが、そのときこういう資料があったなら本当にすごかっただろう。
私は長い間Androidアプリ開発者だったので、Appleが物事にやや異なる、より慎重なアプローチをしているのを見るのは興味深かった。Androidでは、Layoutクラス(およびそのサブクラス)がレイアウトとレンダリングに関するすべてを処理し、TextViewが編集/選択ロジックの一部を実装する。EditTextとTextViewの唯一の違いは、EditTextがTextViewにすでに存在する編集機能を「有効化」することだ。このやや一体型のアプローチ(そして出来の悪いAPI)の問題は、アプリがテキストのレンダリング方法についてより多くの制御を必要とする場合、打つ手がないことだ。たとえば、レイアウト後に個々のグリフへアクセスしたい場合は? いや、無理だ。
TextEditアプリはほぼ完全に単一のTextViewで構成されている。Windowsでの対応物はWordPadだと思う。これはRichEditコントロールをベースにしている。もう1つ面白い事実として、RTFは基本的にNSAttributedStringをシリアライズした形式だ。WindowsのRichEditコントロールにも同じことが当てはまる。実際にはWindows側の実装のほうが先だったようだ: https://en.wikipedia.org/wiki/Rich_Text_Format
このアプリが本当に好きだ。obsidianや ia Writer を含む、他のすべてのMarkdownアプリを置き換えてしまった!
ありがたいことに、少なくとも誰かは2024年になってもCocoaを使っている。
iOSコンポーネントについて、こういう文書がもっとあればいいのに!