GNU Emacs 32.0.50 (9008bf64c3) のマニュアルを PLaMo 翻訳で機械翻訳したものです。誤訳を含むことがあります。原文: https://www.gnu.org/software/emacs/manual/html_node/elisp/Clickable-Text.html ・ emacs-doc.conao3.com

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

クリック可能なテキストとは、マウスまたはキーボード操作でクリックすることで、何らかの結果が得られるテキストのことです。多くの主要なモードでは、クリック可能なテキストを用いてテキストハイパーリンク、略してリンクを実装しています。

リンクを挿入・操作する最も簡単な方法は、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 の関数でクリックが発生した位置を、dired-get-file-for-visit でどのファイルにアクセスするかを判定します。

マウスコマンドをメジャーモードのキーマップにバインドする代わりに、keymap テキストプロパティ(特殊な意味を持つプロパティを参照)を使用して、リンクテキスト内にバインドすることもできます。例えば:

(let ((map (make-sparse-keymap)))
  (keymap-set 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で制御されます。The GNU Emacs ManualのMouse Referencesを参照してください。

リンクを mouse-1-click-follows-link に従うように設定するには、(1) リンクテキストに follow-link テキストまたはオーバーレイプロパティを適用するか、(2) follow-link イベントをキーマップ(メジャーモードのキーマップ、または keymap テキストプロパティで指定されるローカルキーマップ)にバインドする必要があります。follow-link プロパティの値、または follow-link イベントのバインドは、リンクアクションの条件として機能します。この条件は、mouse-1 クリックをリンク内部で発生したとみなすべき状況と、mouse-1 クリックを何に変換すべきかを示すアクションコードをどのように計算するかという2点を Emacs に伝えます。リンクアクションの条件は、以下のいずれかになります:

mouse-face

条件がシンボル mouse-face の場合、その位置に nil でも mouse-face でもないプロパティがあれば、その位置はリンク内となります。アクションコードは常に t です。

例えば、Info mode が 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 イベントはその文字列またはベクトルの第1要素に変換されます。つまり、mouse-1 クリックのアクションは、その文字または記号のローカルまたはグローバルバインディングとなります。したがって、アクションコードが "foo" であれば、mouse-1 は f に変換されます。[foo] であれば、mouse-1 は foo に変換されます。

その他

それ以外のnil以外のアクションコードの場合、mouse-1イベントは同じ位置のmouse-2イベントに変換されます。

define-button-type で定義されたボタンを有効化するために mouse-1 を定義するには、そのボタンに follow-link プロパティを指定します。このプロパティの値は、前述の通りリンクアクション条件とする必要があります。ボタンを参照してください。例えば、ヘルプモードでは mouse-1 を次のように処理します。

(define-button-type 'help-xref
  'follow-link t
  'action #'help-button-action)

define-widget で定義されたウィジェットに mouse-1 を定義するには、そのウィジェットに :follow-link プロパティを指定します。プロパティの値は、前述の通りリンクアクション条件とする必要があります。例えば、link ウィジェットで mouse-1 のクリックを RET にマッピングするように指定する方法は以下の通りです。

(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 によって返されるマウスイベントの発生位置である場合もあります(マウスイベントへのアクセス を参照)。