summaryrefslogtreecommitdiff
path: root/devdocs/elisp/clickable-text.html
blob: f4a90bbf3d342aa576b7d35cc374460b78997bd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
 <h4 class="subsection">Defining Clickable Text</h4>    <p><em>Clickable text</em> is text that can be clicked, with either the mouse or via a keyboard command, to produce some result. Many major modes use clickable text to implement textual hyper-links, or <em>links</em> for short. </p> <p>The easiest way to insert and manipulate links is to use the <code>button</code> package. See <a href="buttons">Buttons</a>. In this section, we will explain how to manually set up clickable text in a buffer, using text properties. For simplicity, we will refer to the clickable text as a <em>link</em>. </p> <p>Implementing a link involves three separate steps: (1) indicating clickability when the mouse moves over the link; (2) making <tt class="key">RET</tt> or <kbd>mouse-2</kbd> on that link do something; and (3) setting up a <code>follow-link</code> condition so that the link obeys <code>mouse-1-click-follows-link</code>. </p> <p>To indicate clickability, add the <code>mouse-face</code> text property to the text of the link; then Emacs will highlight the link when the mouse moves over it. In addition, you should define a tooltip or echo area message, using the <code>help-echo</code> text property. See <a href="special-properties">Special Properties</a>. For instance, here is how Dired indicates that file names are clickable: </p> <div class="example"> <pre class="example"> (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")))
</pre>
</div> <p>To make the link clickable, bind <tt class="key">RET</tt> and <kbd>mouse-2</kbd> to commands that perform the desired action. Each command should check to see whether it was called on a link, and act accordingly. For instance, Dired’s major mode keymap binds <kbd>mouse-2</kbd> to the following command: </p> <div class="example"> <pre class="example">(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)))))
</pre>
</div> <p>This command uses the functions <code>posn-window</code> and <code>posn-point</code> to determine where the click occurred, and <code>dired-get-file-for-visit</code> to determine which file to visit. </p> <p>Instead of binding the mouse command in a major mode keymap, you can bind it within the link text, using the <code>keymap</code> text property (see <a href="special-properties">Special Properties</a>). For instance: </p> <div class="example"> <pre class="example">(let ((map (make-sparse-keymap)))
  (define-key map [mouse-2] 'operate-this-button)
  (put-text-property link-start link-end 'keymap map))
</pre>
</div> <p>With this method, you can easily define different commands for different links. Furthermore, the global definition of <tt class="key">RET</tt> and <kbd>mouse-2</kbd> remain available for the rest of the text in the buffer. </p>  <p>The basic Emacs command for clicking on links is <kbd>mouse-2</kbd>. However, for compatibility with other graphical applications, Emacs also recognizes <kbd>mouse-1</kbd> clicks on links, provided the user clicks on the link quickly without moving the mouse. This behavior is controlled by the user option <code>mouse-1-click-follows-link</code>. See <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Mouse-References.html#Mouse-References">Mouse References</a> in <cite>The GNU Emacs Manual</cite>. </p>  <p>To set up the link so that it obeys <code>mouse-1-click-follows-link</code>, you must either (1) apply a <code>follow-link</code> text or overlay property to the link text, or (2) bind the <code>follow-link</code> event to a keymap (which can be a major mode keymap or a local keymap specified via the <code>keymap</code> text property). The value of the <code>follow-link</code> property, or the binding for the <code>follow-link</code> event, acts as a condition for the link action. This condition tells Emacs two things: the circumstances under which a <kbd>mouse-1</kbd> click should be regarded as occurring inside the link, and how to compute an action code that says what to translate the <kbd>mouse-1</kbd> click into. The link action condition can be one of the following: </p> <dl compact> <dt><code>mouse-face</code></dt> <dd>
<p>If the condition is the symbol <code>mouse-face</code>, a position is inside a link if there is a non-<code>nil</code> <code>mouse-face</code> property at that position. The action code is always <code>t</code>. </p> <p>For example, here is how Info mode handles <tt class="key">mouse-1</tt>: </p> <div class="example"> <pre class="example">(define-key Info-mode-map [follow-link] 'mouse-face)
</pre>
</div> </dd> <dt>a function</dt> <dd>
<p>If the condition is a function, <var>func</var>, then a position <var>pos</var> is inside a link if <code>(<var>func</var> <var>pos</var>)</code> evaluates to non-<code>nil</code>. The value returned by <var>func</var> serves as the action code. </p> <p>For example, here is how pcvs enables <kbd>mouse-1</kbd> to follow links on file names only: </p> <div class="example"> <pre class="example">(define-key map [follow-link]
  (lambda (pos)
    (eq (get-char-property pos 'face) 'cvs-filename-face)))
</pre>
</div> </dd> <dt>anything else</dt> <dd><p>If the condition value is anything else, then the position is inside a link and the condition itself is the action code. Clearly, you should specify this kind of condition only when applying the condition via a text or overlay property on the link text (so that it does not apply to the entire buffer). </p></dd> </dl> <p>The action code tells <kbd>mouse-1</kbd> how to follow the link: </p> <dl compact> <dt>a string or vector</dt> <dd>
<p>If the action code is a string or vector, the <kbd>mouse-1</kbd> event is translated into the first element of the string or vector; i.e., the action of the <kbd>mouse-1</kbd> click is the local or global binding of that character or symbol. Thus, if the action code is <code>"foo"</code>, <kbd>mouse-1</kbd> translates into <kbd>f</kbd>. If it is <code>[foo]</code>, <kbd>mouse-1</kbd> translates into <tt class="key">foo</tt>. </p> </dd> <dt>anything else</dt> <dd><p>For any other non-<code>nil</code> action code, the <kbd>mouse-1</kbd> event is translated into a <kbd>mouse-2</kbd> event at the same position. </p></dd> </dl> <p>To define <kbd>mouse-1</kbd> to activate a button defined with <code>define-button-type</code>, give the button a <code>follow-link</code> property. The property value should be a link action condition, as described above. See <a href="buttons">Buttons</a>. For example, here is how Help mode handles <kbd>mouse-1</kbd>: </p> <div class="example"> <pre class="example">(define-button-type 'help-xref
  'follow-link t
  'action #'help-button-action)
</pre>
</div> <p>To define <kbd>mouse-1</kbd> on a widget defined with <code>define-widget</code>, give the widget a <code>:follow-link</code> property. The property value should be a link action condition, as described above. For example, here is how the <code>link</code> widget specifies that a <tt class="key">mouse-1</tt> click shall be translated to <tt class="key">RET</tt>: </p> <div class="example"> <pre class="example">(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%]")
</pre>
</div> <dl> <dt id="mouse-on-link-p">Function: <strong>mouse-on-link-p</strong> <em>pos</em>
</dt> <dd><p>This function returns non-<code>nil</code> if position <var>pos</var> in the current buffer is on a link. <var>pos</var> can also be a mouse event location, as returned by <code>event-start</code> (see <a href="accessing-mouse">Accessing Mouse</a>). </p></dd>
</dl><div class="_attribution">
  <p class="_attribution-p">
    Copyright &copy; 1990-1996, 1998-2022 Free Software Foundation, Inc. <br>Licensed under the GNU GPL license.<br>
    <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Clickable-Text.html" class="_attribution-link">https://www.gnu.org/software/emacs/manual/html_node/elisp/Clickable-Text.html</a>
  </p>
</div>