何を改造したって?

ライン・ディシプリン1と呼ばれる、通常 xterm のような端末エミュレー ターと、コマンドプロセスの中間にあって、ユーザーの文字入力をバッファリ ングし、打ち間違いを BackSpace (あるいは Delete)キーで削除することを可 能にしている部分です。

端末のフラグ

端末には行編集やキーボードによるシグナル生成(^C など)の挙動を変更する ための様々なフラグが用意されています。これは stty コマンドで確認、変更 することができます。

例えば、文字入力は常にバッファリングされているわけではなくて、Emacs や bash などの高度な編集機能を有するプログラムは、端末を raw モードなどに 設定することで一文字ごとに入力を受け取っています。

iutf8フラグ

Linux では、このようなフラグの中に iutf8 というものがあります。これは 入力をマルチバイトエンコーディングである UTF-8 と仮定して、行指向編集 を助けるものです。

このフラグが設定されていないと例えばマルチバイト文字の「à」は C3 A0という2バイトですので、二度 BackSpace キーを押さなければ消すことが できず、またその時、端末へは2文字消すように制御文字の並びが送られます から、カーソルは2マス戻ってしまいます。画面上の表示と実際のデータに食 い違いが埋まれてしまうわけです。

iutf8 フラグは、これを一度の BackSpace キーで削除することができるよう にするものです。

Linux は UTF8 を解する。すばらしい! でも…

Linux は UTF8 の1文字を表わすバイト列を認識すると、これを消去したとき は一律に「1マス後退」の命令を端末に送ります。

例に上げた à のようなラテン文字の場合は、グリフが端末上で1マスを占める のでこれで良いのですが、東アジアの人々はいわゆる全角文字も使っており、 これらは2マスを占めます。これを消す為にはカーソルの後退は一度では足り ないのです。

従って、直前に打った全角文字を削除すると、データの上では1文字消えても 表示上はその文字の半ばまでしかカーソルが戻りません。以下の動画は4文字 削除しても、画面上では2文字しか消えていない様子です。

文字幅を知る必要がある

このように、Linux は UTF8 文字は認識できるのですが、これの幅を常に 1 マスだと考えています。どうにかして彼にこの世に全角文字のあることを教え てやらなくてはなりません!

Unicode では個々の文字に、全角か半角かという属性が定義されており、これ を参照すれば文字幅を判定することができます。(実は話はそう簡単ではなく て、全角とも半角ともつかない文字があってややこしいのですが…2)

幸運にも、すでに Markus Kuhn 氏による wcwidth.c というコード が公開されており、これを使えば簡単です。(このコードは、ご存知 w3m テキ ストウェブブラウザでも使われています)

Linux カーネルに組込む

Linux ソースツリーの drivers/tty/n_tty.c がライン・ディシプリンを実装 していますから、これを変更します。

同じディレクトリに wcwidth.c を置いてやって、#include "wcwidth.c" と しました。ちょことちょこと両者を貼り合わせるコードを追加してやって、で きあがりです。

BackSpace 一発で全角文字が削除できるようになりました。

コード