(redirected from HighLight)

HighlightLibrary

This page is about library highlight.el, which provides commands to highlight text.

Library `facemenu+.el' Puts Highlight on the Menu

If you load library facemenu+.el after you load library highlight.el, then the commands in library highlight.el are also available on a Highlight submenu in the Text Properties menus. See FaceMenuPlus for more about library facemenu+.el.

If you load library mouse3.el after you load library highlight.el then:

General Description

You can highlight text in two ways using highlight.el, depending on the value of user option ‘hlt-use-overlays-flag’:

Overlays are independent from the text itself. They are not picked up when you copy and paste text. By default, highlighting uses overlays.

User Option `hlt-use-overlays-flag'

Although highlighting recognizes only ‘nil’ and non-‘nil’ values for ‘hlt-use-overlays-flag’, other actions can have different behavior, depending on the non-‘nil’ value. If it is ‘only’ (the default value), then only overlay highlighting is affected. If it is any other non-‘nil’ value, then both overlay highlighting and text-property highlighting are effected. This is the case, for instance, for unhighlighting and for navigating among highlights.

For example, for unhighlighting, if ‘hlt-use-overlays-flag’ is non-‘nil’, then overlay highlighting is removed. If it is not ‘only’, then text-property highlighting is removed. A value of ‘nil’ thus removes both overlays and text properties.

Keep this sensitivity to the value of ‘hlt-use-overlays-flag’ in mind. For example, if you change the value after adding some highlighting, then that highlighting might not be removed by unhighlighting, unless you change the value back again.

You can toggle the value of ‘hlt-use-overlays-flag’ at any time between ‘nil’ and its previous non-‘nil’ value, using command ‘hlt-toggle-use-overlays-flag’.

Temporary or Permanent Highlighting

Generally, highlighting you add is temporary: it is not saved when you write your buffer to disk. However, Emacs has a curious and unfamiliar feature called “formatted” or “enriched” text mode, which does record highlighting permanently. See Enriched Mode.

To save highlighting permanently, do the following:

  1. ‘M-x enriched-mode’, to put your file buffer in minor mode ‘enriched-mode’. You see ‘Enriched’ in the mode line.
  2. Choose text-property highlighting, not overlay highlighting, by setting option `hlt-use-overlays-flag’ to ‘nil’. To do this using Customize, choose menu item Highlight using text properties, not overlays.
  3. Choose the highlight face to use: ‘M-x hlt-choose-default-face’.
  4. Highlight in any way provided by library highlight.el. For example, use ‘hlt-highlighter’ (I bind it to ‘C-x mouse-2’) to drag-highlight as if using a marker pen.
  5. Save your file. Note that, although highlighting in enriched-text mode modifies the buffer, it does not appear modified to Emacs (check the beginning of the mode line), so if you make no other changes then using ‘C-x C-s’ does not save your highlighting changes. To remedy this, just do something besides highlighting — e.g., add a space and delete it — so that ‘C-x C-s’ saves to disk.

When you reopen your file later, it is automatically in enriched mode, and your highlighting shows. However, be aware that font-locking interferes with enriched mode, so you will probably want to use it on files where you don’t use font-locking.

Commands

You can use any face to highlight, and you can highlight using the ‘mouse-face’ property instead of the ‘face’ property. A mouse face shows up only when the mouse pointer is over it.

The main command to choose a face to use for highlighting (or for unhighlighting) is ‘hlt-choose-default-face’. It reads a face name, with completion.

But you can alternatively choose a color name instead of a face name. The completion candidates are annotated in buffer ‘*Completions*’ with ‘Face’ or ‘Color’, to help you identify them.

If you use library Icicles and option `icicle-WYSIWYG-Completions-flag’ is non-nil, then candidate faces and colors are WYSIWYG: What You See Is What You Get. This page shows some some screenshots that give an idea of the effect (but for highlighting, candidates can be a mix of faces and colors – these screenshots show only colors.).

If you choose a color instead of a face then an unnamed pseudo face is created and used. It has the chosen color as background, and its foreground color is determined by the value of user option ‘hlt-auto-face-foreground’. If that option is ‘nil’ then highlighting does not change the existing foreground color. Otherwise, the option value is the foreground color used for highlighting.

