33.19.8 Определение кликабельного текста

Кликабельный текст — это текст, по которому можно кликнуть, либо мышью, либо с помощью команды клавиатуры, чтобы получить определенный результат. Многие основные режимы используют кликабельный текст для реализации текстовых гиперссылок или, вкратце, ссылок.

Самый простой способ вставки и манипулирования ссылками — использовать пакет button. См. Buttons. В этом разделе мы объясним, как вручную настроить кликабельный текст в буфере, используя свойства текста. Для простоты мы будем называть кликабельный текст ссылкой.

Реализация ссылки включает три отдельных шага: (1) указание кликабельности при наведении курсора на ссылку; (2) выполнение действия при нажатии RET или mouse-2 на этой ссылке; и (3) настройка условия follow-link, чтобы ссылка подчинялась mouse-1-click-follows-link.

Чтобы указать кликабельность, добавьте свойство текста mouse-face к тексту ссылки; тогда Emacs подсветит ссылку при наведении курсора. Кроме того, следует определить всплывающую подсказку или сообщение в области эхо, используя свойство текста help-echo. См. Properties with Special Meanings. Например, вот как 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)
  "В Dired посетите имя файла или каталога, на который вы кликнули."
  (interactive "e")
  (let ((window (posn-window (event-end event)))
        (pos (posn-point (event-end event)))
        file)
    (if (not (windowp window))
        (error "Файл не выбран"))
    (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 (см. Properties with Special Meanings). Например:

(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 в The GNU Emacs Manual.

Чтобы настроить ссылку так, чтобы она подчинялась mouse-1-click-follows-link, вы должны либо (1) применить свойство текста или оверлея follow-link к тексту ссылки, либо (2) привязать событие follow-link к карте команд (это может быть карта команд основного режима или локальная карта команд, указанная через свойство текста keymap). Значение свойства follow-link или привязка события follow-link действует как условие для действия ссылки. Это условие сообщает Emacs две вещи: обстоятельства, при которых клик mouse-1 должен считаться произошедшим внутри ссылки, и как вычислить код действия, который определяет, во что преобразовать клик mouse-1. Условие действия ссылки может быть одним из следующих:

mouse-face

Если условие — это символ mouse-face, позиция находится внутри ссылки, если в этой позиции есть свойство mouse-face, отличное от nil. Код действия всегда t.

Например, вот как Info-режим обрабатывает mouse-1:

(keymap-set Info-mode-map "<follow-link>" 'mouse-face)
функция

Если условие — это функция, func, то позиция pos находится внутри ссылки, если (func pos) оценивается как не-nil. Значение, возвращаемое 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 в той же позиции.

Чтобы определить mouse-1 для активации кнопки, определенной с помощью define-button-type, предоставьте кнопке свойство follow-link. Значение свойства должно быть условием действия ссылки, как описано выше. См. Buttons. Например, вот как Help-режим обрабатывает mouse-1:

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

Чтобы определить mouse-1 для виджета, определенного с помощью define-widget, предоставьте виджету свойство :follow-link. Значение свойства должно быть условием действия ссылки, как описано выше. Например, вот как виджет link указывает, что клик mouse-1 должен преобразовываться в RET:

(define-widget 'link 'item
  "Встроенная ссылка."
  :button-prefix 'widget-link-prefix
  :button-suffix 'widget-link-suffix
  :follow-link "\C-m"
  :help-echo "Перейти по ссылке."
  :format "%[%t%]")

Эта функция возвращает не-nil, если позиция pos в текущем буфере находится на ссылке. pos также может быть местоположением события мыши, возвращенным event-start (см. Accessing Mouse Events).