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