Another way to choose the highlighting face is to use command ‘hlt-next-face’ or ‘hlt-previous-face’. These cycle among a smaller set of faces and background colors, the elements in the list value of option ‘hlt-auto-face-backgrounds’. You can use a numeric prefix argument with these commands to choose any of the elements by its absolute position in the list.

Choosing the default highlighting face using ‘hlt-choose-default-face’, ‘hlt-next-face’, or ‘hlt-previous-face’ affects the next highlighting or unhighlighting operation. You can also choose to automatically cycle among the faces defined by ‘hlt-auto-face-backgrounds’, with each (un)highlighting command using the next face in the list. To choose this behavior, customize option ‘hlt-auto-faces-flag’ to non-‘nil’.

The commands with ‘region’ in their name act on the text in the active region. If the region is not active then they act on the text in the whole buffer. The commands with ‘to-end’ in their name act on the text from point to the end of the buffer. See also What Gets Highlighted: Region, Buffer, New Text You Type, below.

The commands you will use the most often are perhaps ‘hlt-highlight’, ‘hlt-highlighter’, ‘hlt-next-highlight’, and ‘hlt-previous-highlight’. You might also often use the various commands to hide and show highlighted text.

You can use command ‘hlt-highlight’ to highlight or unhighlight the region, or to highlight or unhighlight a regexp throughout the region, depending on the prefix argument. It combines the behaviors of commands ‘hlt-highlight-region’, ‘hlt-unhighlight-region’, ‘hlt-highlight-regexp-region’, and ‘hlt-unhighlight-regexp-region’. I suggest that you bind ‘hlt-highlight’ to a key — I use ‘C-x C-y’.

Commands ‘hlt-highlight-regexp-to-end’ and ‘hlt-unhighlight-regexp-to-end’ highlight and unhighlight a regexp from point to the end of the buffer, respectively.

Command ‘hlt-highlighter’ lets you highlight text by simply dragging the mouse, just as you would use a highlighter (marker). You can thus highlight text the same way that you drag the mouse to define the region. (Bind this to, for instance, ‘C-x mouse-2’.)

Command ‘hlt-eraser’ lets you delete highlighting by dragging the mouse. However, its behavior is quite different for overlays and text properties, and it is perhaps different from you expect. If option ‘hlt-use-overlays-flag’ is not ‘only’ then it removes text-property highlighting for ALL faces (not just highlighting faces).

A prefix arg for ‘hlt-highlighter’ and ‘hlt-eraser’ acts the same as for ‘hlt-next-face’: it lets you choose the face to use. It has no effect for ‘hlt-eraser’ unless ‘hlt-use-overlays-flag’ is ‘only’, in which case it erases the Nth face in ‘hlt-auto-face-backgrounds’, where N is the prefix arg.

If you use Emacs 21 or later, you can use various commands that highlight and unhighlight text that has certain text properties with given values. You can use them to highlight all text in the region or buffer that has a given property value. An example is highlighting all links (text with property ‘mouse-face’). These commands are:

As always for library highlight.el, this “highlighting” can use property ‘mouse-face’ instead of ‘face’. You could, for example, highlight, using ‘mouse-face’, all text that has property ‘foo’ – or that has property ‘face’, for that matter.

If you use Emacs 21 or later, you can use commands ‘hlt-next-highlight’ and ‘hlt-previous-highlight’ to navigate among highlights of a given face. (Bind these to, for instance, ‘S-C-n’ and ‘S-C-p’.)

See Also: Icicles - Other Search Commands#SearchingTextProperties for other, more general ways to navigate among highlighted zones.

You can unhighlight the region/buffer or a regexp in the region/buffer using command ‘hlt-unhighlight-region’ or ‘hlt-unhighlight-regexp-region’. If you use overlay highlighting then you can use command ‘hlt-unhighlight-region-for-face’ to unhighlight the region/buffer for an individual highlighting face – other highlighting faces remain.

You can replace a highlighting face in the region/buffer by another, using command ‘hlt-replace-highlight-face’. With a prefix argument, property ‘mouse-face’ is used, not property ‘face’.

