テキスト・エディタの interactive 引数指定の正規表現

GNU Emacs の編集コマンドは interactive 特殊形式を持つだけでなく、 この特殊形式で対話時に引数をどのように得るかを指定します。 この仕掛けは、 関数と編集コマンドの差異をなくす働きをします。 エディタの read-eval-print ループからは、 特殊形式を…

テキスト・エディタの行の折り返し表示 その 4 - キャッシュ更新の改善

「行の折り返し表示 その 3」 でテキスト・エディタで長い文書ファイルを開いても、 表示速度が極端に落ちないようにと、 行の折り返し表示のための書記素クラスタ情報をキャッシュすることにしました。 ところが、 キャッシュは良いことばかりではないよう…

テキスト・エディタのマルチ・バッファ

ここまでで、 マルチ・バッファにする下地は整っているので、 まずは、 落穂拾いから始めます。テキスト挿入もしくは削除に伴い、 マークと行折り返しレイアウト・キャッシュを更新する目的で、 Window に buffer 属性を、 Buffer に window 属性を設けて相…

テキスト・エディタのインクリメンタル・サーチ

Emacs のインクリメンタル・サーチを真似してみます。 このサーチ法は、 1 文字入力するごとに、 パターンを 1 文字増やしながら同時に文字列を探します。 開始方法は 2 つあります。 isearch-forward (C-s) コマンドで現点から後方への検索を開始し、 isear…

テキスト・エディタのミニバッファ

ミニバッファは、 コマンド実行に必要な文字列を利用者との対話によって得たいときに使います。 普段、 キーボード入力は Window につながっています。 それを一時的にミニバッファが譲り受けて、 対話が終わると、 Window へ返却します。 キーボード入力の…

テキスト・エディタのウィンドウ

Window は WindowBase の派生クラスです。 同じ WindowBase の派生クラス MiniWindow との違い、 MiniWindow が画面出力専用であるのに対し、 Window はコマンド実行による編集作業を補助するメソッドをいくつか備えています。 また、 モード行をもっており…

テキスト・エディタの上下タイリング・ウィンドウ

テキスト・エディタが端末画面に複数のウィンドウを表示するとき、 画面を分割して隙間なくウィンドウをタイルのように並べる方式が定番になっています。 ここで作ろうとしているエディタも複数のウィンドウをタイリング方式で表示できるようにしていきます…

テキスト・エディタの文字列補完

Emacs は文字列補完機能をもっています。 補完機能を使うには、 文字をいくつかタイプして TAB キーを押します。 すると、 タイプ済みの文字列で始まるコマンド名やファイル名を探して長い文字列に展開してくれます。 Emacs のコマンド名には長いものが多い…

テキスト・エディタのエコー領域

エコー領域は端末画面最下にあり、 エディタからのメッセージを表示する場所です。 ここでは、 エコー領域兼ミニバッファの表示に MiniWindow を使います。 MiniWindow のインスタンスはエディタ稼働中に 1 個存在し続け、 Screen が保持しています。 Screen…

テキスト・エディタのカーソル移動

Craig Finseth は、 文字単位で現点を前後へ動かす関数を point_move としていました。 その関数は移動量を示す count を引数にとってました。 count が負のときは前方向へ現点を動かし、 正のときは後方向へ現点を動かしていました。 count の絶対値は移動…

テキスト・エディタの Undo

Emacs 系のテキスト・エディタは文字を一文字ずつバッファに self-insert-command で挿入していきます。 ところが、 Undo コマンド (C-x u) は、 挿入単位の一文字ごとではなく、 一連の文字挿入をまとめて巻き戻すように作ってあります。 一連の文字削除も…

OptionParser の省略可引数は Placed 推奨

ruby 添付ライブラリ optparse は、 オプションの省略可引数を Optional と Placed の 2 種類に分けて区別します。 特に理由がなければ、 Optional を使わず、 Placed を使いましょう。 この 2 つには、 コマンドライン解釈時に、 オプションと省略可引数の…

test-unit の TAP 出力用 Rakefile

test-unit の test-unit-runner-tap を使って Test Anything Protocol (TAP) 出力をおこなわせる備忘録です。bundler で sample gem を作ります。 $ gem install bundler $ bundle gem sample --test minitest --mit $ cd sampleGEM テンプレート sample.gem…

行の折り返し表示 その 3 - キャッシュ

行の書記素クラスタの開始配列 Line、 行の折り返し配置情報 Grid の両方ともキャッシュで最近使ったものを保持しています。 キャッシュに保持可能な項目数は、 キャッシュ・オブジェクト生成時に指定し、 以後、 保持可能項目数を変更することはできません…

行の折り返し表示 その 2 - Line を求める

昨日の Layout は対象行の書記素クラスタの開始位置の配列 Line を使いました。 これを求めるのは Buffer の役目です。 Line = Struct.new(:first, :last, :h) # Line[first=200, last=211, h=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11]] # |H |e |l |l |o |こ|…

行の折り返し表示 その 1 - Layout クラス

