クリック可能テキスト(clickable text)とは何らかの結果を生成するためにマウスやキーボードコマンドを通じてクリックできるテキストです。多くのメジャーモードがテキスト的なハイパーリンク、略してリンク(link)を実装するためにクリック可能テキストを使用しています。
リンクの挿入や操作を行うもっとも簡単な方法はbutton
パッケージの使用です。ボタンを参照してください。このセクションではテキストプロパティを使用してバッファー内に手作業でクリック可能テキストをセットアップする方法を説明します。簡略にするためにクリック可能テキストをリンクと呼ぶことにします。
リンクの実装には、(1)リンク上にマウスが移動した際にクリック可能であることを示し、(2)そのリンク上のRETかmouse-2で何かを行うようにして、(3)そのリンクがmouse-1-click-follows-link
にしたがうようfollow-link
をセットアップする、という3つのステップが含まれます。
クリック可能なことを示すためには、そのリンクのテキストにmouse-face
プロパティを追加します。するとEmacsはそれ以降マウスがその上に移動した際にリンクをハイライトするでしょう。加えてhelp-echo
テキストプロパティを使用してツールチップかエコーエリアメッセージを定義するべきです。特殊な意味をもつプロパティを参照してください。たとえば以下はDiredがファイル名がクリック可能なことを示す方法です:
(if (dired-move-to-filename) (add-text-properties (point) (save-excursion (dired-move-to-end-of-filename) (point)) '(mouse-face highlight help-echo "mouse-2: visit this file in other window")))
リンクをクリック可能にするためには、 RETとmouse-2を望むアクションを行うコマンドにバインドします。各コマンドはリンク上から呼び出されたかチェックして、それに応じて動作するべきです。たとえばDiredメジャーモードのキーマップはmouse-2を以下のコマンドにバインドします:
(defun dired-mouse-find-file-other-window (event) "In Dired, visit the file or directory name you click on." (interactive "e") (let ((window (posn-window (event-end event))) (pos (posn-point (event-end event))) file) (if (not (windowp window)) (error "No file chosen")) (with-current-buffer (window-buffer window) (goto-char pos) (setq file (dired-get-file-for-visit))) (if (file-directory-p file) (or (and (cdr dired-subdir-alist) (dired-goto-subdir file)) (progn (select-window window) (dired-other-window file))) (select-window window) (find-file-other-window (file-name-sans-versions file t)))))
このコマンドはクリックがどこで発生したかを判断するために関数posn-window
とposn-point
、visitするファイルの判断に関数dired-get-file-for-visit
を使用します。
マウスコマンドをメジャーモードキーマップ内でバインドするかわりに、keymap
プロパティ(特殊な意味をもつプロパティを参照)を使用してリンクテキスト内でバインドできます。たとえば:
(let ((map (make-sparse-keymap))) (define-key map [mouse-2] 'operate-this-button) (put-text-property link-start link-end 'keymap map))
この手法により異なるリンクに異なるコマンドを簡単に定義できます。さらにそのバッファー内の残りのテキストにたいしては、RETとmouse-2のグローバル定義を利用可能なまま残すことができます。
リンク上でのクリックにたいするEmacsの基本コマンドはmouse-2です。しかし他のグラフィカルなアプリケーションとの互換性のために、ユーザーがマウスを動かさずに素早くリンクをクリックするという条件の下で、Emacsはリンク上でのmouse-1クリックも認識します。この振る舞いはユーザーオプションmouse-1-click-follows-link
により制御されます。Mouse
References in The GNU Emacs Manualを参照してください。
mouse-1-click-follows-link
にしたがうようにリンクをセットアップするには、(1)そのテキストにfollow-link
テキストプロパティまたはオーバーレイプロパティを適用する、または(2)follow-link
イベントをキーマップ(keymap
テキストプロパティを通じたメジャーモードキーマップまたはローカルキーマップ)にバインドするかの、いずれかを行わなければなりません。follow-link
プロパティの値、またはfollow-link
イベントにたいするバインディングはリンクアクションにたいするコンディション(condition)として機能します。この条件はEmacsにたいして2つのことを告げます。それはmouse-1のクリックがそのリンクの内側で発生したとみなすべき状況、そしてmouse-1のクリックを何に変換するかを告げるアクションコード(action
code)を計算する方法です。そのリンクのアクション条件は以下のうちの1つです:
mouse-face
コンディションがシンボルmouse-face
の場合には、その位置に非nil
のmouse-face
プロパティがあればそれはリンク内側の位置。アクションコードは常にt
。
以下はInfoモードがmouse-1を処理する例:
(keymap-set Info-mode-map "<follow-link>" 'mouse-face)
コンディションが関数funcの場合には、(func
pos)
が非nil
に評価されれば、位置posはリンクの内側。funcがリターンする値はアクションコードとして機能する。
以下はpcvsがファイル名の上でのみmouse-1によるリンクのフォローを有効にする方法の例:
(keymap-set map "<follow-link>" (lambda (pos) (eq (get-char-property pos 'face) 'cvs-filename-face)))
コンディション値がそれ以外の場合には、その位置はリンク内側であり、そのコンディション自体がアクションコード。(バッファー全体に適用されないように)リンクテキストのテキストプロパティかオーバーレイプロパティを通じてコンディションを適用するときのみ、この類のコンディションを指定すべきなのは明確である。
アクションコードはmouse-1がリンクをフォローする方法を告げます:
アクションコードが文字列かベクターなら、mouse-1イベントは文字列かベクターの最初の要素に変換される。つまりmouse-1クリックのアクションはその文字、またはシンボルのローカルかグローバルのバインディング。したがってアクションコードが"foo"
なら、mouse-1はf、[foo]
ならmouse-1はfooに変換される。
その他の非nil
のアクションコードでは、mouse-1イベントは同じ位置のmouse-2イベントに変換される。
define-button-type
で定義されるボタンをアクティブにするようにmouse-1を定義するには、そのボタンにfollow-link
プロパティを与えます。このプロパティの値は上述したリンクのアクションコンディションであるべきです。ボタンを参照のこと。たとえば以下はHelpモードがMouse-1を処理する例です。
(define-button-type 'help-xref 'follow-link t 'action #'help-button-action)
define-widget
で定義されたウィジェットにmouse-1を定義するには、そのウィジェットに:follow-link
プロパティを与えます。このプロパティの値は、上述したようなリンクのアクションコンディションであるべきです。たとえば以下はmouse-1クリックがRETに変換されるようにlink
ウィジェットを指定する方法の例です:
(define-widget 'link 'item "An embedded link." :button-prefix 'widget-link-prefix :button-suffix 'widget-link-suffix :follow-link "\C-m" :help-echo "Follow the link." :format "%[%t%]")
この関数はカレントバッファー内の位置posがリンク上なら非nil
をリターンする。posはevent-start
がリターンするようなマウスイベント位置でもよい(マウスイベントへのアクセスを参照)。