Command ‘hlt-highlight-single-quotations’ highlights single-quoted text in the region. For example, Emacs commands and keys between ` and ': ‘foobar’.

Command ‘hlt-mouse-face-each-line’ puts a ‘mouse-face’ property on each line of the region.

Finally, you can highlight and unhighlight multiple buffers at the same time. Just as for a single buffer, there are commands for regexp (un)highlighting, and all of the multiple-buffer commands, whose names end in ‘-in-buffers’, are sensitive to the region in each buffer, when active. These are the multiple-buffer commands:

Normally, you are prompted for the names of the buffers, one at a time. Use ‘C-g’ when you are done entering buffer names. But a non-positive prefix arg means act on all visible or iconified buffers. (A non-negative prefix arg means use property ‘mouse-face’, not ‘face’.)

Copy and Yank (Paste) Text Properties

You can highlight or unhighlight text by simply copying existing highlighting (or lack of any highlighting) from anywhere in Emacs and yanking (pasting) it anywhere else.

Put differently, you can copy and yank a set of text properties. You can use these commands to copy and yank any text properties, not just ‘face’ or ‘mouse-face’.

To copy the text properties at a given position, use command ‘hlt-copy-props’. You can then use command ‘hlt-yank-props’ to yank those properties to the active region anywhere. If the set of properties that you copy is empty, then yanking means effectively removing all text properties.

User option ‘hlt-default-copy/yank-props’ controls which text properties to copy and yank, by default. The default value of the option includes only ‘face’, which means that only property ‘face’ is copied and pasted. That is typically what you want, for highlighting purposes. You can set the option value to any list of properties or to ‘t’, meaning copy/yank all text properties present.

You can further control which text properties are copied or yanked when you use the commands, by using a prefix argument. A plain or non-negative prefix arg means copy or yank all available text properties. A negative prefix arg (e.g. ‘C--’) means you are prompted for which text properties to use, among those available.

For copying, the available properties are those among ‘hlt-default-copy/yank-props’ that are present at the copy position. For yanking, the available properties are those among ‘hlt-default-copy/yank-props’ that have previously (last) been copied.

User Option `hlt-act-on-any-face-flag'

Library ‘highlight’ generally acts only on faces that it controls, that is, faces that you have explicitly asked it to use for highlighting. It sets the text property or overlay property ‘hlt-highlight’ on such highlighted text, so that it can recognize which faces it has responsibility for.

Sometimes, you might want to hide and show text other than that controlled by library ‘highlight’. Similarly, you might sometimes want to navigate among faces other than those used for highlighting. You can control this using option ‘hlt-act-on-any-face-flag’, which you can toggle at any time using command ‘hlt-toggle-act-on-any-face-flag’.

Hiding and Showing Text

You can hide and show text that you have highlighted. You will want to read the EmacsLisp manual (Elisp), section Invisible Text, to understand better what this entails. In particular, you should understand that for library highlight.el, hiding text means adding the symbol naming the face to be hidden to both:

1. a text or overlay ‘invisible’ property, making the text or overlay susceptible to being hidden by buffer-local variable ‘buffer-invisibility-spec’, and

2. the buffer’s ‘buffer-invisibility-spec’, so that it in fact becomes hidden.

After text has been hidden this way, and unless the highlighting as been removed completely by unhighlighting the text, the ‘invisible’ property of that text keeps the names of the faces that have been applied to that text and hidden previously, even after you show that text again. Showing a hidden face simply removes it from the ‘buffer-invisibility-spec’; it does not change any ‘invisible’ properties.

For example, if you hide face ‘foo’ at some buffer position:

1. The ‘invisible’ property of the text or overlay at that position is updated to include ‘foo’. If there are no other faces that have been applied to this text and then hidden, the ‘invisible’ property is just (foo).

2. ‘buffer-invisibility-spec’ is also updated to include ‘foo’. This hides all text properties and overlay properties with ‘invisible’ property ‘foo’, throughout the buffer. If there are no other invisible faces in the buffer, then ‘buffer-invisibility-spec’ has value (foo).

If you then show face ‘foo’ at that same buffer position, there is no change to the ‘invisible’ property. ‘buffer-invisibility-spec’ is updated, by removing ‘foo’: if it was (foo), it becomes ().

