comparison lisp/erc/erc-goodies.el @ 68451:fc745b05e928

Revision: emacs@sv.gnu.org/emacs--devo--0--patch-22 Creator: Michael Olson <mwolson@gnu.org> Install ERC.
author Miles Bader <miles@gnu.org>
date Sun, 29 Jan 2006 13:08:58 +0000
parents
children 86c478cccc57
comparison
equal deleted inserted replaced
68450:a3ba4ef5d590 68451:fc745b05e928
1 ;; erc-goodies.el --- Collection of ERC modules
2
3 ;; Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation
4
5 ;; Author: Jorgen Schaefer <forcer@forcix.cx>
6
7 ;; Most code is taken verbatim from erc.el, see there for the original
8 ;; authors.
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
26
27 ;;; Commentary:
28
29 ;; This provides some small but still useful modes for ERC.
30
31 ;;; Code:
32
33 (require 'erc)
34
35 ;; Imenu Autoload
36 (add-hook 'erc-mode-hook
37 (lambda ()
38 (setq imenu-create-index-function 'erc-create-imenu-index)))
39 (autoload 'erc-create-imenu-index "erc-imenu" "Imenu index creation function")
40
41 ;;; Automatically scroll to bottom
42 (defcustom erc-input-line-position nil
43 "Specify where to position the input line when using `erc-scroll-to-bottom'.
44
45 This should be an integer specifying the line of the buffer on which
46 the input line should stay. A value of \"-1\" would keep the input
47 line positioned on the last line in the buffer. This is passed as an
48 argument to `recenter'."
49 :group 'erc-display
50 :type '(choice integer (const nil)))
51
52 (define-erc-module scrolltobottom nil
53 "This mode causes the prompt to stay at the end of the window.
54 You have to activate or deactivate it in already created windows
55 separately."
56 ((add-hook 'erc-mode-hook 'erc-add-scroll-to-bottom))
57 ((remove-hook 'erc-mode-hook 'erc-add-scroll-to-bottom)))
58
59 (defun erc-add-scroll-to-bottom ()
60 "A hook function for `erc-mode-hook' to recenter output at bottom of window.
61
62 If you find that ERC hangs when using this function, try customizing
63 the value of `erc-input-line-position'.
64
65 This works whenever scrolling happens, so it's added to
66 `window-scroll-functions' rather than `erc-insert-post-hook'."
67 ;;(make-local-hook 'window-scroll-functions)
68 (add-hook 'window-scroll-functions 'erc-scroll-to-bottom nil t))
69
70 (defun erc-scroll-to-bottom (window display-start)
71 "Recenter WINDOW so that `point' is on the last line.
72
73 This is added to `window-scroll-functions' by `erc-add-scroll-to-bottom'.
74
75 You can control which line is recentered to by customizing the
76 variable `erc-input-line-position'.
77
78 DISPLAY-START is ignored."
79 (if (and window (window-live-p window))
80 ;; Temporarily bind resize-mini-windows to nil so that users who have it
81 ;; set to a non-nil value will not suffer from premature minibuffer
82 ;; shrinkage due to the below recenter call. I have no idea why this
83 ;; works, but it solves the problem, and has no negative side effects.
84 ;; (Fran Litterio, 2003/01/07)
85 (let ((resize-mini-windows nil))
86 (save-selected-window
87 (select-window window)
88 (save-restriction
89 (widen)
90 (when (and erc-insert-marker
91 ;; we're editing a line. Scroll.
92 (> (point) erc-insert-marker))
93 (save-excursion
94 (goto-char (point-max))
95 (recenter (or erc-input-line-position -1))
96 (sit-for 0))))))))
97
98 ;;; Make read only
99 (define-erc-module readonly nil
100 "This mode causes all inserted text to be read-only."
101 ((add-hook 'erc-insert-post-hook 'erc-make-read-only)
102 (add-hook 'erc-send-post-hook 'erc-make-read-only))
103 ((remove-hook 'erc-insert-post-hook 'erc-make-read-only)
104 (remove-hook 'erc-send-post-hook 'erc-make-read-only)))
105
106 (defun erc-make-read-only ()
107 "Make all the text in the current buffer read-only.
108 Put this function on `erc-insert-post-hook' and/or `erc-send-post-hook'."
109 (put-text-property (point-min) (point-max) 'read-only t)
110 (put-text-property (point-min) (point-max) 'front-sticky t)
111 (put-text-property (point-min) (point-max) 'rear-nonsticky t))
112
113 ;; Distingush non-commands
114 (defvar erc-noncommands-list '(erc-cmd-ME
115 erc-cmd-COUNTRY
116 erc-cmd-SV
117 erc-cmd-SM
118 erc-cmd-SMV
119 erc-cmd-LASTLOG)
120 "List of commands that are aliases for CTCP ACTION or for erc messages.
121
122 If a command's function symbol is in this list, the typed command
123 does not appear in the ERC buffer after the user presses ENTER.")
124
125 (define-erc-module noncommands nil
126 "This mode distinguishies non-commands.
127 Commands listed in `erc-insert-this' know how to display
128 themselves."
129 ((add-hook 'erc-send-pre-hook 'erc-send-distinguish-noncommands))
130 ((remove-hook 'erc-send-pre-hook 'erc-send-distinguish-noncommands)))
131
132 (defun erc-send-distinguish-noncommands (str)
133 "If STR is an ERC non-command, set `erc-insert-this' to nil."
134 (let* ((command (erc-extract-command-from-line str))
135 (cmd-fun (and command
136 (car command))))
137 (when (and cmd-fun
138 (not (string-match "\n.+$" str))
139 (memq cmd-fun erc-noncommands-list))
140 (setq erc-insert-this nil))))
141
142 ;;; IRC control character processing.
143 (defgroup erc-control-characters nil
144 "Dealing with control characters"
145 :group 'erc)
146
147 (defcustom erc-interpret-controls-p t
148 "*If non-nil, display IRC colours and other highlighting effects.
149
150 If this is set to the symbol `remove', ERC removes all IRC colors and
151 highlighting effects. When this variable is non-nil, it can cause Emacs to run
152 slowly on systems lacking sufficient CPU speed. In chatty channels, or in an
153 emergency (message flood) it can be turned off to save processing time. See
154 `erc-toggle-interpret-controls'."
155 :group 'erc-control-characters
156 :type '(choice (const :tag "Highlight control characters" t)
157 (const :tag "Remove control characters" remove)
158 (const :tag "Display raw control characters" nil)))
159
160 (defcustom erc-interpret-mirc-color nil
161 "*If non-nil, erc will interpret mIRC color codes."
162 :group 'erc-control-characters
163 :type 'boolean)
164
165 (defcustom erc-beep-p nil
166 "Beep if C-g is in the server message.
167 The value `erc-interpret-controls-p' must also be t for this to work."
168 :group 'erc-control-characters
169 :type 'boolean)
170
171 (defface erc-bold-face '((t (:bold t)))
172 "ERC bold face."
173 :group 'erc-faces)
174 (defface erc-inverse-face
175 '((t (:foreground "White" :background "Black")))
176 "ERC inverse face."
177 :group 'erc-faces)
178 (defface erc-underline-face '((t (:underline t)))
179 "ERC underline face."
180 :group 'erc-faces)
181
182 (defface fg:erc-color-face0 '((t (:foreground "White")))
183 "ERC face."
184 :group 'erc-faces)
185 (defface fg:erc-color-face1 '((t (:foreground "black")))
186 "ERC face."
187 :group 'erc-faces)
188 (defface fg:erc-color-face2 '((t (:foreground "blue4")))
189 "ERC face."
190 :group 'erc-faces)
191 (defface fg:erc-color-face3 '((t (:foreground "green4")))
192 "ERC face."
193 :group 'erc-faces)
194 (defface fg:erc-color-face4 '((t (:foreground "red")))
195 "ERC face."
196 :group 'erc-faces)
197 (defface fg:erc-color-face5 '((t (:foreground "brown")))
198 "ERC face."
199 :group 'erc-faces)
200 (defface fg:erc-color-face6 '((t (:foreground "purple")))
201 "ERC face."
202 :group 'erc-faces)
203 (defface fg:erc-color-face7 '((t (:foreground "orange")))
204 "ERC face."
205 :group 'erc-faces)
206 (defface fg:erc-color-face8 '((t (:foreground "yellow")))
207 "ERC face."
208 :group 'erc-faces)
209 (defface fg:erc-color-face9 '((t (:foreground "green")))
210 "ERC face."
211 :group 'erc-faces)
212 (defface fg:erc-color-face10 '((t (:foreground "lightblue1")))
213 "ERC face."
214 :group 'erc-faces)
215 (defface fg:erc-color-face11 '((t (:foreground "cyan")))
216 "ERC face."
217 :group 'erc-faces)
218 (defface fg:erc-color-face12 '((t (:foreground "blue")))
219 "ERC face."
220 :group 'erc-faces)
221 (defface fg:erc-color-face13 '((t (:foreground "deeppink")))
222 "ERC face."
223 :group 'erc-faces)
224 (defface fg:erc-color-face14 '((t (:foreground "gray50")))
225 "ERC face."
226 :group 'erc-faces)
227 (defface fg:erc-color-face15 '((t (:foreground "gray90")))
228 "ERC face."
229 :group 'erc-faces)
230
231 (defface bg:erc-color-face0 '((t (:background "White")))
232 "ERC face."
233 :group 'erc-faces)
234 (defface bg:erc-color-face1 '((t (:background "black")))
235 "ERC face."
236 :group 'erc-faces)
237 (defface bg:erc-color-face2 '((t (:background "blue4")))
238 "ERC face."
239 :group 'erc-faces)
240 (defface bg:erc-color-face3 '((t (:background "green4")))
241 "ERC face."
242 :group 'erc-faces)
243 (defface bg:erc-color-face4 '((t (:background "red")))
244 "ERC face."
245 :group 'erc-faces)
246 (defface bg:erc-color-face5 '((t (:background "brown")))
247 "ERC face."
248 :group 'erc-faces)
249 (defface bg:erc-color-face6 '((t (:background "purple")))
250 "ERC face."
251 :group 'erc-faces)
252 (defface bg:erc-color-face7 '((t (:background "orange")))
253 "ERC face."
254 :group 'erc-faces)
255 (defface bg:erc-color-face8 '((t (:background "yellow")))
256 "ERC face."
257 :group 'erc-faces)
258 (defface bg:erc-color-face9 '((t (:background "green")))
259 "ERC face."
260 :group 'erc-faces)
261 (defface bg:erc-color-face10 '((t (:background "lightblue1")))
262 "ERC face."
263 :group 'erc-faces)
264 (defface bg:erc-color-face11 '((t (:background "cyan")))
265 "ERC face."
266 :group 'erc-faces)
267 (defface bg:erc-color-face12 '((t (:background "blue")))
268 "ERC face."
269 :group 'erc-faces)
270 (defface bg:erc-color-face13 '((t (:background "deeppink")))
271 "ERC face."
272 :group 'erc-faces)
273 (defface bg:erc-color-face14 '((t (:background "gray50")))
274 "ERC face."
275 :group 'erc-faces)
276 (defface bg:erc-color-face15 '((t (:background "gray90")))
277 "ERC face."
278 :group 'erc-faces)
279
280 (defun erc-get-bg-color-face (n)
281 "Fetches the right face for background color N (0-15)."
282 (if (stringp n) (setq n (string-to-number n)))
283 (if (not (numberp n))
284 (progn
285 (message "erc-get-bg-color-face: n is NaN: %S" n)
286 (beep)
287 'default)
288 (when (> n 16)
289 (erc-log (format " Wrong color: %s" n))
290 (setq n (mod n 16)))
291 (cond
292 ((and (>= n 0) (< n 16))
293 (intern (concat "bg:erc-color-face" (number-to-string n))))
294 (t (erc-log (format " Wrong color: %s" n)) 'default))))
295
296 (defun erc-get-fg-color-face (n)
297 "Fetches the right face for foreground color N (0-15)."
298 (if (stringp n) (setq n (string-to-number n)))
299 (if (not (numberp n))
300 (progn
301 (message "erc-get-fg-color-face: n is NaN: %S" n)
302 (beep)
303 'default)
304 (when (> n 16)
305 (erc-log (format " Wrong color: %s" n))
306 (setq n (mod n 16)))
307 (cond
308 ((and (>= n 0) (< n 16))
309 (intern (concat "fg:erc-color-face" (number-to-string n))))
310 (t (erc-log (format " Wrong color: %s" n)) 'default))))
311
312 (define-erc-module irccontrols nil
313 "This mode enables the interpretation of IRC control chars."
314 ((add-hook 'erc-insert-modify-hook 'erc-controls-highlight)
315 (add-hook 'erc-send-modify-hook 'erc-controls-highlight))
316 ((remove-hook 'erc-insert-modify-hook 'erc-controls-highlight)
317 (remove-hook 'erc-send-modify-hook 'erc-controls-highlight)))
318
319 (defun erc-controls-interpret (str)
320 "Return a copy of STR after dealing with IRC control characters.
321 See `erc-interpret-controls-p' and `erc-interpret-mirc-color' for options."
322 (when str
323 (let ((s str))
324 (cond ((eq erc-interpret-controls-p 'remove)
325 (erc-controls-strip s))
326 (erc-interpret-controls-p
327 (let ((boldp nil)
328 (inversep nil)
329 (underlinep nil)
330 (fg nil)
331 (bg nil))
332 (while (string-match erc-controls-highlight-regexp s)
333 (let ((control (match-string 1 s))
334 (fg-color (match-string 2 s))
335 (bg-color (match-string 4 s))
336 (start (match-beginning 0))
337 (end (+ (match-beginning 0)
338 (length (match-string 5 s)))))
339 (setq s (erc-replace-match-subexpression-in-string
340 "" s control 1 start))
341 (cond ((and erc-interpret-mirc-color (or fg-color bg-color))
342 (setq fg fg-color)
343 (setq bg bg-color))
344 ((string= control "\C-b")
345 (setq boldp (not boldp)))
346 ((string= control "\C-v")
347 (setq inversep (not inversep)))
348 ((string= control "\C-_")
349 (setq underlinep (not underlinep)))
350 ((string= control "\C-c")
351 (setq fg nil
352 bg nil))
353 ((string= control "\C-g")
354 (when erc-beep-p
355 (ding)))
356 ((string= control "\C-o")
357 (setq boldp nil
358 inversep nil
359 underlinep nil
360 fg nil
361 bg nil))
362 (t nil))
363 (erc-controls-propertize
364 start end boldp inversep underlinep fg bg s)))
365 s))
366 (t s)))))
367
368 (defun erc-controls-strip (str)
369 "Return a copy of STR with all IRC control characters removed."
370 (when str
371 (let ((s str))
372 (while (string-match erc-controls-remove-regexp s)
373 (setq s (replace-match "" nil nil s)))
374 s)))
375
376 (defvar erc-controls-remove-regexp
377 "\C-b\\|\C-_\\|\C-v\\|\C-g\\|\C-o\\|\C-c[0-9]?[0-9]?\\(,[0-9][0-9]?\\)?"
378 "Regular expression which matches control characters to remove.")
379
380 (defvar erc-controls-highlight-regexp
381 (concat "\\(\C-b\\|\C-v\\|\C-_\\|\C-g\\|\C-o\\|"
382 "\C-c\\([0-9][0-9]?\\)?\\(,\\([0-9][0-9]?\\)\\)?\\)"
383 "\\([^\C-b\C-v\C-_\C-c\C-g\C-o\n]*\\)")
384 "Regular expression which matches control chars and the text to highlight.")
385
386 (defun erc-controls-highlight ()
387 "Highlight IRC control chars in the buffer.
388 This is useful for `erc-insert-modify-hook' and
389 `erc-send-modify-hook'. Also see `erc-interpret-controls-p' and
390 `erc-interpret-mirc-color'."
391 (goto-char (point-min))
392 (cond ((eq erc-interpret-controls-p 'remove)
393 (while (re-search-forward erc-controls-remove-regexp nil t)
394 (replace-match "")))
395 (erc-interpret-controls-p
396 (let ((boldp nil)
397 (inversep nil)
398 (underlinep nil)
399 (fg nil)
400 (bg nil))
401 (while (re-search-forward erc-controls-highlight-regexp nil t)
402 (let ((control (match-string 1))
403 (fg-color (match-string 2))
404 (bg-color (match-string 4))
405 (start (match-beginning 0))
406 (end (+ (match-beginning 0) (length (match-string 5)))))
407 (replace-match "" nil nil nil 1)
408 (cond ((and erc-interpret-mirc-color (or fg-color bg-color))
409 (setq fg fg-color)
410 (setq bg bg-color))
411 ((string= control "\C-b")
412 (setq boldp (not boldp)))
413 ((string= control "\C-v")
414 (setq inversep (not inversep)))
415 ((string= control "\C-_")
416 (setq underlinep (not underlinep)))
417 ((string= control "\C-c")
418 (setq fg nil
419 bg nil))
420 ((string= control "\C-g")
421 (when erc-beep-p
422 (ding)))
423 ((string= control "\C-o")
424 (setq boldp nil
425 inversep nil
426 underlinep nil
427 fg nil
428 bg nil))
429 (t nil))
430 (erc-controls-propertize start end
431 boldp inversep underlinep fg bg)))))
432 (t nil)))
433
434 (defun erc-controls-propertize (from to boldp inversep underlinep fg bg
435 &optional str)
436 "Prepend properties from IRC control characters between FROM and TO.
437 If optional argument STR is provided, apply to STR, otherwise prepend properties
438 to a region in the current buffer."
439 (font-lock-prepend-text-property
440 from
441 to
442 'face
443 (append (if boldp
444 '(erc-bold-face)
445 nil)
446 (if inversep
447 '(erc-inverse-face)
448 nil)
449 (if underlinep
450 '(erc-underline-face)
451 nil)
452 (if fg
453 (list (erc-get-fg-color-face fg))
454 nil)
455 (if bg
456 (list (erc-get-bg-color-face bg))
457 nil))
458 str)
459 str)
460
461 (defun erc-toggle-interpret-controls (&optional arg)
462 "Toggle interpretation of control sequences in messages.
463
464 If ARG is positive, interpretation is turned on.
465 Else interpretation is turned off."
466 (interactive "P")
467 (cond ((and (numberp arg) (> arg 0))
468 (setq erc-interpret-controls-p t))
469 (arg (setq erc-interpret-controls-p nil))
470 (t (setq erc-interpret-controls-p (not erc-interpret-controls-p))))
471 (message "ERC color interpretation %s"
472 (if erc-interpret-controls-p "ON" "OFF")))
473
474 ;; Smiley
475 (define-erc-module smiley nil
476 "This mode translates text-smileys such as :-) into pictures.
477 This requires the function `smiley-region', which is defined in
478 smiley.el, which is part of Gnus."
479 ((add-hook 'erc-insert-modify-hook 'erc-smiley)
480 (add-hook 'erc-send-modify-hook 'erc-smiley))
481 ((remove-hook 'erc-insert-modify-hook 'erc-smiley)
482 (remove-hook 'erc-send-modify-hook 'erc-smiley)))
483
484 (defun erc-smiley ()
485 "Smilify a region.
486 This function should be used with `erc-insert-modify-hook'."
487 (when (fboundp 'smiley-region)
488 (smiley-region (point-min) (point-max))))
489
490 ;; Unmorse
491 (define-erc-module unmorse nil
492 "This mode causes morse code in the current channel to be unmorsed."
493 ((add-hook 'erc-insert-modify-hook 'erc-unmorse))
494 ((remove-hook 'erc-insert-modify-hook 'erc-unmorse)))
495
496 (defun erc-unmorse ()
497 "Unmorse some text.
498 Add this to `erc-insert-modify-hook' if you happen to be on a
499 channel that has weird people talking in morse to each other.
500
501 See also `unmorse-region'."
502 (goto-char (point-min))
503 (when (re-search-forward "[.-]+\\([.-]+[/ ]\\)+[.-]+" nil t)
504 (unmorse-region (match-beginning 0) (match-end 0))))
505
506 ;;; erc-occur
507 (defun erc-occur (string &optional proc)
508 "Search for STRING in all buffers related to current server.
509 If called interactively and prefix argument is given, search on all connected
510 servers. If called from a program, PROC specifies the server process."
511 (interactive
512 (list (read-string "Search for: ")
513 (if current-prefix-arg
514 nil erc-server-process)))
515 (if (fboundp 'multi-occur)
516 (multi-occur (erc-buffer-list nil proc) string)
517 (error "`multi-occur' is not defined as a function")))
518
519 (provide 'erc-goodies)
520
521 ;; arch-tag: d987ae26-9e28-4c72-9596-e617309fb582
522 ;;; erc-goodies.el ends here