* novice.el (disabled-command-function): Remove a spurious help xref.
[bpt/emacs.git] / lisp / hi-lock.el
CommitLineData
853c1ffc 1;;; hi-lock.el --- minor mode for interactive automatic highlighting -*- lexical-binding: t -*-
abb2db1c 2
acaf905b 3;; Copyright (C) 2000-2012 Free Software Foundation, Inc.
abb2db1c 4
4c120732 5;; Author: David M. Koppelman <koppel@ece.lsu.edu>
abb2db1c
GM
6;; Keywords: faces, minor-mode, matching, display
7
8;; This file is part of GNU Emacs.
9
eb3fa2cf 10;; GNU Emacs is free software: you can redistribute it and/or modify
abb2db1c 11;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
abb2db1c
GM
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
eb3fa2cf 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
abb2db1c 22
e8af40ee 23;;; Commentary:
71296446 24;;
abb2db1c
GM
25;; With the hi-lock commands text matching interactively entered
26;; regexp's can be highlighted. For example, `M-x highlight-regexp
27;; RET clearly RET RET' will highlight all occurrences of `clearly'
28;; using a yellow background face. New occurrences of `clearly' will
29;; be highlighted as they are typed. `M-x unhighlight-regexp RET'
30;; will remove the highlighting. Any existing face can be used for
31;; highlighting and a set of appropriate faces is provided. The
32;; regexps can be written into the current buffer in a form that will
c898bef7
CY
33;; be recognized the next time the corresponding file is read (when
34;; file patterns is turned on).
abb2db1c
GM
35;;
36;; Applications:
37;;
38;; In program source code highlight a variable to quickly see all
39;; places it is modified or referenced:
40;; M-x highlight-regexp ground_contact_switches_closed RET RET
41;;
42;; In a shell or other buffer that is showing lots of program
43;; output, highlight the parts of the output you're interested in:
44;; M-x highlight-regexp Total execution time [0-9]+ RET hi-blue-b RET
45;;
46;; In buffers displaying tables, highlight the lines you're interested in:
47;; M-x highlight-lines-matching-regexp January 2000 RET hi-black-b RET
48;;
49;; When writing text, highlight personal cliches. This can be
50;; amusing.
108ee42b 51;; M-x highlight-phrase as can be seen RET RET
abb2db1c 52;;
108ee42b 53;; Setup:
abb2db1c 54;;
865fe16f 55;; Put the following code in your init file. This turns on
108ee42b 56;; hi-lock mode and adds a "Regexp Highlighting" entry
abb2db1c
GM
57;; to the edit menu.
58;;
71060bdd 59;; (global-hi-lock-mode 1)
71296446 60;;
c898bef7 61;; To enable the use of patterns found in files (presumably placed
865fe16f 62;; there by hi-lock) include the following in your init file:
c898bef7
CY
63;;
64;; (setq hi-lock-file-patterns-policy 'ask)
65;;
66;; If you get tired of being asked each time a file is loaded replace
06b1a5ef 67;; `ask' with a function that returns t if patterns should be read.
c898bef7 68;;
abb2db1c
GM
69;; You might also want to bind the hi-lock commands to more
70;; finger-friendly sequences:
71
72;; (define-key hi-lock-map "\C-z\C-h" 'highlight-lines-matching-regexp)
73;; (define-key hi-lock-map "\C-zi" 'hi-lock-find-patterns)
74;; (define-key hi-lock-map "\C-zh" 'highlight-regexp)
108ee42b 75;; (define-key hi-lock-map "\C-zp" 'highlight-phrase)
abb2db1c
GM
76;; (define-key hi-lock-map "\C-zr" 'unhighlight-regexp)
77;; (define-key hi-lock-map "\C-zb" 'hi-lock-write-interactive-patterns))
78
79;; See the documentation for hi-lock-mode `C-h f hi-lock-mode' for
80;; additional instructions.
81
82;; Sample file patterns:
83
84; Hi-lock: (("^;;; .*" (0 (quote hi-black-hb) t)))
85; Hi-lock: ( ("make-variable-buffer-\\(local\\)" (0 font-lock-keyword-face)(1 'italic append)))))
86; Hi-lock: end
87
88;;; Code:
89
befe199d 90(require 'font-lock)
abb2db1c 91
f43eaaef 92(defgroup hi-lock nil
abb2db1c 93 "Interactively add and remove font-lock patterns for highlighting text."
f43eaaef
JL
94 :link '(custom-manual "(emacs)Highlight Interactively")
95 :group 'font-lock)
abb2db1c 96
abb2db1c
GM
97(defcustom hi-lock-file-patterns-range 10000
98 "Limit of search in a buffer for hi-lock patterns.
8b730780 99When a file is visited and hi-lock mode is on, patterns starting
abb2db1c
GM
100up to this limit are added to font-lock's patterns. See documentation
101of functions `hi-lock-mode' and `hi-lock-find-patterns'."
102 :type 'integer
f43eaaef 103 :group 'hi-lock)
abb2db1c 104
81dc5714
JL
105(defcustom hi-lock-highlight-range 200000
106 "Size of area highlighted by hi-lock when font-lock not active.
107Font-lock is not active in buffers that do their own highlighting,
108such as the buffer created by `list-colors-display'. In those buffers
109hi-lock patterns will only be applied over a range of
110`hi-lock-highlight-range' characters. If font-lock is active then
111highlighting will be applied throughout the buffer."
112 :type 'integer
113 :group 'hi-lock)
114
abb2db1c
GM
115(defcustom hi-lock-exclude-modes
116 '(rmail-mode mime/viewer-mode gnus-article-mode)
117 "List of major modes in which hi-lock will not run.
118For security reasons since font lock patterns can specify function
119calls."
f5bd8092 120 :type '(repeat symbol)
f43eaaef 121 :group 'hi-lock)
abb2db1c 122
cf995676 123(defcustom hi-lock-file-patterns-policy 'ask
c898bef7 124 "Specify when hi-lock should use patterns found in file.
06b1a5ef 125If `ask', prompt when patterns found in buffer; if bound to a function,
c898bef7 126use patterns when function returns t (function is called with patterns
06b1a5ef 127as first argument); if nil or `never' or anything else, don't use file
176eb1f1
GM
128patterns."
129 :type '(choice (const :tag "Do not use file patterns" never)
130 (const :tag "Ask about file patterns" ask)
131 (function :tag "Function to check file patterns"))
132 :group 'hi-lock
133 :version "22.1")
134
135;; It can have a function value.
136(put 'hi-lock-file-patterns-policy 'risky-local-variable t)
abb2db1c 137
b85aec93
J
138(defcustom hi-lock-auto-select-face nil
139 "Non-nil if highlighting commands should not prompt for face names.
140When non-nil, each hi-lock command will cycle through faces in
853c1ffc 141`hi-lock-face-defaults' without prompting."
b85aec93
J
142 :type 'boolean
143 :version "24.4")
144
abb2db1c
GM
145(defgroup hi-lock-faces nil
146 "Faces for hi-lock."
f43eaaef
JL
147 :group 'hi-lock
148 :group 'faces)
abb2db1c
GM
149
150(defface hi-yellow
e0d815a2 151 '((((min-colors 88) (background dark))
ea81d57e
DN
152 (:background "yellow1" :foreground "black"))
153 (((background dark)) (:background "yellow" :foreground "black"))
154 (((min-colors 88)) (:background "yellow1"))
a0b8c939 155 (t (:background "yellow")))
abb2db1c
GM
156 "Default face for hi-lock mode."
157 :group 'hi-lock-faces)
158
159(defface hi-pink
16cdf141 160 '((((background dark)) (:background "pink" :foreground "black"))
a0b8c939 161 (t (:background "pink")))
abb2db1c
GM
162 "Face for hi-lock mode."
163 :group 'hi-lock-faces)
164
165(defface hi-green
e0d815a2 166 '((((min-colors 88) (background dark))
ea81d57e
DN
167 (:background "green1" :foreground "black"))
168 (((background dark)) (:background "green" :foreground "black"))
e0d815a2 169 (((min-colors 88)) (:background "green1"))
a0b8c939 170 (t (:background "green")))
abb2db1c
GM
171 "Face for hi-lock mode."
172 :group 'hi-lock-faces)
173
174(defface hi-blue
16cdf141 175 '((((background dark)) (:background "light blue" :foreground "black"))
a0b8c939 176 (t (:background "light blue")))
abb2db1c
GM
177 "Face for hi-lock mode."
178 :group 'hi-lock-faces)
179
180(defface hi-black-b
181 '((t (:weight bold)))
182 "Face for hi-lock mode."
183 :group 'hi-lock-faces)
184
185(defface hi-blue-b
ea81d57e
DN
186 '((((min-colors 88)) (:weight bold :foreground "blue1"))
187 (t (:weight bold :foreground "blue")))
abb2db1c
GM
188 "Face for hi-lock mode."
189 :group 'hi-lock-faces)
190
191(defface hi-green-b
ea81d57e
DN
192 '((((min-colors 88)) (:weight bold :foreground "green1"))
193 (t (:weight bold :foreground "green")))
abb2db1c
GM
194 "Face for hi-lock mode."
195 :group 'hi-lock-faces)
196
197(defface hi-red-b
ea81d57e
DN
198 '((((min-colors 88)) (:weight bold :foreground "red1"))
199 (t (:weight bold :foreground "red")))
abb2db1c
GM
200 "Face for hi-lock mode."
201 :group 'hi-lock-faces)
202
203(defface hi-black-hb
c3b27206 204 '((t (:weight bold :height 1.67 :inherit variable-pitch)))
abb2db1c
GM
205 "Face for hi-lock mode."
206 :group 'hi-lock-faces)
207
208(defvar hi-lock-file-patterns nil
209 "Patterns found in file for hi-lock. Should not be changed.")
210
211(defvar hi-lock-interactive-patterns nil
212 "Patterns provided to hi-lock by user. Should not be changed.")
213
a52c0aa0
SM
214(define-obsolete-variable-alias 'hi-lock-face-history
215 'hi-lock-face-defaults "23.1")
ef705f25
JL
216(defvar hi-lock-face-defaults
217 '("hi-yellow" "hi-pink" "hi-green" "hi-blue" "hi-black-b"
218 "hi-blue-b" "hi-red-b" "hi-green-b" "hi-black-hb")
219 "Default faces for hi-lock interactive functions.")
abb2db1c 220
ef705f25
JL
221(define-obsolete-variable-alias 'hi-lock-regexp-history
222 'regexp-history
223 "23.1")
abb2db1c
GM
224
225(defvar hi-lock-file-patterns-prefix "Hi-lock"
c898bef7 226 "Search target for finding hi-lock patterns at top of file.")
abb2db1c 227
71060bdd 228(defvar hi-lock-archaic-interface-message-used nil
90756087 229 "True if user alerted that `global-hi-lock-mode' is now the global switch.
8b730780 230Earlier versions of hi-lock used `hi-lock-mode' as the global switch;
90756087 231the message is issued if it appears that `hi-lock-mode' is used assuming
71060bdd
EZ
232that older functionality. This variable avoids multiple reminders.")
233
234(defvar hi-lock-archaic-interface-deduce nil
90756087
JL
235 "If non-nil, sometimes assume that `hi-lock-mode' means `global-hi-lock-mode'.
236Assumption is made if `hi-lock-mode' used in the *scratch* buffer while
71060bdd
EZ
237a library is being loaded.")
238
abb2db1c
GM
239(make-variable-buffer-local 'hi-lock-interactive-patterns)
240(put 'hi-lock-interactive-patterns 'permanent-local t)
abb2db1c
GM
241(make-variable-buffer-local 'hi-lock-file-patterns)
242(put 'hi-lock-file-patterns 'permanent-local t)
243
b016851c
SM
244(defvar hi-lock-menu
245 (let ((map (make-sparse-keymap "Hi Lock")))
246 (define-key-after map [highlight-regexp]
247 '(menu-item "Highlight Regexp..." highlight-regexp
248 :help "Highlight text matching PATTERN (a regexp)."))
249
250 (define-key-after map [highlight-phrase]
251 '(menu-item "Highlight Phrase..." highlight-phrase
252 :help "Highlight text matching PATTERN (a regexp processed to match phrases)."))
253
254 (define-key-after map [highlight-lines-matching-regexp]
255 '(menu-item "Highlight Lines..." highlight-lines-matching-regexp
256 :help "Highlight lines containing match of PATTERN (a regexp)."))
257
258 (define-key-after map [unhighlight-regexp]
259 '(menu-item "Remove Highlighting..." unhighlight-regexp
260 :help "Remove previously entered highlighting pattern."
261 :enable hi-lock-interactive-patterns))
262
263 (define-key-after map [hi-lock-write-interactive-patterns]
264 '(menu-item "Patterns to Buffer" hi-lock-write-interactive-patterns
265 :help "Insert interactively added REGEXPs into buffer at point."
266 :enable hi-lock-interactive-patterns))
267
268 (define-key-after map [hi-lock-find-patterns]
269 '(menu-item "Patterns from Buffer" hi-lock-find-patterns
270 :help "Use patterns (if any) near top of buffer."))
271 map)
abb2db1c
GM
272 "Menu for hi-lock mode.")
273
b016851c
SM
274(defvar hi-lock-map
275 (let ((map (make-sparse-keymap "Hi Lock")))
276 (define-key map "\C-xwi" 'hi-lock-find-patterns)
277 (define-key map "\C-xwl" 'highlight-lines-matching-regexp)
278 (define-key map "\C-xwp" 'highlight-phrase)
279 (define-key map "\C-xwh" 'highlight-regexp)
280 (define-key map "\C-xwr" 'unhighlight-regexp)
281 (define-key map "\C-xwb" 'hi-lock-write-interactive-patterns)
282 map)
abb2db1c
GM
283 "Key map for hi-lock.")
284
abb2db1c
GM
285;; Visible Functions
286
abb2db1c 287;;;###autoload
71060bdd 288(define-minor-mode hi-lock-mode
06e21633
CY
289 "Toggle selective highlighting of patterns (Hi Lock mode).
290With a prefix argument ARG, enable Hi Lock mode if ARG is
291positive, and disable it otherwise. If called from Lisp, enable
292the mode if ARG is omitted or nil.
293
a9f6f311
CY
294Hi Lock mode is automatically enabled when you invoke any of the
295highlighting commands listed below, such as \\[highlight-regexp].
296To enable Hi Lock mode in all buffers, use `global-hi-lock-mode'
297or add (global-hi-lock-mode 1) to your init file.
298
299In buffers where Font Lock mode is enabled, patterns are
300highlighted using font lock. In buffers where Font Lock mode is
301disabled, patterns are applied using overlays; in this case, the
302highlighting will not be updated as you type.
303
304When Hi Lock mode is enabled, a \"Regexp Highlighting\" submenu
305is added to the \"Edit\" menu. The commands in the submenu,
306which can be called interactively, are:
abb2db1c
GM
307
308\\[highlight-regexp] REGEXP FACE
309 Highlight matches of pattern REGEXP in current buffer with FACE.
310
108ee42b
GM
311\\[highlight-phrase] PHRASE FACE
312 Highlight matches of phrase PHRASE in current buffer with FACE.
313 (PHRASE can be any REGEXP, but spaces will be replaced by matches
314 to whitespace and initial lower-case letters will become case insensitive.)
71296446 315
abb2db1c
GM
316\\[highlight-lines-matching-regexp] REGEXP FACE
317 Highlight lines containing matches of REGEXP in current buffer with FACE.
318
319\\[unhighlight-regexp] REGEXP
320 Remove highlighting on matches of REGEXP in current buffer.
321
322\\[hi-lock-write-interactive-patterns]
c898bef7 323 Write active REGEXPs into buffer as comments (if possible). They may
abb2db1c
GM
324 be read the next time file is loaded or when the \\[hi-lock-find-patterns] command
325 is issued. The inserted regexps are in the form of font lock keywords.
ee44464c 326 (See `font-lock-keywords'.) They may be edited and re-loaded with \\[hi-lock-find-patterns],
869d3e17
JB
327 any valid `font-lock-keywords' form is acceptable. When a file is
328 loaded the patterns are read if `hi-lock-file-patterns-policy' is
c898bef7
CY
329 'ask and the user responds y to the prompt, or if
330 `hi-lock-file-patterns-policy' is bound to a function and that
331 function returns t.
abb2db1c
GM
332
333\\[hi-lock-find-patterns]
334 Re-read patterns stored in buffer (in the format produced by \\[hi-lock-write-interactive-patterns]).
335
c898bef7
CY
336When hi-lock is started and if the mode is not excluded or patterns
337rejected, the beginning of the buffer is searched for lines of the
338form:
abb2db1c 339 Hi-lock: FOO
a9f6f311
CY
340
341where FOO is a list of patterns. The patterns must start before
342position \(number of characters into buffer)
343`hi-lock-file-patterns-range'. Patterns will be read until
344Hi-lock: end is found. A mode is excluded if it's in the list
345`hi-lock-exclude-modes'."
963b2040 346 :group 'hi-lock
90756087
JL
347 :lighter (:eval (if (or hi-lock-interactive-patterns
348 hi-lock-file-patterns)
349 " Hi" ""))
963b2040
CY
350 :global nil
351 :keymap hi-lock-map
71060bdd
EZ
352 (when (and (equal (buffer-name) "*scratch*")
353 load-in-progress
32226619 354 (not (called-interactively-p 'interactive))
71060bdd
EZ
355 (not hi-lock-archaic-interface-message-used))
356 (setq hi-lock-archaic-interface-message-used t)
357 (if hi-lock-archaic-interface-deduce
358 (global-hi-lock-mode hi-lock-mode)
359 (warn
360 "Possible archaic use of (hi-lock-mode).
361Use (global-hi-lock-mode 1) in .emacs to enable hi-lock for all buffers,
90756087 362use (hi-lock-mode 1) for individual buffers. For compatibility with Emacs
865fe16f 363versions before 22 use the following in your init file:
71060bdd
EZ
364
365 (if (functionp 'global-hi-lock-mode)
366 (global-hi-lock-mode 1)
367 (hi-lock-mode 1))
368")))
369 (if hi-lock-mode
963b2040
CY
370 ;; Turned on.
371 (progn
372 (define-key-after menu-bar-edit-menu [hi-lock]
373 (cons "Regexp Highlighting" hi-lock-menu))
374 (hi-lock-find-patterns)
e4d59066 375 (add-hook 'font-lock-mode-hook 'hi-lock-font-lock-hook nil t))
abb2db1c 376 ;; Turned off.
e4d59066
CY
377 (when (or hi-lock-interactive-patterns
378 hi-lock-file-patterns)
71060bdd 379 (when hi-lock-interactive-patterns
e4d59066
CY
380 (font-lock-remove-keywords nil hi-lock-interactive-patterns)
381 (setq hi-lock-interactive-patterns nil))
382 (when hi-lock-file-patterns
383 (font-lock-remove-keywords nil hi-lock-file-patterns)
384 (setq hi-lock-file-patterns nil))
81dc5714
JL
385 (remove-overlays nil nil 'hi-lock-overlay t)
386 (when font-lock-fontified (font-lock-fontify-buffer)))
963b2040
CY
387 (define-key-after menu-bar-edit-menu [hi-lock] nil)
388 (remove-hook 'font-lock-mode-hook 'hi-lock-font-lock-hook t)))
abb2db1c 389
963b2040 390;;;###autoload
98007d83 391(define-globalized-minor-mode global-hi-lock-mode
71060bdd 392 hi-lock-mode turn-on-hi-lock-if-enabled
9cb4bb45 393 :group 'hi-lock)
71060bdd 394
963b2040 395(defun turn-on-hi-lock-if-enabled ()
71060bdd 396 (setq hi-lock-archaic-interface-message-used t)
963b2040 397 (unless (memq major-mode hi-lock-exclude-modes)
71060bdd 398 (hi-lock-mode 1)))
abb2db1c
GM
399
400;;;###autoload
401(defalias 'highlight-lines-matching-regexp 'hi-lock-line-face-buffer)
402;;;###autoload
403(defun hi-lock-line-face-buffer (regexp &optional face)
108ee42b 404 "Set face of all lines containing a match of REGEXP to FACE.
a9f6f311
CY
405Interactively, prompt for REGEXP then FACE, using a buffer-local
406history list for REGEXP and a global history list for FACE.
abb2db1c 407
a9f6f311
CY
408If Font Lock mode is enabled in the buffer, it is used to
409highlight REGEXP. If Font Lock mode is disabled, overlays are
410used for highlighting; in this case, the highlighting will not be
411updated as you type."
abb2db1c
GM
412 (interactive
413 (list
8677dea3
JL
414 (hi-lock-regexp-okay
415 (read-regexp "Regexp to highlight line" (car regexp-history)))
abb2db1c 416 (hi-lock-read-face-name)))
597767da 417 (or (facep face) (setq face 'hi-yellow))
71060bdd 418 (unless hi-lock-mode (hi-lock-mode 1))
abb2db1c 419 (hi-lock-set-pattern
b18f5523
SM
420 ;; The \\(?:...\\) grouping construct ensures that a leading ^, +, * or ?
421 ;; or a trailing $ in REGEXP will be interpreted correctly.
963b2040 422 (concat "^.*\\(?:" regexp "\\).*$") face))
abb2db1c 423
108ee42b 424
abb2db1c
GM
425;;;###autoload
426(defalias 'highlight-regexp 'hi-lock-face-buffer)
427;;;###autoload
428(defun hi-lock-face-buffer (regexp &optional face)
108ee42b 429 "Set face of each match of REGEXP to FACE.
a9f6f311
CY
430Interactively, prompt for REGEXP then FACE, using a buffer-local
431history list for REGEXP and a global history list for FACE.
abb2db1c 432
a9f6f311
CY
433If Font Lock mode is enabled in the buffer, it is used to
434highlight REGEXP. If Font Lock mode is disabled, overlays are
435used for highlighting; in this case, the highlighting will not be
436updated as you type."
abb2db1c
GM
437 (interactive
438 (list
8677dea3
JL
439 (hi-lock-regexp-okay
440 (read-regexp "Regexp to highlight" (car regexp-history)))
abb2db1c 441 (hi-lock-read-face-name)))
597767da 442 (or (facep face) (setq face 'hi-yellow))
71060bdd 443 (unless hi-lock-mode (hi-lock-mode 1))
963b2040 444 (hi-lock-set-pattern regexp face))
abb2db1c 445
108ee42b
GM
446;;;###autoload
447(defalias 'highlight-phrase 'hi-lock-face-phrase-buffer)
448;;;###autoload
449(defun hi-lock-face-phrase-buffer (regexp &optional face)
450 "Set face of each match of phrase REGEXP to FACE.
82ed3ab4
GM
451If called interactively, replaces whitespace in REGEXP with
452arbitrary whitespace and makes initial lower-case letters case-insensitive.
a9f6f311
CY
453
454If Font Lock mode is enabled in the buffer, it is used to
455highlight REGEXP. If Font Lock mode is disabled, overlays are
456used for highlighting; in this case, the highlighting will not be
457updated as you type."
108ee42b
GM
458 (interactive
459 (list
460 (hi-lock-regexp-okay
461 (hi-lock-process-phrase
8677dea3 462 (read-regexp "Phrase to highlight" (car regexp-history))))
108ee42b 463 (hi-lock-read-face-name)))
597767da 464 (or (facep face) (setq face 'hi-yellow))
71060bdd 465 (unless hi-lock-mode (hi-lock-mode 1))
963b2040 466 (hi-lock-set-pattern regexp face))
108ee42b 467
e8a11b22 468(declare-function x-popup-menu "menu.c" (position menu))
f2d9c15f 469
b85aec93
J
470(defun hi-lock--regexps-at-point ()
471 (let ((regexps '()))
472 ;; When using overlays, there is no ambiguity on the best
473 ;; choice of regexp.
853c1ffc
SM
474 (let ((regexp (get-char-property (point) 'hi-lock-overlay-regexp)))
475 (when regexp (push regexp regexps)))
b85aec93
J
476 ;; With font-locking on, check if the cursor is on an highlighted text.
477 ;; Checking for hi-lock face is a good heuristic.
478 (and (string-match "\\`hi-lock-" (face-name (face-at-point)))
479 (let* ((hi-text
480 (buffer-substring-no-properties
481 (previous-single-property-change (point) 'face)
482 (next-single-property-change (point) 'face))))
483 ;; Compute hi-lock patterns that match the
484 ;; highlighted text at point. Use this later in
485 ;; during completing-read.
486 (dolist (hi-lock-pattern hi-lock-interactive-patterns)
487 (let ((regexp (car hi-lock-pattern)))
488 (if (string-match regexp hi-text)
489 (push regexp regexps))))))))
490
853c1ffc
SM
491(defvar-local hi-lock--last-face nil)
492
abb2db1c
GM
493;;;###autoload
494(defalias 'unhighlight-regexp 'hi-lock-unface-buffer)
495;;;###autoload
496(defun hi-lock-unface-buffer (regexp)
108ee42b 497 "Remove highlighting of each match to REGEXP set by hi-lock.
a9f6f311 498Interactively, prompt for REGEXP, accepting only regexps
b85aec93
J
499previously inserted by hi-lock interactive functions.
500If REGEXP is t (or if \\[universal-argument] was specified interactively),
501then remove all hi-lock highlighting."
abb2db1c 502 (interactive
b85aec93
J
503 (cond
504 (current-prefix-arg (list t))
505 ((and (display-popup-menus-p)
506 (listp last-nonmenu-event)
507 use-dialog-box)
508 (catch 'snafu
509 (or
510 (x-popup-menu
511 t
512 (cons
513 `keymap
514 (cons "Select Pattern to Unhighlight"
515 (mapcar (lambda (pattern)
516 (list (car pattern)
517 (format
518 "%s (%s)" (car pattern)
853c1ffc 519 (cadr (cadr (cadr pattern))))
b85aec93
J
520 (cons nil nil)
521 (car pattern)))
522 hi-lock-interactive-patterns))))
523 ;; If the user clicks outside the menu, meaning that they
524 ;; change their mind, x-popup-menu returns nil, and
525 ;; interactive signals a wrong number of arguments error.
526 ;; To prevent that, we return an empty string, which will
527 ;; effectively disable the rest of the function.
528 (throw 'snafu '("")))))
529 (t
530 ;; Un-highlighting triggered via keyboard action.
531 (unless hi-lock-interactive-patterns
532 (error "No highlighting to remove"))
533 ;; Infer the regexp to un-highlight based on cursor position.
534 (let* ((defaults (hi-lock--regexps-at-point)))
abb2db1c 535 (list
b85aec93
J
536 (completing-read (if (null defaults)
537 "Regexp to unhighlight: "
538 (format "Regexp to unhighlight (default %s): "
539 (car defaults)))
540 hi-lock-interactive-patterns
541 nil t nil nil defaults))))))
542 (dolist (keyword (if (eq regexp t) hi-lock-interactive-patterns
543 (list (assoc regexp hi-lock-interactive-patterns))))
abb2db1c 544 (when keyword
853c1ffc
SM
545 (let ((face (cadr (cadr (cadr keyword)))))
546 ;; Make `face' the next one to use by default.
547 (setq hi-lock--last-face
548 (cadr (member (symbol-name face)
549 (reverse hi-lock-face-defaults)))))
abb2db1c
GM
550 (font-lock-remove-keywords nil (list keyword))
551 (setq hi-lock-interactive-patterns
552 (delq keyword hi-lock-interactive-patterns))
81dc5714 553 (remove-overlays
853c1ffc 554 nil nil 'hi-lock-overlay-regexp (hi-lock--hashcons regexp))
81dc5714 555 (when font-lock-fontified (font-lock-fontify-buffer)))))
abb2db1c
GM
556
557;;;###autoload
558(defun hi-lock-write-interactive-patterns ()
559 "Write interactively added patterns, if any, into buffer at point.
560
561Interactively added patterns are those normally specified using
562`highlight-regexp' and `highlight-lines-matching-regexp'; they can
563be found in variable `hi-lock-interactive-patterns'."
564 (interactive)
597767da
CY
565 (if (null hi-lock-interactive-patterns)
566 (error "There are no interactive patterns"))
567 (let ((beg (point)))
ee44464c 568 (mapc
abb2db1c 569 (lambda (pattern)
90756087
JL
570 (insert (format "%s: (%s)\n"
571 hi-lock-file-patterns-prefix
572 (prin1-to-string pattern))))
597767da
CY
573 hi-lock-interactive-patterns)
574 (comment-region beg (point)))
575 (when (> (point) hi-lock-file-patterns-range)
576 (warn "Inserted keywords not close enough to top of file")))
abb2db1c
GM
577
578;; Implementation Functions
579
108ee42b
GM
580(defun hi-lock-process-phrase (phrase)
581 "Convert regexp PHRASE to a regexp that matches phrases.
582
583Blanks in PHRASE replaced by regexp that matches arbitrary whitespace
584and initial lower-case letters made case insensitive."
585 (let ((mod-phrase nil))
82ed3ab4 586 ;; FIXME fragile; better to just bind case-fold-search? (Bug#7161)
108ee42b
GM
587 (setq mod-phrase
588 (replace-regexp-in-string
1595ecfa
GM
589 "\\(^\\|\\s-\\)\\([a-z]\\)"
590 (lambda (m) (format "%s[%s%s]"
591 (match-string 1 m)
592 (upcase (match-string 2 m))
593 (match-string 2 m))) phrase))
82ed3ab4 594 ;; FIXME fragile; better to use search-spaces-regexp?
108ee42b
GM
595 (setq mod-phrase
596 (replace-regexp-in-string
597 "\\s-+" "[ \t\n]+" mod-phrase nil t))))
598
abb2db1c
GM
599(defun hi-lock-regexp-okay (regexp)
600 "Return REGEXP if it appears suitable for a font-lock pattern.
601
602Otherwise signal an error. A pattern that matches the null string is
603not suitable."
604 (if (string-match regexp "")
605 (error "Regexp cannot match an empty string")
606 regexp))
607
608(defun hi-lock-read-face-name ()
853c1ffc 609 "Return face for interactive highlighting.
b85aec93
J
610When `hi-lock-auto-select-face' is non-nil, just return the next face.
611Otherwise, read face name from minibuffer with completion and history."
853c1ffc
SM
612 (let ((default (or (cadr (member hi-lock--last-face hi-lock-face-defaults))
613 (car hi-lock-face-defaults))))
614 (setq hi-lock--last-face
615 (if (and hi-lock-auto-select-face (not current-prefix-arg))
616 default
617 (completing-read
618 (format "Highlight using face (default %s): " default)
619 obarray 'facep t nil 'face-name-history
620 (append (member default hi-lock-face-defaults)
621 hi-lock-face-defaults))))
622 (unless (member hi-lock--last-face hi-lock-face-defaults)
623 (setq hi-lock-face-defaults
624 (append hi-lock-face-defaults (list hi-lock--last-face))))
625 (intern hi-lock--last-face)))
abb2db1c 626
963b2040
CY
627(defun hi-lock-set-pattern (regexp face)
628 "Highlight REGEXP with face FACE."
853c1ffc
SM
629 ;; Hashcons the regexp, so it can be passed to remove-overlays later.
630 (setq regexp (hi-lock--hashcons regexp))
c58059f2 631 (let ((pattern (list regexp (list 0 (list 'quote face) t))))
abb2db1c 632 (unless (member pattern hi-lock-interactive-patterns)
963b2040 633 (push pattern hi-lock-interactive-patterns)
a9f6f311 634 (if font-lock-mode
c58059f2
DK
635 (progn
636 (font-lock-add-keywords nil (list pattern) t)
637 (font-lock-fontify-buffer))
853c1ffc 638 (let* ((range-min (- (point) (/ hi-lock-highlight-range 2)))
81dc5714
JL
639 (range-max (+ (point) (/ hi-lock-highlight-range 2)))
640 (search-start
641 (max (point-min)
642 (- range-min (max 0 (- range-max (point-max))))))
643 (search-end
644 (min (point-max)
645 (+ range-max (max 0 (- (point-min) range-min))))))
646 (save-excursion
647 (goto-char search-start)
648 (while (re-search-forward regexp search-end t)
649 (let ((overlay (make-overlay (match-beginning 0) (match-end 0))))
650 (overlay-put overlay 'hi-lock-overlay t)
853c1ffc 651 (overlay-put overlay 'hi-lock-overlay-regexp regexp)
81dc5714
JL
652 (overlay-put overlay 'face face))
653 (goto-char (match-end 0)))))))))
abb2db1c
GM
654
655(defun hi-lock-set-file-patterns (patterns)
656 "Replace file patterns list with PATTERNS and refontify."
108ee42b
GM
657 (when (or hi-lock-file-patterns patterns)
658 (font-lock-remove-keywords nil hi-lock-file-patterns)
659 (setq hi-lock-file-patterns patterns)
90756087 660 (font-lock-add-keywords nil hi-lock-file-patterns t)
e4d59066 661 (font-lock-fontify-buffer)))
abb2db1c
GM
662
663(defun hi-lock-find-patterns ()
664 "Find patterns in current buffer for hi-lock."
665 (interactive)
666 (unless (memq major-mode hi-lock-exclude-modes)
667 (let ((all-patterns nil)
668 (target-regexp (concat "\\<" hi-lock-file-patterns-prefix ":")))
669 (save-excursion
62cec9fe
SM
670 (save-restriction
671 (widen)
672 (goto-char (point-min))
673 (re-search-forward target-regexp
674 (+ (point) hi-lock-file-patterns-range) t)
675 (beginning-of-line)
676 (while (and (re-search-forward target-regexp (+ (point) 100) t)
677 (not (looking-at "\\s-*end")))
ed6773fa
JB
678 (condition-case nil
679 (setq all-patterns (append (read (current-buffer)) all-patterns))
680 (error (message "Invalid pattern list expression at %d"
963b2040 681 (line-number-at-pos)))))))
c898bef7
CY
682 (when (and all-patterns
683 hi-lock-mode
684 (cond
685 ((eq this-command 'hi-lock-find-patterns) t)
686 ((functionp hi-lock-file-patterns-policy)
687 (funcall hi-lock-file-patterns-policy all-patterns))
688 ((eq hi-lock-file-patterns-policy 'ask)
689 (y-or-n-p "Add patterns from this buffer to hi-lock? "))
690 (t nil)))
691 (hi-lock-set-file-patterns all-patterns)
32226619 692 (if (called-interactively-p 'interactive)
c898bef7 693 (message "Hi-lock added %d patterns." (length all-patterns)))))))
abb2db1c
GM
694
695(defun hi-lock-font-lock-hook ()
8b730780 696 "Add hi-lock patterns to font-lock's."
c58059f2
DK
697 (when font-lock-fontified
698 (font-lock-add-keywords nil hi-lock-file-patterns t)
699 (font-lock-add-keywords nil hi-lock-interactive-patterns t)))
abb2db1c 700
853c1ffc
SM
701(defvar hi-lock--hashcons-hash
702 (make-hash-table :test 'equal :weakness t)
703 "Hash table used to hash cons regexps.")
81dc5714 704
853c1ffc
SM
705(defun hi-lock--hashcons (string)
706 "Return unique object equal to STRING."
707 (or (gethash string hi-lock--hashcons-hash)
708 (puthash string string hi-lock--hashcons-hash)))
81dc5714 709
869d3e17
JB
710(defun hi-lock-unload-function ()
711 "Unload the Hi-Lock library."
712 (global-hi-lock-mode -1)
713 ;; continue standard unloading
714 nil)
715
abb2db1c
GM
716(provide 'hi-lock)
717
718;;; hi-lock.el ends here