There are several commands for hiding and showing highlighted text. The basic commands for hiding and showing are ‘hlt-hide-default-face’ and ‘hlt-show-default-face’, which you can use to hide and show the face last used for highlighting. With a prefix argument, you are prompted for a different face to hide; it then becomes the default face for highlighting. You can also change the default highlighting face at any time using command ‘hlt-choose-default-face’.

The other hide and show commands depend on your also using Icicles, which is a set of libraries that offer enhanced completion. The Icicles-dependent commands are the following:

  `hlt-choose-faces', `hlt-choose-invisible-faces',
  `hlt-choose-visible-faces', `hlt-hide', `hlt-hide-only',
  `hlt-show', `hlt-show-only'

These are all multi-commands (see Icicles - Multi-Commands), which means that they each let you choose multiple completion candidates or all candidates that match your current input (a regexp). You can use command ‘hlt-hide’ to hide any number of visible faces. Any text is hidden that has that face as a text property or an overlay property, depending on the value of ‘hlt-use-overlays-flag’.

Command ‘hlt-show’ is the opposite of ‘hlt-hide’: it shows invisible text that has the faces you choose. Neither ‘hlt-hide’ nor ‘hlt-show’ has any effect on other faces, besides those you choose to hide or show, respectively; they each do only one thing, hide or show.

Command ‘hlt-hide-only’ hides the faces you choose, and shows all other faces, and command ‘hlt-show-only’ does the opposite. You can thus use these commands to specify exactly what faces should be invisible and visible. Empty input means none: If you choose no faces to hide (that is, hit ‘RET’ with an empty minibuffer), then all faces are made visible; if you choose no faces to show, then all are hidden.

Currently, face attributes for highlighting are combined when overlays overlap, but the same is not true for text properties. For example, if you highlight a word with face ‘foo’, and then you highlight it with face ‘bar’, only ‘bar’ remains as the face for that word. With overlays, the attributes of the two faces are composed. When you hide or show faces, this behavior difference has an effect.

You can hide text using the commands in this library for any of the purposes that you might use invisible text in Emacs. This gives you an easy, interactive way to control which sections of text are seen by search and other Emacs tools. Use the regexp highlighting commands, for instance, to highlight text syntactically, and then hide that highlighted text. Or use ‘hlt-highlighter’ to sweep over text that you want to hide with the mouse.

Hiding and showing faces also provides a “conditional text” feature similar to that available in desktop publishing applications such as Adobe Framemaker. Publishers often use such a feature to produce different output documents from the same source document (”single sourcing”). You can use this feature similarly, if you have an application (printing is one example) that is sensitive to whether text is visible or invisible. One caveat: Emacs faces are not saved when you save your file.

What Gets Highlighted: Region, Buffer, New Text You Type

Most mention of the “region” in this commentary should really say “active region or buffer”. If the region is active and non-empty, then only the text in the region is targeted by the commands in this library. This lets you easily control the scope of operations.

If the region is not active or it is empty, then:

- If ‘hlt-use-overlays-flag’ is ‘nil’ and there is no prefix arg, then the face is applied to the next characters that you type.

- Otherwise, the face is applied to the entire buffer (or the current restriction, if the buffer is narrowed).

Interference by Font Lock

If you use Emacs 22 or later, then you can use library highlight.el in conjunction with library font-lock+.el (it is loaded automatically, if available). That prevents font-locking from removing any highlighting face properties that you apply using the commands defined here.

[If you also load library facemenu+.el, then the same applies to highlighting that you apply using the face menu (see FaceMenuPlus): that highlighting is also protected from interference by font lock.]

Otherwise, when ‘hlt-use-overlays-flag’ is ‘nil’, font-lock highlighting interferes with the highlighting of this library. In most cases, you can still highlight text, but sooner or later font-lock erases that highlighting when it refontifies the buffer. If ‘hlt-use-overlays-flag’ is non-‘nil’, there is no such problem : font-lock has no effect on overlays.

Suggested bindings

Library ‘highlight’ binds many of its commands to keys on the prefix key ‘C-x X’. It also adds menu items to the ‘Region’ submenu of the Edit menu-bar menu, if you have a Region submenu. To obtain this menu, load library menu-bar+.el.