C. Finseth The Craft of Text Editing の基本エディタ部は、 画面表示部から独立しています。 そのため、 どこが画面に表示されているかに依存せず、 現点を自在に移動することができます。 画面表示部では、 現点を画面に表示できるように表示開始点を求め…

ls (1) コマンドのカラム形式出力の真似

カレント・ディレクトリを ls (1) コマンドのカラム形式の真似をして表示します。 だいぶ前に書いたコードがあるのですが、 必要以上に複雑に書きすぎていて反省。 今度は、 必要最小限のシンプルさを心がけてみました。 Point2d = Struct.new(:y, :x) class…

Emacs 風のキー入力部 (2) 単独 ESC 文字の受け入れ

前のキー入力部は、 ESC f のように、 ESC に文字を組み合わせることを前提にしていました。 そのため、 keymap で ESC にシンボルを指定しても、 ESC を押した後にキー入力待ちをしてしまいました。 これでは、 インクリメンタル・サーチのように ESC を単…

Emacs 風テキスト・エディタ向けの端末キー入力手順

Emacs 風のコマンド入力を解釈するのに必要な端末入力機能は、 コード・ポイント 1 個分の文字列を get メッセージで得ることができ、 unget でコード・ポイント 1 個分の文字列を読み戻せなければなりません。 さらに、 一連のキー入力の途中でエコー表示を…

Emacs 風のキー入力部

Emacs のキー入力は、 コマンドに結びつけたキー入力文字列の前に数値引数をくっつけることができます。 この前置引数には 2 通りの打ち込み方があります。 私が良く使う汎引数と、 めったに使わない数値引数です。 デフォルトでは、 汎引数 universal-argum…

LRU Hash

Ruby では、 オブジェクトをキャッシュする用途に添付ライブラリ WeakRef が使えるようになっています。 ただし、 WeakRef を使うとオブジェクトをゴミ集め時に廃棄するため、 短命のキャッシュにしか使えません。 そこで、 ゴミ集めの頻度よりも長い時間に…

UTF-8 エンコーディングのままでバッファ・ギャップ その2

前回のギャップ・バッファのギャップ移動を使って、 挿入・削除・置換を試してみます。挿入では、 現点にギャップを移動します。 ギャップのバイト数が挿入したい文字列のバイト数よりも大きくなるように適宜バッファを grow メソッドで長くします。 そして…

端末のスクロール機能を使った簡易版 refresh

xterm は ANSI 画面制御シーケンスに、 行削除 (\e[L) と行挿入 (\e[M) をもっています。 1 行だけでなくパラメータで行数を指定して、 複数の行を一度に削除したり挿入することもできます。 挿入するのは空行です。 さらに、 この 2 つを組み合わせることで…

EastAsianWidth 対応 wcwidth

Unicode Character Database の EastAsianWidth に対応する wcwidth です。 コード・ポイントに対する文字が、 端末上で必ず半角なら 1、 必ず全角なら 2 を返します。 フォントによって半角かもしれず、 全角かもしれないなら 3 を返します。文字幅情報は 2…

Terminfo 文字列ケーパビリティのパラメータ展開

Terminfo (5) ケーパビリティは、 様々な端末のエスケープ・シーケンスに柔軟に対応するために、 スタック計算機を組み込んであります。 それを使って、 パラメータを加工して、 望みの位置に望みの形式でパラメータを展開していきます。 そのスタック演算と…

AVL 木なロープもどきの改訂

4 年前に書いたロープに手を入れました。⇒ https://gist.github.com/tociyuki/10372481 avlrope.rb ⇒ AVL 木なロープもどき ⇒ Rope もどきの落ち穂拾い算法は同じです。 このロープの木は、 部分木に含まれている文字数による Weight 木になっていて、 木の…

ruby の SHARED String

Seeing double: how Ruby shares string values の内容に次の 4 点を追記しておきます。 リテラル文字列は SHARED です。 リテラル文字列へ束縛している String オブジェクトを破壊操作すると、 文字列実体であるバイト列を複製して書き込みます (copy-on-wr…

UTF-8 エンコーディングのままでバッファ・ギャップ

昨夜投稿したものの再投稿です。 更新しようとして操作ミスで削除してしまいました。ピュア Ruby で記述した Emacs 風のテキスト・エディタ Textbringer は、 Ruby の String オブジェクトをバッファ・ギャップにしています。 バッファ・ギャップの要点はギ…

Markdown ブロックの WikiWikiWeb 方式での書式変換 (その3)

先日の続きです。 葉ブロックの 2 行目以降の行では、 マーク・スタックを作らないため、 ブロック開始行用とは別に、 行頭の字下げを調べるメソッドを用意しています。 先日の setext ヘディングが開始行と同じレイアウトで下線行が字下げされているかどう…

Markdown ブロックの WikiWikiWeb 方式での書式変換 (その2)

WikiWikiWeb 方式で、 行単位でのマーク・スタックの変化から Markdown のブロック要素の入れ子構造の追跡を前回に試みました。 マーク・スタックを作るのは物理行単位とし、 すべての行でマーク・スタックを作っていたのですけど、 Markdown には空行とイン…