* lisp/net/rcirc.el: Add PRIVMSG and CTCP functions.
[bpt/emacs.git] / lisp / hi-lock.el
CommitLineData
e8af40ee 1;;; hi-lock.el --- minor mode for interactive automatic highlighting
abb2db1c 2
73b0cd50 3;; Copyright (C) 2000-2011 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
GM
54;;
55;; Put the following code in your .emacs 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
CY
61;; To enable the use of patterns found in files (presumably placed
62;; there by hi-lock) include the following in your .emacs file:
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
GM
137
138(defgroup hi-lock-faces nil
139 "Faces for hi-lock."
f43eaaef
JL
140 :group 'hi-lock
141 :group 'faces)
abb2db1c
GM
142
143(defface hi-yellow
e0d815a2 144 '((((min-colors 88) (background dark))
ea81d57e
DN
145 (:background "yellow1" :foreground "black"))
146 (((background dark)) (:background "yellow" :foreground "black"))
147 (((min-colors 88)) (:background "yellow1"))
a0b8c939 148 (t (:background "yellow")))
abb2db1c
GM
149 "Default face for hi-lock mode."
150 :group 'hi-lock-faces)
151
152(defface hi-pink
16cdf141 153 '((((background dark)) (:background "pink" :foreground "black"))
a0b8c939 154 (t (:background "pink")))
abb2db1c
GM
155 "Face for hi-lock mode."
156 :group 'hi-lock-faces)
157
158(defface hi-green
e0d815a2 159 '((((min-colors 88) (background dark))
ea81d57e
DN
160 (:background "green1" :foreground "black"))
161 (((background dark)) (:background "green" :foreground "black"))
e0d815a2 162 (((min-colors 88)) (:background "green1"))
a0b8c939 163 (t (:background "green")))
abb2db1c
GM
164 "Face for hi-lock mode."
165 :group 'hi-lock-faces)
166
167(defface hi-blue
16cdf141 168 '((((background dark)) (:background "light blue" :foreground "black"))
a0b8c939 169 (t (:background "light blue")))
abb2db1c
GM
170 "Face for hi-lock mode."
171 :group 'hi-lock-faces)
172
173(defface hi-black-b
174 '((t (:weight bold)))
175 "Face for hi-lock mode."
176 :group 'hi-lock-faces)
177
178(defface hi-blue-b
ea81d57e
DN
179 '((((min-colors 88)) (:weight bold :foreground "blue1"))
180 (t (:weight bold :foreground "blue")))
abb2db1c
GM
181 "Face for hi-lock mode."
182 :group 'hi-lock-faces)
183
184(defface hi-green-b
ea81d57e
DN
185 '((((min-colors 88)) (:weight bold :foreground "green1"))
186 (t (:weight bold :foreground "green")))
abb2db1c
GM
187 "Face for hi-lock mode."
188 :group 'hi-lock-faces)
189
190(defface hi-red-b
ea81d57e
DN
191 '((((min-colors 88)) (:weight bold :foreground "red1"))
192 (t (:weight bold :foreground "red")))
abb2db1c
GM
193 "Face for hi-lock mode."
194 :group 'hi-lock-faces)
195
196(defface hi-black-hb
c3b27206 197 '((t (:weight bold :height 1.67 :inherit variable-pitch)))
abb2db1c
GM
198 "Face for hi-lock mode."
199 :group 'hi-lock-faces)
200
201(defvar hi-lock-file-patterns nil
202 "Patterns found in file for hi-lock. Should not be changed.")
203
204(defvar hi-lock-interactive-patterns nil
205 "Patterns provided to hi-lock by user. Should not be changed.")
206
ef705f25
JL
207(defvar hi-lock-face-defaults
208 '("hi-yellow" "hi-pink" "hi-green" "hi-blue" "hi-black-b"
209 "hi-blue-b" "hi-red-b" "hi-green-b" "hi-black-hb")
210 "Default faces for hi-lock interactive functions.")
abb2db1c 211
ef705f25 212;(dolist (f hi-lock-face-defaults) (unless (facep f) (error "%s not a face" f)))
abb2db1c 213
ef705f25
JL
214(define-obsolete-variable-alias 'hi-lock-face-history
215 'hi-lock-face-defaults
216 "23.1")
217
218(define-obsolete-variable-alias 'hi-lock-regexp-history
219 'regexp-history
220 "23.1")
abb2db1c
GM
221
222(defvar hi-lock-file-patterns-prefix "Hi-lock"
c898bef7 223 "Search target for finding hi-lock patterns at top of file.")
abb2db1c 224
71060bdd 225(defvar hi-lock-archaic-interface-message-used nil
90756087 226 "True if user alerted that `global-hi-lock-mode' is now the global switch.
8b730780 227Earlier versions of hi-lock used `hi-lock-mode' as the global switch;
90756087 228the message is issued if it appears that `hi-lock-mode' is used assuming
71060bdd
EZ
229that older functionality. This variable avoids multiple reminders.")
230
231(defvar hi-lock-archaic-interface-deduce nil
90756087
JL
232 "If non-nil, sometimes assume that `hi-lock-mode' means `global-hi-lock-mode'.
233Assumption is made if `hi-lock-mode' used in the *scratch* buffer while
71060bdd
EZ
234a library is being loaded.")
235
abb2db1c
GM
236(make-variable-buffer-local 'hi-lock-interactive-patterns)
237(put 'hi-lock-interactive-patterns 'permanent-local t)
abb2db1c
GM
238(make-variable-buffer-local 'hi-lock-file-patterns)
239(put 'hi-lock-file-patterns 'permanent-local t)
240
241(defvar hi-lock-menu (make-sparse-keymap "Hi Lock")
242 "Menu for hi-lock mode.")
243
244(define-key-after hi-lock-menu [highlight-regexp]
245 '(menu-item "Highlight Regexp..." highlight-regexp
246 :help "Highlight text matching PATTERN (a regexp)."))
247
108ee42b
GM
248(define-key-after hi-lock-menu [highlight-phrase]
249 '(menu-item "Highlight Phrase..." highlight-phrase
250 :help "Highlight text matching PATTERN (a regexp processed to match phrases)."))
251
abb2db1c
GM
252(define-key-after hi-lock-menu [highlight-lines-matching-regexp]
253 '(menu-item "Highlight Lines..." highlight-lines-matching-regexp
d88444f2 254 :help "Highlight lines containing match of PATTERN (a regexp)."))
abb2db1c
GM
255
256(define-key-after hi-lock-menu [unhighlight-regexp]
257 '(menu-item "Remove Highlighting..." unhighlight-regexp
258 :help "Remove previously entered highlighting pattern."
259 :enable hi-lock-interactive-patterns))
260
261(define-key-after hi-lock-menu [hi-lock-write-interactive-patterns]
262 '(menu-item "Patterns to Buffer" hi-lock-write-interactive-patterns
263 :help "Insert interactively added REGEXPs into buffer at point."
264 :enable hi-lock-interactive-patterns))
265
266(define-key-after hi-lock-menu [hi-lock-find-patterns]
267 '(menu-item "Patterns from Buffer" hi-lock-find-patterns
268 :help "Use patterns (if any) near top of buffer."))
269
270(defvar hi-lock-map (make-sparse-keymap "Hi Lock")
271 "Key map for hi-lock.")
272
273(define-key hi-lock-map "\C-xwi" 'hi-lock-find-patterns)
274(define-key hi-lock-map "\C-xwl" 'highlight-lines-matching-regexp)
108ee42b 275(define-key hi-lock-map "\C-xwp" 'highlight-phrase)
abb2db1c
GM
276(define-key hi-lock-map "\C-xwh" 'highlight-regexp)
277(define-key hi-lock-map "\C-xwr" 'unhighlight-regexp)
278(define-key hi-lock-map "\C-xwb" 'hi-lock-write-interactive-patterns)
279
abb2db1c
GM
280;; Visible Functions
281
abb2db1c 282;;;###autoload
71060bdd 283(define-minor-mode hi-lock-mode
abb2db1c
GM
284 "Toggle minor mode for interactively adding font-lock highlighting patterns.
285
90756087
JL
286If ARG positive, turn hi-lock on. Issuing a hi-lock command will also
287turn hi-lock on. To turn hi-lock on in all buffers use
288`global-hi-lock-mode' or in your .emacs file (global-hi-lock-mode 1).
71060bdd
EZ
289When hi-lock is turned on, a \"Regexp Highlighting\" submenu is added
290to the \"Edit\" menu. The commands in the submenu, which can be
291called interactively, are:
abb2db1c
GM
292
293\\[highlight-regexp] REGEXP FACE
294 Highlight matches of pattern REGEXP in current buffer with FACE.
295
108ee42b
GM
296\\[highlight-phrase] PHRASE FACE
297 Highlight matches of phrase PHRASE in current buffer with FACE.
298 (PHRASE can be any REGEXP, but spaces will be replaced by matches
299 to whitespace and initial lower-case letters will become case insensitive.)
71296446 300
abb2db1c
GM
301\\[highlight-lines-matching-regexp] REGEXP FACE
302 Highlight lines containing matches of REGEXP in current buffer with FACE.
303
304\\[unhighlight-regexp] REGEXP
305 Remove highlighting on matches of REGEXP in current buffer.
306
307\\[hi-lock-write-interactive-patterns]
c898bef7 308 Write active REGEXPs into buffer as comments (if possible). They may
abb2db1c
GM
309 be read the next time file is loaded or when the \\[hi-lock-find-patterns] command
310 is issued. The inserted regexps are in the form of font lock keywords.
ee44464c 311 (See `font-lock-keywords'.) They may be edited and re-loaded with \\[hi-lock-find-patterns],
869d3e17
JB
312 any valid `font-lock-keywords' form is acceptable. When a file is
313 loaded the patterns are read if `hi-lock-file-patterns-policy' is
c898bef7
CY
314 'ask and the user responds y to the prompt, or if
315 `hi-lock-file-patterns-policy' is bound to a function and that
316 function returns t.
abb2db1c
GM
317
318\\[hi-lock-find-patterns]
319 Re-read patterns stored in buffer (in the format produced by \\[hi-lock-write-interactive-patterns]).
320
c898bef7
CY
321When hi-lock is started and if the mode is not excluded or patterns
322rejected, the beginning of the buffer is searched for lines of the
323form:
abb2db1c 324 Hi-lock: FOO
8b730780
JB
325where FOO is a list of patterns. These are added to the font lock
326keywords already present. The patterns must start before position
327\(number of characters into buffer) `hi-lock-file-patterns-range'.
328Patterns will be read until
abb2db1c 329 Hi-lock: end
8b730780 330is found. A mode is excluded if it's in the list `hi-lock-exclude-modes'."
963b2040 331 :group 'hi-lock
90756087
JL
332 :lighter (:eval (if (or hi-lock-interactive-patterns
333 hi-lock-file-patterns)
334 " Hi" ""))
963b2040
CY
335 :global nil
336 :keymap hi-lock-map
71060bdd
EZ
337 (when (and (equal (buffer-name) "*scratch*")
338 load-in-progress
32226619 339 (not (called-interactively-p 'interactive))
71060bdd
EZ
340 (not hi-lock-archaic-interface-message-used))
341 (setq hi-lock-archaic-interface-message-used t)
342 (if hi-lock-archaic-interface-deduce
343 (global-hi-lock-mode hi-lock-mode)
344 (warn
345 "Possible archaic use of (hi-lock-mode).
346Use (global-hi-lock-mode 1) in .emacs to enable hi-lock for all buffers,
90756087 347use (hi-lock-mode 1) for individual buffers. For compatibility with Emacs
71060bdd
EZ
348versions before 22 use the following in your .emacs file:
349
350 (if (functionp 'global-hi-lock-mode)
351 (global-hi-lock-mode 1)
352 (hi-lock-mode 1))
353")))
354 (if hi-lock-mode
963b2040
CY
355 ;; Turned on.
356 (progn
e4d59066 357 (unless font-lock-mode (font-lock-mode 1))
963b2040
CY
358 (define-key-after menu-bar-edit-menu [hi-lock]
359 (cons "Regexp Highlighting" hi-lock-menu))
360 (hi-lock-find-patterns)
e4d59066 361 (add-hook 'font-lock-mode-hook 'hi-lock-font-lock-hook nil t))
abb2db1c 362 ;; Turned off.
e4d59066
CY
363 (when (or hi-lock-interactive-patterns
364 hi-lock-file-patterns)
71060bdd 365 (when hi-lock-interactive-patterns
e4d59066
CY
366 (font-lock-remove-keywords nil hi-lock-interactive-patterns)
367 (setq hi-lock-interactive-patterns nil))
368 (when hi-lock-file-patterns
369 (font-lock-remove-keywords nil hi-lock-file-patterns)
370 (setq hi-lock-file-patterns nil))
81dc5714
JL
371 (remove-overlays nil nil 'hi-lock-overlay t)
372 (when font-lock-fontified (font-lock-fontify-buffer)))
963b2040
CY
373 (define-key-after menu-bar-edit-menu [hi-lock] nil)
374 (remove-hook 'font-lock-mode-hook 'hi-lock-font-lock-hook t)))
abb2db1c 375
963b2040 376;;;###autoload
98007d83 377(define-globalized-minor-mode global-hi-lock-mode
71060bdd 378 hi-lock-mode turn-on-hi-lock-if-enabled
9cb4bb45 379 :group 'hi-lock)
71060bdd 380
963b2040 381(defun turn-on-hi-lock-if-enabled ()
71060bdd 382 (setq hi-lock-archaic-interface-message-used t)
963b2040 383 (unless (memq major-mode hi-lock-exclude-modes)
71060bdd 384 (hi-lock-mode 1)))
abb2db1c
GM
385
386;;;###autoload
387(defalias 'highlight-lines-matching-regexp 'hi-lock-line-face-buffer)
388;;;###autoload
389(defun hi-lock-line-face-buffer (regexp &optional face)
108ee42b 390 "Set face of all lines containing a match of REGEXP to FACE.
abb2db1c
GM
391
392Interactively, prompt for REGEXP then FACE. Buffer-local history
393list maintained for regexps, global history maintained for faces.
ef705f25
JL
394\\<minibuffer-local-map>Use \\[previous-history-element] to retrieve previous history items,
395and \\[next-history-element] to retrieve default values.
8b730780 396\(See info node `Minibuffer History'.)"
abb2db1c
GM
397 (interactive
398 (list
8677dea3
JL
399 (hi-lock-regexp-okay
400 (read-regexp "Regexp to highlight line" (car regexp-history)))
abb2db1c 401 (hi-lock-read-face-name)))
597767da 402 (or (facep face) (setq face 'hi-yellow))
71060bdd 403 (unless hi-lock-mode (hi-lock-mode 1))
abb2db1c 404 (hi-lock-set-pattern
b18f5523
SM
405 ;; The \\(?:...\\) grouping construct ensures that a leading ^, +, * or ?
406 ;; or a trailing $ in REGEXP will be interpreted correctly.
963b2040 407 (concat "^.*\\(?:" regexp "\\).*$") face))
abb2db1c 408
108ee42b 409
abb2db1c
GM
410;;;###autoload
411(defalias 'highlight-regexp 'hi-lock-face-buffer)
412;;;###autoload
413(defun hi-lock-face-buffer (regexp &optional face)
108ee42b 414 "Set face of each match of REGEXP to FACE.
abb2db1c
GM
415
416Interactively, prompt for REGEXP then FACE. Buffer-local history
417list maintained for regexps, global history maintained for faces.
ef705f25
JL
418\\<minibuffer-local-map>Use \\[previous-history-element] to retrieve previous history items,
419and \\[next-history-element] to retrieve default values.
8b730780 420\(See info node `Minibuffer History'.)"
abb2db1c
GM
421 (interactive
422 (list
8677dea3
JL
423 (hi-lock-regexp-okay
424 (read-regexp "Regexp to highlight" (car regexp-history)))
abb2db1c 425 (hi-lock-read-face-name)))
597767da 426 (or (facep face) (setq face 'hi-yellow))
71060bdd 427 (unless hi-lock-mode (hi-lock-mode 1))
963b2040 428 (hi-lock-set-pattern regexp face))
abb2db1c 429
108ee42b
GM
430;;;###autoload
431(defalias 'highlight-phrase 'hi-lock-face-phrase-buffer)
432;;;###autoload
433(defun hi-lock-face-phrase-buffer (regexp &optional face)
434 "Set face of each match of phrase REGEXP to FACE.
435
436Whitespace in REGEXP converted to arbitrary whitespace and initial
437lower-case letters made case insensitive."
438 (interactive
439 (list
440 (hi-lock-regexp-okay
441 (hi-lock-process-phrase
8677dea3 442 (read-regexp "Phrase to highlight" (car regexp-history))))
108ee42b 443 (hi-lock-read-face-name)))
597767da 444 (or (facep face) (setq face 'hi-yellow))
71060bdd 445 (unless hi-lock-mode (hi-lock-mode 1))
963b2040 446 (hi-lock-set-pattern regexp face))
108ee42b 447
e8a11b22 448(declare-function x-popup-menu "menu.c" (position menu))
f2d9c15f 449
abb2db1c
GM
450;;;###autoload
451(defalias 'unhighlight-regexp 'hi-lock-unface-buffer)
452;;;###autoload
453(defun hi-lock-unface-buffer (regexp)
108ee42b 454 "Remove highlighting of each match to REGEXP set by hi-lock.
abb2db1c
GM
455
456Interactively, prompt for REGEXP. Buffer-local history of inserted
457regexp's maintained. Will accept only regexps inserted by hi-lock
108ee42b 458interactive functions. \(See `hi-lock-interactive-patterns'.\)
abb2db1c 459\\<minibuffer-local-must-match-map>Use \\[minibuffer-complete] to complete a partially typed regexp.
cf667bc5 460\(See info node `Minibuffer History'.\)"
abb2db1c 461 (interactive
a2ab90da 462 (if (and (display-popup-menus-p) (not last-nonmenu-event))
cf667bc5
EZ
463 (catch 'snafu
464 (or
465 (x-popup-menu
466 t
467 (cons
468 `keymap
469 (cons "Select Pattern to Unhighlight"
470 (mapcar (lambda (pattern)
471 (list (car pattern)
472 (format
473 "%s (%s)" (car pattern)
474 (symbol-name
475 (car
476 (cdr (car (cdr (car (cdr pattern))))))))
477 (cons nil nil)
478 (car pattern)))
479 hi-lock-interactive-patterns))))
480 ;; If the user clicks outside the menu, meaning that they
481 ;; change their mind, x-popup-menu returns nil, and
482 ;; interactive signals a wrong number of arguments error.
483 ;; To prevent that, we return an empty string, which will
484 ;; effectively disable the rest of the function.
485 (throw 'snafu '(""))))
abb2db1c
GM
486 (let ((history-list (mapcar (lambda (p) (car p))
487 hi-lock-interactive-patterns)))
488 (unless hi-lock-interactive-patterns
489 (error "No highlighting to remove"))
490 (list
491 (completing-read "Regexp to unhighlight: "
932c309e 492 hi-lock-interactive-patterns nil t
abb2db1c
GM
493 (car (car hi-lock-interactive-patterns))
494 (cons 'history-list 1))))))
495 (let ((keyword (assoc regexp hi-lock-interactive-patterns)))
496 (when keyword
497 (font-lock-remove-keywords nil (list keyword))
498 (setq hi-lock-interactive-patterns
499 (delq keyword hi-lock-interactive-patterns))
81dc5714
JL
500 (remove-overlays
501 nil nil 'hi-lock-overlay-regexp (hi-lock-string-serialize regexp))
502 (when font-lock-fontified (font-lock-fontify-buffer)))))
abb2db1c
GM
503
504;;;###autoload
505(defun hi-lock-write-interactive-patterns ()
506 "Write interactively added patterns, if any, into buffer at point.
507
508Interactively added patterns are those normally specified using
509`highlight-regexp' and `highlight-lines-matching-regexp'; they can
510be found in variable `hi-lock-interactive-patterns'."
511 (interactive)
597767da
CY
512 (if (null hi-lock-interactive-patterns)
513 (error "There are no interactive patterns"))
514 (let ((beg (point)))
ee44464c 515 (mapc
abb2db1c 516 (lambda (pattern)
90756087
JL
517 (insert (format "%s: (%s)\n"
518 hi-lock-file-patterns-prefix
519 (prin1-to-string pattern))))
597767da
CY
520 hi-lock-interactive-patterns)
521 (comment-region beg (point)))
522 (when (> (point) hi-lock-file-patterns-range)
523 (warn "Inserted keywords not close enough to top of file")))
abb2db1c
GM
524
525;; Implementation Functions
526
108ee42b
GM
527(defun hi-lock-process-phrase (phrase)
528 "Convert regexp PHRASE to a regexp that matches phrases.
529
530Blanks in PHRASE replaced by regexp that matches arbitrary whitespace
531and initial lower-case letters made case insensitive."
532 (let ((mod-phrase nil))
533 (setq mod-phrase
534 (replace-regexp-in-string
535 "\\<[a-z]" (lambda (m) (format "[%s%s]" (upcase m) m)) phrase))
536 (setq mod-phrase
537 (replace-regexp-in-string
538 "\\s-+" "[ \t\n]+" mod-phrase nil t))))
539
abb2db1c
GM
540(defun hi-lock-regexp-okay (regexp)
541 "Return REGEXP if it appears suitable for a font-lock pattern.
542
543Otherwise signal an error. A pattern that matches the null string is
544not suitable."
545 (if (string-match regexp "")
546 (error "Regexp cannot match an empty string")
547 regexp))
548
549(defun hi-lock-read-face-name ()
550 "Read face name from minibuffer with completion and history."
551 (intern (completing-read
552 "Highlight using face: "
553 obarray 'facep t
ef705f25 554 (cons (car hi-lock-face-defaults)
abb2db1c
GM
555 (let ((prefix
556 (try-completion
ef705f25
JL
557 (substring (car hi-lock-face-defaults) 0 1)
558 hi-lock-face-defaults)))
abb2db1c 559 (if (and (stringp prefix)
ef705f25 560 (not (equal prefix (car hi-lock-face-defaults))))
abb2db1c 561 (length prefix) 0)))
ef705f25
JL
562 'face-name-history
563 (cdr hi-lock-face-defaults))))
abb2db1c 564
963b2040
CY
565(defun hi-lock-set-pattern (regexp face)
566 "Highlight REGEXP with face FACE."
c58059f2 567 (let ((pattern (list regexp (list 0 (list 'quote face) t))))
abb2db1c 568 (unless (member pattern hi-lock-interactive-patterns)
963b2040 569 (push pattern hi-lock-interactive-patterns)
81dc5714 570 (if font-lock-fontified
c58059f2
DK
571 (progn
572 (font-lock-add-keywords nil (list pattern) t)
573 (font-lock-fontify-buffer))
81dc5714
JL
574 (let* ((serial (hi-lock-string-serialize regexp))
575 (range-min (- (point) (/ hi-lock-highlight-range 2)))
576 (range-max (+ (point) (/ hi-lock-highlight-range 2)))
577 (search-start
578 (max (point-min)
579 (- range-min (max 0 (- range-max (point-max))))))
580 (search-end
581 (min (point-max)
582 (+ range-max (max 0 (- (point-min) range-min))))))
583 (save-excursion
584 (goto-char search-start)
585 (while (re-search-forward regexp search-end t)
586 (let ((overlay (make-overlay (match-beginning 0) (match-end 0))))
587 (overlay-put overlay 'hi-lock-overlay t)
588 (overlay-put overlay 'hi-lock-overlay-regexp serial)
589 (overlay-put overlay 'face face))
590 (goto-char (match-end 0)))))))))
abb2db1c
GM
591
592(defun hi-lock-set-file-patterns (patterns)
593 "Replace file patterns list with PATTERNS and refontify."
108ee42b
GM
594 (when (or hi-lock-file-patterns patterns)
595 (font-lock-remove-keywords nil hi-lock-file-patterns)
596 (setq hi-lock-file-patterns patterns)
90756087 597 (font-lock-add-keywords nil hi-lock-file-patterns t)
e4d59066 598 (font-lock-fontify-buffer)))
abb2db1c
GM
599
600(defun hi-lock-find-patterns ()
601 "Find patterns in current buffer for hi-lock."
602 (interactive)
603 (unless (memq major-mode hi-lock-exclude-modes)
604 (let ((all-patterns nil)
605 (target-regexp (concat "\\<" hi-lock-file-patterns-prefix ":")))
606 (save-excursion
62cec9fe
SM
607 (save-restriction
608 (widen)
609 (goto-char (point-min))
610 (re-search-forward target-regexp
611 (+ (point) hi-lock-file-patterns-range) t)
612 (beginning-of-line)
613 (while (and (re-search-forward target-regexp (+ (point) 100) t)
614 (not (looking-at "\\s-*end")))
ed6773fa
JB
615 (condition-case nil
616 (setq all-patterns (append (read (current-buffer)) all-patterns))
617 (error (message "Invalid pattern list expression at %d"
963b2040 618 (line-number-at-pos)))))))
c898bef7
CY
619 (when (and all-patterns
620 hi-lock-mode
621 (cond
622 ((eq this-command 'hi-lock-find-patterns) t)
623 ((functionp hi-lock-file-patterns-policy)
624 (funcall hi-lock-file-patterns-policy all-patterns))
625 ((eq hi-lock-file-patterns-policy 'ask)
626 (y-or-n-p "Add patterns from this buffer to hi-lock? "))
627 (t nil)))
628 (hi-lock-set-file-patterns all-patterns)
32226619 629 (if (called-interactively-p 'interactive)
c898bef7 630 (message "Hi-lock added %d patterns." (length all-patterns)))))))
abb2db1c
GM
631
632(defun hi-lock-font-lock-hook ()
8b730780 633 "Add hi-lock patterns to font-lock's."
c58059f2
DK
634 (when font-lock-fontified
635 (font-lock-add-keywords nil hi-lock-file-patterns t)
636 (font-lock-add-keywords nil hi-lock-interactive-patterns t)))
abb2db1c 637
81dc5714
JL
638(defvar hi-lock-string-serialize-hash
639 (make-hash-table :test 'equal)
640 "Hash table used to assign unique numbers to strings.")
641
642(defvar hi-lock-string-serialize-serial 1
643 "Number assigned to last new string in call to `hi-lock-string-serialize'.
644A string is considered new if it had not previously been used in a call to
645`hi-lock-string-serialize'.")
646
647(defun hi-lock-string-serialize (string)
648 "Return unique serial number for STRING."
649 (interactive)
650 (let ((val (gethash string hi-lock-string-serialize-hash)))
651 (if val val
652 (puthash string
653 (setq hi-lock-string-serialize-serial
654 (1+ hi-lock-string-serialize-serial))
655 hi-lock-string-serialize-hash)
656 hi-lock-string-serialize-serial)))
657
869d3e17
JB
658(defun hi-lock-unload-function ()
659 "Unload the Hi-Lock library."
660 (global-hi-lock-mode -1)
661 ;; continue standard unloading
662 nil)
663
abb2db1c
GM
664(provide 'hi-lock)
665
666;;; hi-lock.el ends here