Library `highlight.el’ makes no other key bindings. Here are some additional, suggested bindings (‘C-x y’, ‘C-x mouse-2’, ‘C-x S-mouse-2’, ‘S-C-p’, and ‘S-C-n’):

 (define-key ctl-x-map [(control ?y)]     'hlt-highlight)
 (define-key ctl-x-map [(down-mouse-2)]   'hlt-highlighter)
 (define-key ctl-x-map [(S-down-mouse-2)] 'hlt-eraser)
 (global-set-key [(shift control ?p)]     'hlt-previous-highlight) ; Emacs 21+
 (global-set-key [(shift control ?n)]     'hlt-next-highlight) ; Emacs 21+

See Also

Commands That Won't Work in Emacs 20

The following commands and options work only for Emacs versions more recent than Emacs 20:

  `hlt-act-on-any-face-flag', `hlt-choose-faces',
  `hlt-choose-invisible-faces', `hlt-choose-visible-faces',
  `hlt-hide', `hlt-hide-default-face', `hlt-hide-only',
  `hlt-next-highlight', `hlt-previous-highlight', `hlt-show',
  `hlt-show-default-face', `hlt-show-only',
  `hlt-toggle-act-on-any-face-flag'
Here is a screenshot showing highlighting with ‘hlt-highlight-single-quotations’:
DrewsEmacsHighlight

Discussion

I tried to use ‘hlt-highlight-regexp-region’ (with default settings) in my Lisp program to highlight a non font-locking buffer by regexp. But it is 100x slower than while/re-search-forward/put-text-property version. – rubikitch

Such limited feedback is not helpful, unfortunately. Please send a proper bug report, with details. ‘hlt-highlight-regexp-region’ does precisely the search and ‘put-text-property’ that you mention, but it can also do more. Performance can only be discussed after some detailed analysis. Please look in more detail for where the apparent slowdown occurs. Thx. – DrewAdams

Test file is here: http://www.rubyist.net/~rubikitch/archive/command.txt

(defun newbuf ()
  (kill-buffer (get-buffer-create "*highlight test*"))
  (with-current-buffer (get-buffer-create "*highlight test*")
    (insert-file-contents "/tmp/command.txt")
    (display-buffer (current-buffer))))

(defun my-highlight (regexp)
  (save-excursion
    (set-buffer "*highlight test*")
    (goto-char 1)
    (let (me)
      (while (and (setq me (re-search-forward regexp nil t)) (< (point) (point-max)))
        (put-text-property (match-beginning 0) me 'face 'highlight)))))
  
(defun highlight-el-highlight (regexp way)
  (let ((hlt-use-overlays-flag way))
    (save-excursion
      (set-buffer "*highlight test*")
      (hlt-highlight-regexp-region 1 (point-max) regexp 'highlight))))

(newbuf)
(benchmark-run 1 (my-highlight "command")) ; => (0.010105 0 0.0)|(0.016 0 0.0)
(benchmark-run 1 (my-highlight "command")) ; => (0.008182 0 0.0)|(0.0 0 0.0)
(benchmark-run 1 (my-highlight "command")) ; => (0.008342 0 0.0)|(0.0 0 0.0)
(benchmark-run 1 (my-highlight "command")) ; => (0.008312 0 0.0)|(0.0 0 0.0)
(newbuf)
(benchmark-run 1 (highlight-el-highlight "command" 'only)) ; => (0.6560950000000001 0 0.0)|(0.125 0 0.0)
(benchmark-run 1 (highlight-el-highlight "command" 'only)) ; => (1.449072 0 0.0)|(0.23399999999999999 0 0.0)
(benchmark-run 1 (highlight-el-highlight "command" 'only)) ; => (2.924364 0 0.0)|(0.375 1 0.06299999999999972)
(benchmark-run 1 (highlight-el-highlight "command" 'only)) ; => (4.708601 0 0.0)|(0.422 0 0.0)
(newbuf)
(benchmark-run 1 (highlight-el-highlight "command" nil)) ; => (0.127139 0 0.0)|(0.094 1 0.04699999999999971)
(benchmark-run 1 (highlight-el-highlight "command" nil)) ; => (0.130912 0 0.0)|(0.016 0 0.0)
(benchmark-run 1 (highlight-el-highlight "command" nil)) ; => (0.13116400000000006 0 0.0)|(0.078 1 0.06200000000000028)
(benchmark-run 1 (highlight-el-highlight "command" nil)) ; => (0.13116 0 0.0)|(0.031 0 0.0)
(newbuf)
(benchmark-run 1 (highlight-el-highlight "command" t)) ; => (0.664406 0 0.0)|(0.188 1 0.06299999999999972)
(benchmark-run 1 (highlight-el-highlight "command" t)) ; => (1.373779 0 0.0)|(0.219 0 0.0)
(benchmark-run 1 (highlight-el-highlight "command" t)) ; => (2.780717 0 0.0)|(0.312 0 0.0)
(benchmark-run 1 (highlight-el-highlight "command" t)) ; => (4.934234 0 0.0)|(0.469 1 0.06200000000000028)

I learned that I should use text properties possible by this result. – rubikitch

What I meant by “analysis” was some attempt to try to see where performance is affected. That’s the only way to help improve code performance.

Again, when text properties are used, the highlight.el code does the same thing as yours: loop over ‘re-search-forward’ + ‘put-text-property’.

Obviously, it is some of the other processing done that makes a difference here. That’s the question. If all you need to do is a proper subset of what ‘hlt-highlight-regexp-region’ does, then yes, it makes sense that a proper subset takes less time. If you only need to search for regexp matches and add text properties, then do only that, as you have done.

Anyway, FWIW, I’ve added the times I see to the right of yours, above, after `|’. And here are some byte-compiled times I see, FWIW:

