Next: , Previous: , Up: Text Properties   [Contents][Index]


31.19.8 クリック可能なテキストの定義

クリック可能テキスト(clickable text)とは何らかの結果を生成するためにマウスやキーボードコマンドを通じてクリックできるテキストです。多くのメジャーモードがテキスト的なハイパーリンク、略してリンク(link)を実装するためにクリック可能テキストを使用しています。

リンクの挿入や操作を行うもっとも簡単な方法はbuttonパッケージの使用です。Buttonsを参照してください。このセクションではテキストプロパティを使用してバッファー内に手作業でクリック可能テキストをセットアップする方法を説明します。簡略にするためにクリック可能テキストをリンクと呼ぶことにします。

リンクの実装には、(1)リンク上にマウスが移動した際にクリック可能であることを示し、(2)そのリンク上のRETmouse-2で何かを行うようにして、(3)そのリンクがmouse-1-click-follows-linkにしたがうようfollow-linkをセットアップする、という3つのステップが含まれます。

クリック可能なことを示すためには、そのリンクのテキストにmouse-faceプロパティを追加します。するとEmacsはそれ以降マウスがその上に移動した際にリンクをハイライトするでしょう。加えてhelp-echoテキストプロパティを使用してツールチップかエコーエリアメッセージを定義するべきです。Special Propertiesを参照してください。たとえば以下は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")))

リンクをクリック可能にするためには、 RETmouse-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-windowposn-point、visitするファイルの判断に関数dired-get-file-for-visitを使用します。

マウスコマンドをメジャーモードキーマップ内でバインドするかわりに、keymapプロパティ(Special Propertiesを参照)を使用してリンクテキスト内でバインドできます。たとえば:

(let ((map (make-sparse-keymap)))
  (define-key map [mouse-2] 'operate-this-button)
  (put-text-property link-start link-end 'keymap map))

この手法により異なるリンクに異なるコマンドを簡単に定義できます。さらにそのバッファー内の残りのテキストにたいしては、RETmouse-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の場合には、その位置に非nilmouse-faceプロパティがあればそれはリンク内側の位置。アクションコードは常にt

以下はInfoモードがmouse-1を処理する例:

(define-key Info-mode-map [follow-link] 'mouse-face)
関数

コンディションが関数funcの場合には、(func pos)が非nilに評価されれば、位置posはリンクの内側。funcがリターンする値はアクションコードとして機能する。

以下はpcvsがファイル名の上でのみmouse-1によるリンクのフォローを有効にする方法の例:

(define-key map [follow-link]
  (lambda (pos)
    (eq (get-char-property pos 'face) 'cvs-filename-face)))
その他

コンディション値がそれ以外の場合には、その位置はリンク内側であり、そのコンディション自体がアクションコード。(バッファー全体に適用されないように)リンクテキストのテキストプロパティかオーバーレイプロパティを通じてコンディションを適用するときのみ、この類のコンディションを指定すべきなのは明確である。

アクションコードはmouse-1がリンクをフォローする方法を告げます:

文字列かベクター

アクションコードが文字列かベクターなら、mouse-1イベントは文字列かベクターの最初の要素に変換される。つまりmouse-1クリックのアクションはその文字、またはシンボルのローカルかグローバルのバインディング。したがってアクションコードが"foo"なら、mouse-1f[foo]ならmouse-1fooに変換される。

その他

その他の非nilのアクションコードでは、mouse-1イベントは同じ位置のmouse-2イベントに変換される。

define-button-typeで定義されるボタンをアクティブにするようにmouse-1を定義するには、そのボタンにfollow-linkプロパティを与えます。このプロパティの値は上述したリンクのアクションコンディションであるべきです。Buttonsを参照のこと。たとえば以下は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をリターンする。posevent-startがリターンするようなマウスイベント位置でもよい(Accessing Mouseを参照)。