(newbuf)
(benchmark-run-compiled 1 (my-highlight "command")) ; => ???|(0.0 0 0.0)
(benchmark-run-compiled 1 (my-highlight "command")) ; => ???|(0.015 0 0.0)
(benchmark-run-compiled 1 (my-highlight "command")) ; => ???|(0.0 0 0.0)
(benchmark-run-compiled 1 (my-highlight "command")) ; => ???|(0.078 1 0.06299999999999972)
(newbuf)
(benchmark-run-compiled 1 (highlight-el-highlight "command" 'only)) ; => ???|(0.125 0 0.0)
(benchmark-run-compiled 1 (highlight-el-highlight "command" 'only)) ; => ???|(0.218 0 0.0)
(benchmark-run-compiled 1 (highlight-el-highlight "command" 'only)) ; => ???|(0.375 1 0.07800000000000029)
(benchmark-run-compiled 1 (highlight-el-highlight "command" 'only)) ; => ???|(0.422 0 0.0)
(newbuf)
(benchmark-run-compiled 1 (highlight-el-highlight "command" nil)) ; => ???|(0.032 0 0.0)
(benchmark-run-compiled 1 (highlight-el-highlight "command" nil)) ; => ???|(0.093 1 0.06299999999999972)
(benchmark-run-compiled 1 (highlight-el-highlight "command" nil)) ; => ???|(0.016 0 0.0)
(benchmark-run-compiled 1 (highlight-el-highlight "command" nil)) ; => ???|(0.031 0 0.0)
(newbuf)
(benchmark-run-compiled 1 (highlight-el-highlight "command" t)) ; => ???|(0.188 1 0.06300000000000061)
(benchmark-run-compiled 1 (highlight-el-highlight "command" t)) ; => ???|(0.218 0 0.0)
(benchmark-run-compiled 1 (highlight-el-highlight "command" t)) ; => ???|(0.297 0 0.0)
(benchmark-run-compiled 1 (highlight-el-highlight "command" t)) ; => ???|(0.40599999999999997 0 0.0)

These times are all with Emacs 22.3 on MS Windows. I ran the same test with a Windows Emacs 23 pretest build, and the times are just about the same as for Emacs 22.

And yes, overlays are costly – typically O(N), where N is the number of overlays in the buffer. Text properties are typically O(log N). – DrewAdams


DrewsElispLibraries mentioned here: Lisp:facemenu+.el, Lisp:font-lock+.el, Lisp:highlight.el.

CategoryFaces CategoryHideStuff CategoryRegion