Remove unnecessary bindings of default-major-mode (all are followed by
[bpt/emacs.git] / lisp / gnus / gnus-salt.el
CommitLineData
eec82323 1;;; gnus-salt.el --- alternate summary mode interfaces for Gnus
16409b0b 2
e84b4b86 3;; Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004,
ae940284 4;; 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
eec82323 5
6748645f
LMI
6;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
7;; Keywords: news
eec82323
LMI
8
9;; This file is part of GNU Emacs.
10
5e809f55 11;; GNU Emacs is free software: you can redistribute it and/or modify
eec82323 12;; it under the terms of the GNU General Public License as published by
5e809f55
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
eec82323
LMI
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
5e809f55 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
eec82323
LMI
23
24;;; Commentary:
25
26;;; Code:
27
5ab7173c
RS
28(eval-when-compile (require 'cl))
29
eec82323
LMI
30(require 'gnus)
31(require 'gnus-sum)
23f87bed 32(require 'gnus-win)
eec82323
LMI
33
34;;;
35;;; gnus-pick-mode
36;;;
37
38(defvar gnus-pick-mode nil
23f87bed
MB
39 "Minor mode for providing a pick-and-read interface in Gnus
40summary buffers.")
eec82323 41
a8151ef7
LMI
42(defcustom gnus-pick-display-summary nil
43 "*Display summary while reading."
44 :type 'boolean
45 :group 'gnus-summary-pick)
46
47(defcustom gnus-pick-mode-hook nil
48 "Hook run in summary pick mode buffers."
49 :type 'hook
50 :group 'gnus-summary-pick)
51
23f87bed
MB
52(when (featurep 'xemacs)
53 (add-hook 'gnus-pick-mode-hook 'gnus-xmas-pick-menu-add))
54
a8151ef7
LMI
55(defcustom gnus-mark-unpicked-articles-as-read nil
56 "*If non-nil, mark all unpicked articles as read."
57 :type 'boolean
58 :group 'gnus-summary-pick)
59
60(defcustom gnus-pick-elegant-flow t
23f87bed
MB
61 "If non-nil, `gnus-pick-start-reading' runs
62 `gnus-summary-next-group' when no articles have been picked."
a8151ef7
LMI
63 :type 'boolean
64 :group 'gnus-summary-pick)
65
66(defcustom gnus-summary-pick-line-format
23f87bed 67 "%-5P %U\%R\%z\%I\%(%[%4L: %-23,23n%]%) %s\n"
eec82323 68 "*The format specification of the lines in pick buffers.
a8151ef7
LMI
69It accepts the same format specs that `gnus-summary-line-format' does."
70 :type 'string
71 :group 'gnus-summary-pick)
eec82323
LMI
72
73;;; Internal variables.
74
75(defvar gnus-pick-mode-map nil)
76
77(unless gnus-pick-mode-map
78 (setq gnus-pick-mode-map (make-sparse-keymap))
79
6748645f
LMI
80 (gnus-define-keys gnus-pick-mode-map
81 " " gnus-pick-next-page
82 "u" gnus-pick-unmark-article-or-thread
83 "." gnus-pick-article-or-thread
84 gnus-down-mouse-2 gnus-pick-mouse-pick-region
16409b0b 85 "\r" gnus-pick-start-reading))
eec82323
LMI
86
87(defun gnus-pick-make-menu-bar ()
88 (unless (boundp 'gnus-pick-menu)
89 (easy-menu-define
23f87bed
MB
90 gnus-pick-menu gnus-pick-mode-map ""
91 '("Pick"
92 ("Pick"
93 ["Article" gnus-summary-mark-as-processable t]
94 ["Thread" gnus-uu-mark-thread t]
95 ["Region" gnus-uu-mark-region t]
96 ["Regexp" gnus-uu-mark-by-regexp t]
97 ["Buffer" gnus-uu-mark-buffer t])
98 ("Unpick"
99 ["Article" gnus-summary-unmark-as-processable t]
100 ["Thread" gnus-uu-unmark-thread t]
101 ["Region" gnus-uu-unmark-region t]
102 ["Regexp" gnus-uu-unmark-by-regexp t]
103 ["Buffer" gnus-summary-unmark-all-processable t])
104 ["Start reading" gnus-pick-start-reading t]
105 ["Switch pick mode off" gnus-pick-mode gnus-pick-mode]))))
eec82323
LMI
106
107(defun gnus-pick-mode (&optional arg)
108 "Minor mode for providing a pick-and-read interface in Gnus summary buffers.
109
110\\{gnus-pick-mode-map}"
111 (interactive "P")
112 (when (eq major-mode 'gnus-summary-mode)
113 (if (not (set (make-local-variable 'gnus-pick-mode)
114 (if (null arg) (not gnus-pick-mode)
115 (> (prefix-numeric-value arg) 0))))
116 (remove-hook 'gnus-message-setup-hook 'gnus-pick-setup-message)
117 ;; Make sure that we don't select any articles upon group entry.
118 (set (make-local-variable 'gnus-auto-select-first) nil)
119 ;; Change line format.
120 (setq gnus-summary-line-format gnus-summary-pick-line-format)
121 (setq gnus-summary-line-format-spec nil)
122 (gnus-update-format-specifications nil 'summary)
123 (gnus-update-summary-mark-positions)
124 (add-hook 'gnus-message-setup-hook 'gnus-pick-setup-message)
125 (set (make-local-variable 'gnus-summary-goto-unread) 'never)
126 ;; Set up the menu.
127 (when (gnus-visual-p 'pick-menu 'menu)
128 (gnus-pick-make-menu-bar))
01c52d31 129 (add-minor-mode 'gnus-pick-mode " Pick" gnus-pick-mode-map)
6748645f 130 (gnus-run-hooks 'gnus-pick-mode-hook))))
eec82323
LMI
131
132(defun gnus-pick-setup-message ()
133 "Make Message do the right thing on exit."
134 (when (and (gnus-buffer-live-p gnus-summary-buffer)
67d0660b 135 (with-current-buffer gnus-summary-buffer
eec82323
LMI
136 gnus-pick-mode))
137 (message-add-action
67d0660b 138 `(gnus-configure-windows ,gnus-current-window-configuration t)
16409b0b 139 'send 'exit 'postpone 'kill)))
eec82323
LMI
140
141(defvar gnus-pick-line-number 1)
142(defun gnus-pick-line-number ()
143 "Return the current line number."
144 (if (bobp)
145 (setq gnus-pick-line-number 1)
146 (incf gnus-pick-line-number)))
147
148(defun gnus-pick-start-reading (&optional catch-up)
149 "Start reading the picked articles.
150If given a prefix, mark all unpicked articles as read."
151 (interactive "P")
152 (if gnus-newsgroup-processable
153 (progn
23f87bed
MB
154 (gnus-summary-limit-to-articles nil)
155 (when (or catch-up gnus-mark-unpicked-articles-as-read)
eec82323 156 (gnus-summary-limit-mark-excluded-as-read))
23f87bed
MB
157 (gnus-summary-first-article)
158 (gnus-configure-windows
eec82323
LMI
159 (if gnus-pick-display-summary 'article 'pick) t))
160 (if gnus-pick-elegant-flow
161 (progn
162 (when (or catch-up gnus-mark-unpicked-articles-as-read)
a8151ef7 163 (gnus-summary-catchup nil t))
eec82323
LMI
164 (if (gnus-group-quit-config gnus-newsgroup-name)
165 (gnus-summary-exit)
166 (gnus-summary-next-group)))
167 (error "No articles have been picked"))))
168
6748645f 169(defun gnus-pick-goto-article (arg)
16409b0b
GM
170 "Go to the article number indicated by ARG.
171If ARG is an invalid article number, then stay on current line."
6748645f
LMI
172 (let (pos)
173 (save-excursion
174 (goto-char (point-min))
175 (when (zerop (forward-line (1- (prefix-numeric-value arg))))
176 (setq pos (point))))
177 (if (not pos)
178 (gnus-error 2 "No such line: %s" arg)
179 (goto-char pos))))
16409b0b 180
eec82323 181(defun gnus-pick-article (&optional arg)
16409b0b 182 "Pick the article on the current line.
eec82323
LMI
183If ARG, pick the article on that line instead."
184 (interactive "P")
185 (when arg
6748645f 186 (gnus-pick-goto-article arg))
eec82323
LMI
187 (gnus-summary-mark-as-processable 1))
188
6748645f 189(defun gnus-pick-article-or-thread (&optional arg)
16409b0b 190 "If `gnus-thread-hide-subtree' is t, then pick the thread on the current line.
6748645f
LMI
191Otherwise pick the article on the current line.
192If ARG, pick the article/thread on that line instead."
193 (interactive "P")
194 (when arg
195 (gnus-pick-goto-article arg))
196 (if gnus-thread-hide-subtree
16409b0b
GM
197 (progn
198 (save-excursion
199 (gnus-uu-mark-thread))
200 (forward-line 1))
6748645f 201 (gnus-summary-mark-as-processable 1)))
16409b0b 202
6748645f 203(defun gnus-pick-unmark-article-or-thread (&optional arg)
16409b0b 204 "If `gnus-thread-hide-subtree' is t, then unmark the thread on current line.
6748645f
LMI
205Otherwise unmark the article on current line.
206If ARG, unmark thread/article on that line instead."
207 (interactive "P")
208 (when arg
209 (gnus-pick-goto-article arg))
210 (if gnus-thread-hide-subtree
16409b0b
GM
211 (save-excursion
212 (gnus-uu-unmark-thread))
6748645f 213 (gnus-summary-unmark-as-processable 1)))
16409b0b 214
eec82323
LMI
215(defun gnus-pick-mouse-pick (e)
216 (interactive "e")
217 (mouse-set-point e)
218 (save-excursion
219 (gnus-summary-mark-as-processable 1)))
220
221(defun gnus-pick-mouse-pick-region (start-event)
222 "Pick articles that the mouse is dragged over.
223This must be bound to a button-down mouse event."
224 (interactive "e")
225 (mouse-minibuffer-check start-event)
226 (let* ((echo-keystrokes 0)
227 (start-posn (event-start start-event))
228 (start-point (posn-point start-posn))
9b40100a 229 (start-line (1+ (count-lines (point-min) start-point)))
eec82323 230 (start-window (posn-window start-posn))
6748645f 231 (bounds (gnus-window-edges start-window))
eec82323
LMI
232 (top (nth 1 bounds))
233 (bottom (if (window-minibuffer-p start-window)
234 (nth 3 bounds)
235 ;; Don't count the mode line.
236 (1- (nth 3 bounds))))
237 (click-count (1- (event-click-count start-event))))
238 (setq mouse-selection-click-count click-count)
239 (setq mouse-selection-click-count-buffer (current-buffer))
240 (mouse-set-point start-event)
23f87bed 241 ;; In case the down click is in the middle of some intangible text,
eec82323
LMI
242 ;; use the end of that text, and put it in START-POINT.
243 (when (< (point) start-point)
244 (goto-char start-point))
245 (gnus-pick-article)
246 (setq start-point (point))
247 ;; end-of-range is used only in the single-click case.
248 ;; It is the place where the drag has reached so far
249 ;; (but not outside the window where the drag started).
6748645f 250 (let (event end end-point (end-of-range (point)))
eec82323 251 (track-mouse
23f87bed
MB
252 (while (progn
253 (setq event (cdr (gnus-read-event-char)))
254 (or (mouse-movement-p event)
255 (eq (car-safe event) 'switch-frame)))
256 (if (eq (car-safe event) 'switch-frame)
257 nil
258 (setq end (event-end event)
259 end-point (posn-point end))
260
261 (cond
262 ;; Are we moving within the original window?
263 ((and (eq (posn-window end) start-window)
264 (integer-or-marker-p end-point))
9b40100a 265 ;; Go to START-POINT first, so that when we move to END-POINT,
23f87bed
MB
266 ;; if it's in the middle of intangible text,
267 ;; point jumps in the direction away from START-POINT.
268 (goto-char start-point)
269 (goto-char end-point)
270 (gnus-pick-article)
271 ;; In case the user moved his mouse really fast, pick
9b40100a
SM
272 ;; articles on the line between this one and the last one.
273 (let* ((this-line (1+ (count-lines (point-min) end-point)))
23f87bed
MB
274 (min-line (min this-line start-line))
275 (max-line (max this-line start-line)))
9b40100a 276 ;; Why not use `forward-line'? --Stef
23f87bed
MB
277 (while (< min-line max-line)
278 (goto-line min-line)
279 (gnus-pick-article)
280 (setq min-line (1+ min-line)))
281 (setq start-line this-line))
282 (when (zerop (% click-count 3))
283 (setq end-of-range (point))))
284 (t
285 (let ((mouse-row (cdr (cdr (mouse-position)))))
286 (cond
287 ((null mouse-row))
288 ((< mouse-row top)
289 (mouse-scroll-subr start-window (- mouse-row top)))
290 ((>= mouse-row bottom)
291 (mouse-scroll-subr start-window
292 (1+ (- mouse-row bottom)))))))))))
eec82323
LMI
293 (when (consp event)
294 (let ((fun (key-binding (vector (car event)))))
295 ;; Run the binding of the terminating up-event, if possible.
23f87bed 296 ;; In the case of a multiple click, it gives the wrong results,
eec82323
LMI
297 ;; because it would fail to set up a region.
298 (when nil
23f87bed
MB
299 ;; (and (= (mod mouse-selection-click-count 3) 0) (fboundp fun))
300 ;; In this case, we can just let the up-event execute normally.
eec82323
LMI
301 (let ((end (event-end event)))
302 ;; Set the position in the event before we replay it,
303 ;; because otherwise it may have a position in the wrong
304 ;; buffer.
305 (setcar (cdr end) end-of-range)
306 ;; Delete the overlay before calling the function,
23f87bed 307 ;; because delete-overlay increases buffer-modified-tick.
eec82323
LMI
308 (push event unread-command-events))))))))
309
310(defun gnus-pick-next-page ()
311 "Go to the next page. If at the end of the buffer, start reading articles."
312 (interactive)
313 (let ((scroll-in-place nil))
314 (condition-case nil
315 (scroll-up)
316 (end-of-buffer (gnus-pick-start-reading)))))
317
318;;;
319;;; gnus-binary-mode
320;;;
321
322(defvar gnus-binary-mode nil
323 "Minor mode for providing a binary group interface in Gnus summary buffers.")
324
325(defvar gnus-binary-mode-hook nil
326 "Hook run in summary binary mode buffers.")
327
328(defvar gnus-binary-mode-map nil)
329
330(unless gnus-binary-mode-map
331 (setq gnus-binary-mode-map (make-sparse-keymap))
332
333 (gnus-define-keys
16409b0b
GM
334 gnus-binary-mode-map
335 "g" gnus-binary-show-article))
eec82323
LMI
336
337(defun gnus-binary-make-menu-bar ()
338 (unless (boundp 'gnus-binary-menu)
339 (easy-menu-define
23f87bed
MB
340 gnus-binary-menu gnus-binary-mode-map ""
341 '("Pick"
342 ["Switch binary mode off" gnus-binary-mode t]))))
eec82323
LMI
343
344(defun gnus-binary-mode (&optional arg)
345 "Minor mode for providing a binary group interface in Gnus summary buffers."
346 (interactive "P")
347 (when (eq major-mode 'gnus-summary-mode)
348 (make-local-variable 'gnus-binary-mode)
349 (setq gnus-binary-mode
350 (if (null arg) (not gnus-binary-mode)
351 (> (prefix-numeric-value arg) 0)))
352 (when gnus-binary-mode
353 ;; Make sure that we don't select any articles upon group entry.
354 (make-local-variable 'gnus-auto-select-first)
355 (setq gnus-auto-select-first nil)
356 (make-local-variable 'gnus-summary-display-article-function)
357 (setq gnus-summary-display-article-function 'gnus-binary-display-article)
358 ;; Set up the menu.
359 (when (gnus-visual-p 'binary-menu 'menu)
360 (gnus-binary-make-menu-bar))
01c52d31 361 (add-minor-mode 'gnus-binary-mode " Binary" gnus-binary-mode-map)
6748645f 362 (gnus-run-hooks 'gnus-binary-mode-hook))))
eec82323
LMI
363
364(defun gnus-binary-display-article (article &optional all-header)
365 "Run ARTICLE through the binary decode functions."
366 (when (gnus-summary-goto-subject article)
23f87bed 367 (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
eec82323
LMI
368 (gnus-uu-decode-uu))))
369
370(defun gnus-binary-show-article (&optional arg)
371 "Bypass the binary functions and show the article."
372 (interactive "P")
373 (let (gnus-summary-display-article-function)
374 (gnus-summary-show-article arg)))
375
376;;;
377;;; gnus-tree-mode
378;;;
379
a8151ef7
LMI
380(defcustom gnus-tree-line-format "%(%[%3,3n%]%)"
381 "Format of tree elements."
382 :type 'string
383 :group 'gnus-summary-tree)
eec82323 384
a8151ef7 385(defcustom gnus-tree-minimize-window t
eec82323
LMI
386 "If non-nil, minimize the tree buffer window.
387If a number, never let the tree buffer grow taller than that number of
a8151ef7 388lines."
6748645f
LMI
389 :type '(choice boolean
390 integer)
a8151ef7 391 :group 'gnus-summary-tree)
eec82323 392
a8151ef7
LMI
393(defcustom gnus-selected-tree-face 'modeline
394 "*Face used for highlighting selected articles in the thread tree."
395 :type 'face
396 :group 'gnus-summary-tree)
eec82323
LMI
397
398(defvar gnus-tree-brackets '((?\[ . ?\]) (?\( . ?\))
399 (?\{ . ?\}) (?< . ?>))
400 "Brackets used in tree nodes.")
401
402(defvar gnus-tree-parent-child-edges '(?- ?\\ ?|)
403 "Characters used to connect parents with children.")
404
a8151ef7
LMI
405(defcustom gnus-tree-mode-line-format "Gnus: %%b %S %Z"
406 "*The format specification for the tree mode line."
407 :type 'string
408 :group 'gnus-summary-tree)
eec82323 409
a8151ef7 410(defcustom gnus-generate-tree-function 'gnus-generate-vertical-tree
eec82323
LMI
411 "*Function for generating a thread tree.
412Two predefined functions are available:
a8151ef7
LMI
413`gnus-generate-horizontal-tree' and `gnus-generate-vertical-tree'."
414 :type '(radio (function-item gnus-generate-vertical-tree)
415 (function-item gnus-generate-horizontal-tree)
416 (function :tag "Other" nil))
417 :group 'gnus-summary-tree)
eec82323 418
a8151ef7
LMI
419(defcustom gnus-tree-mode-hook nil
420 "*Hook run in tree mode buffers."
421 :type 'hook
422 :group 'gnus-summary-tree)
eec82323 423
23f87bed
MB
424(when (featurep 'xemacs)
425 (add-hook 'gnus-tree-mode-hook 'gnus-xmas-tree-menu-add)
426 (add-hook 'gnus-tree-mode-hook 'gnus-xmas-switch-horizontal-scrollbar-off))
427
428
eec82323
LMI
429;;; Internal variables.
430
431(defvar gnus-tree-line-format-alist
432 `((?n gnus-tmp-name ?s)
433 (?f gnus-tmp-from ?s)
434 (?N gnus-tmp-number ?d)
435 (?\[ gnus-tmp-open-bracket ?c)
436 (?\] gnus-tmp-close-bracket ?c)
437 (?s gnus-tmp-subject ?s)))
438
439(defvar gnus-tree-mode-line-format-alist gnus-summary-mode-line-format-alist)
440
441(defvar gnus-tree-mode-line-format-spec nil)
442(defvar gnus-tree-line-format-spec nil)
443
444(defvar gnus-tree-node-length nil)
445(defvar gnus-selected-tree-overlay nil)
446
447(defvar gnus-tree-displayed-thread nil)
16409b0b 448(defvar gnus-tree-inhibit nil)
eec82323
LMI
449
450(defvar gnus-tree-mode-map nil)
451(put 'gnus-tree-mode 'mode-class 'special)
452
453(unless gnus-tree-mode-map
454 (setq gnus-tree-mode-map (make-keymap))
455 (suppress-keymap gnus-tree-mode-map)
456 (gnus-define-keys
16409b0b
GM
457 gnus-tree-mode-map
458 "\r" gnus-tree-select-article
459 gnus-mouse-2 gnus-tree-pick-article
460 "\C-?" gnus-tree-read-summary-keys
461 "h" gnus-tree-show-summary
eec82323 462
16409b0b 463 "\C-c\C-i" gnus-info-find-node)
eec82323
LMI
464
465 (substitute-key-definition
466 'undefined 'gnus-tree-read-summary-keys gnus-tree-mode-map))
467
468(defun gnus-tree-make-menu-bar ()
469 (unless (boundp 'gnus-tree-menu)
470 (easy-menu-define
23f87bed
MB
471 gnus-tree-menu gnus-tree-mode-map ""
472 '("Tree"
473 ["Select article" gnus-tree-select-article t]))))
eec82323
LMI
474
475(defun gnus-tree-mode ()
476 "Major mode for displaying thread trees."
477 (interactive)
6748645f
LMI
478 (gnus-set-format 'tree-mode)
479 (gnus-set-format 'tree t)
eec82323
LMI
480 (when (gnus-visual-p 'tree-menu 'menu)
481 (gnus-tree-make-menu-bar))
482 (kill-all-local-variables)
483 (gnus-simplify-mode-line)
484 (setq mode-name "Tree")
485 (setq major-mode 'gnus-tree-mode)
486 (use-local-map gnus-tree-mode-map)
16409b0b 487 (buffer-disable-undo)
eec82323
LMI
488 (setq buffer-read-only t)
489 (setq truncate-lines t)
490 (save-excursion
491 (gnus-set-work-buffer)
492 (gnus-tree-node-insert (make-mail-header "") nil)
493 (setq gnus-tree-node-length (1- (point))))
cfcd5c91 494 (gnus-run-mode-hooks 'gnus-tree-mode-hook))
eec82323
LMI
495
496(defun gnus-tree-read-summary-keys (&optional arg)
497 "Read a summary buffer key sequence and execute it."
498 (interactive "P")
16409b0b
GM
499 (unless gnus-tree-inhibit
500 (let ((buf (current-buffer))
501 (gnus-tree-inhibit t)
502 win)
503 (set-buffer gnus-article-buffer)
504 (gnus-article-read-summary-keys arg nil t)
505 (when (setq win (get-buffer-window buf))
506 (select-window win)
507 (when gnus-selected-tree-overlay
508 (goto-char (or (gnus-overlay-end gnus-selected-tree-overlay) 1)))
509 (gnus-tree-minimize)))))
eec82323 510
a8151ef7
LMI
511(defun gnus-tree-show-summary ()
512 "Reconfigure windows to show summary buffer."
513 (interactive)
514 (if (not (gnus-buffer-live-p gnus-summary-buffer))
515 (error "There is no summary buffer for this tree buffer")
516 (gnus-configure-windows 'article)
517 (gnus-summary-goto-subject gnus-current-article)))
518
eec82323
LMI
519(defun gnus-tree-select-article (article)
520 "Select the article under point, if any."
521 (interactive (list (gnus-tree-article-number)))
522 (let ((buf (current-buffer)))
523 (when article
67d0660b 524 (with-current-buffer gnus-summary-buffer
eec82323
LMI
525 (gnus-summary-goto-article article))
526 (select-window (get-buffer-window buf)))))
527
528(defun gnus-tree-pick-article (e)
529 "Select the article under the mouse pointer."
530 (interactive "e")
531 (mouse-set-point e)
532 (gnus-tree-select-article (gnus-tree-article-number)))
533
534(defun gnus-tree-article-number ()
535 (get-text-property (point) 'gnus-number))
536
537(defun gnus-tree-article-region (article)
538 "Return a cons with BEG and END of the article region."
16409b0b
GM
539 (let ((pos (text-property-any
540 (point-min) (point-max) 'gnus-number article)))
eec82323
LMI
541 (when pos
542 (cons pos (next-single-property-change pos 'gnus-number)))))
543
544(defun gnus-tree-goto-article (article)
16409b0b
GM
545 (let ((pos (text-property-any
546 (point-min) (point-max) 'gnus-number article)))
eec82323
LMI
547 (when pos
548 (goto-char pos))))
549
550(defun gnus-tree-recenter ()
551 "Center point in the tree window."
552 (let ((selected (selected-window))
23f87bed 553 (tree-window (gnus-get-buffer-window gnus-tree-buffer t)))
eec82323
LMI
554 (when tree-window
555 (select-window tree-window)
556 (when gnus-selected-tree-overlay
557 (goto-char (or (gnus-overlay-end gnus-selected-tree-overlay) 1)))
558 (let* ((top (cond ((< (window-height) 4) 0)
559 ((< (window-height) 7) 1)
560 (t 2)))
561 (height (1- (window-height)))
562 (bottom (save-excursion (goto-char (point-max))
563 (forward-line (- height))
564 (point))))
23f87bed 565 ;; Set the window start to either `bottom', which is the biggest
eec82323
LMI
566 ;; possible valid number, or the second line from the top,
567 ;; whichever is the least.
568 (set-window-start
569 tree-window (min bottom (save-excursion
570 (forward-line (- top)) (point)))))
571 (select-window selected))))
572
573(defun gnus-get-tree-buffer ()
574 "Return the tree buffer properly initialized."
67d0660b 575 (with-current-buffer (gnus-get-buffer-create gnus-tree-buffer)
eec82323 576 (unless (eq major-mode 'gnus-tree-mode)
eec82323
LMI
577 (gnus-tree-mode))
578 (current-buffer)))
579
580(defun gnus-tree-minimize ()
581 (when (and gnus-tree-minimize-window
582 (not (one-window-p)))
583 (let ((windows 0)
584 tot-win-height)
585 (walk-windows (lambda (window) (incf windows)))
586 (setq tot-win-height
587 (- (frame-height)
588 (* window-min-height (1- windows))
589 2))
590 (let* ((window-min-height 2)
591 (height (count-lines (point-min) (point-max)))
592 (min (max (1- window-min-height) height))
593 (tot (if (numberp gnus-tree-minimize-window)
594 (min gnus-tree-minimize-window min)
595 min))
596 (win (get-buffer-window (current-buffer)))
597 (wh (and win (1- (window-height win)))))
598 (setq tot (min tot tot-win-height))
599 (when (and win
600 (not (eq tot wh)))
601 (let ((selected (selected-window)))
602 (when (ignore-errors (select-window win))
603 (enlarge-window (- tot wh))
604 (select-window selected))))))))
605
606;;; Generating the tree.
607
608(defun gnus-tree-node-insert (header sparse &optional adopted)
609 (let* ((dummy (stringp header))
610 (header (if (vectorp header) header
611 (progn
612 (setq header (make-mail-header "*****"))
613 (mail-header-set-number header 0)
614 (mail-header-set-lines header 0)
615 (mail-header-set-chars header 0)
616 header)))
617 (gnus-tmp-from (mail-header-from header))
618 (gnus-tmp-subject (mail-header-subject header))
619 (gnus-tmp-number (mail-header-number header))
620 (gnus-tmp-name
621 (cond
622 ((string-match "(.+)" gnus-tmp-from)
623 (substring gnus-tmp-from
624 (1+ (match-beginning 0)) (1- (match-end 0))))
625 ((string-match "<[^>]+> *$" gnus-tmp-from)
626 (let ((beg (match-beginning 0)))
627 (or (and (string-match "^\"[^\"]*\"" gnus-tmp-from)
628 (substring gnus-tmp-from (1+ (match-beginning 0))
629 (1- (match-end 0))))
630 (substring gnus-tmp-from 0 beg))))
631 ((memq gnus-tmp-number sparse)
632 "***")
633 (t gnus-tmp-from)))
634 (gnus-tmp-open-bracket
635 (cond ((memq gnus-tmp-number sparse)
636 (caadr gnus-tree-brackets))
637 (dummy (caaddr gnus-tree-brackets))
638 (adopted (car (nth 3 gnus-tree-brackets)))
639 (t (caar gnus-tree-brackets))))
640 (gnus-tmp-close-bracket
641 (cond ((memq gnus-tmp-number sparse)
642 (cdadr gnus-tree-brackets))
643 (adopted (cdr (nth 3 gnus-tree-brackets)))
644 (dummy
645 (cdaddr gnus-tree-brackets))
646 (t (cdar gnus-tree-brackets))))
647 (buffer-read-only nil)
648 beg end)
649 (gnus-add-text-properties
650 (setq beg (point))
651 (setq end (progn (eval gnus-tree-line-format-spec) (point)))
652 (list 'gnus-number gnus-tmp-number))
653 (when (or t (gnus-visual-p 'tree-highlight 'highlight))
654 (gnus-tree-highlight-node gnus-tmp-number beg end))))
655
656(defun gnus-tree-highlight-node (article beg end)
657 "Highlight current line according to `gnus-summary-highlight'."
658 (let ((list gnus-summary-highlight)
659 face)
67d0660b 660 (with-current-buffer gnus-summary-buffer
eec82323
LMI
661 (let* ((score (or (cdr (assq article gnus-newsgroup-scored))
662 gnus-summary-default-score 0))
663 (default gnus-summary-default-score)
23f87bed
MB
664 (default-high gnus-summary-default-high-score)
665 (default-low gnus-summary-default-low-score)
666 (uncached (memq article gnus-newsgroup-undownloaded))
667 (downloaded (not uncached))
eec82323
LMI
668 (mark (or (gnus-summary-article-mark article) gnus-unread-mark)))
669 ;; Eval the cars of the lists until we find a match.
670 (while (and list
671 (not (eval (caar list))))
672 (setq list (cdr list)))))
673 (unless (eq (setq face (cdar list)) (get-text-property beg 'face))
6748645f 674 (gnus-put-text-property-excluding-characters-with-faces
eec82323
LMI
675 beg end 'face
676 (if (boundp face) (symbol-value face) face)))))
677
678(defun gnus-tree-indent (level)
679 (insert (make-string (1- (* (1+ gnus-tree-node-length) level)) ? )))
680
681(defvar gnus-tmp-limit)
682(defvar gnus-tmp-sparse)
683(defvar gnus-tmp-indent)
684
685(defun gnus-generate-tree (thread)
686 "Generate a thread tree for THREAD."
67d0660b 687 (with-current-buffer (gnus-get-tree-buffer)
eec82323
LMI
688 (let ((buffer-read-only nil)
689 (gnus-tmp-indent 0))
690 (erase-buffer)
691 (funcall gnus-generate-tree-function thread 0)
692 (gnus-set-mode-line 'tree)
693 (goto-char (point-min))
694 (gnus-tree-minimize)
695 (gnus-tree-recenter)
696 (let ((selected (selected-window)))
23f87bed
MB
697 (when (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t)
698 (select-window (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t))
eec82323
LMI
699 (gnus-horizontal-recenter)
700 (select-window selected))))))
701
702(defun gnus-generate-horizontal-tree (thread level &optional dummyp adopted)
703 "Generate a horizontal tree."
704 (let* ((dummy (stringp (car thread)))
705 (do (or dummy
a8151ef7
LMI
706 (and (car thread)
707 (memq (mail-header-number (car thread))
708 gnus-tmp-limit))))
eec82323
LMI
709 col beg)
710 (if (not do)
711 ;; We don't want this article.
712 (setq thread (cdr thread))
713 (if (not (bolp))
714 ;; Not the first article on the line, so we insert a "-".
715 (insert (car gnus-tree-parent-child-edges))
716 ;; If the level isn't zero, then we insert some indentation.
717 (unless (zerop level)
718 (gnus-tree-indent level)
719 (insert (cadr gnus-tree-parent-child-edges))
01c52d31 720 (setq col (- (setq beg (point)) (point-at-bol) 1))
eec82323
LMI
721 ;; Draw "|" lines upwards.
722 (while (progn
723 (forward-line -1)
724 (forward-char col)
16409b0b 725 (eq (char-after) ? ))
eec82323
LMI
726 (delete-char 1)
727 (insert (caddr gnus-tree-parent-child-edges)))
728 (goto-char beg)))
729 (setq dummyp nil)
730 ;; Insert the article node.
731 (gnus-tree-node-insert (pop thread) gnus-tmp-sparse adopted))
732 (if (null thread)
733 ;; End of the thread, so we go to the next line.
734 (unless (bolp)
735 (insert "\n"))
736 ;; Recurse downwards in all children of this article.
737 (while thread
738 (gnus-generate-horizontal-tree
739 (pop thread) (if do (1+ level) level)
740 (or dummyp dummy) dummy)))))
741
742(defsubst gnus-tree-indent-vertical ()
743 (let ((len (- (* (1+ gnus-tree-node-length) gnus-tmp-indent)
01c52d31 744 (- (point) (point-at-bol)))))
eec82323
LMI
745 (when (> len 0)
746 (insert (make-string len ? )))))
747
748(defsubst gnus-tree-forward-line (n)
749 (while (>= (decf n) 0)
750 (unless (zerop (forward-line 1))
751 (end-of-line)
752 (insert "\n")))
753 (end-of-line))
754
755(defun gnus-generate-vertical-tree (thread level &optional dummyp adopted)
756 "Generate a vertical tree."
757 (let* ((dummy (stringp (car thread)))
758 (do (or dummy
759 (and (car thread)
760 (memq (mail-header-number (car thread))
761 gnus-tmp-limit))))
762 beg)
763 (if (not do)
764 ;; We don't want this article.
765 (setq thread (cdr thread))
766 (if (not (save-excursion (beginning-of-line) (bobp)))
767 ;; Not the first article on the line, so we insert a "-".
768 (progn
769 (gnus-tree-indent-vertical)
770 (insert (make-string (/ gnus-tree-node-length 2) ? ))
771 (insert (caddr gnus-tree-parent-child-edges))
772 (gnus-tree-forward-line 1))
773 ;; If the level isn't zero, then we insert some indentation.
774 (unless (zerop gnus-tmp-indent)
775 (gnus-tree-forward-line (1- (* 2 level)))
776 (gnus-tree-indent-vertical)
777 (delete-char -1)
778 (insert (cadr gnus-tree-parent-child-edges))
779 (setq beg (point))
a8151ef7 780 (forward-char -1)
eec82323 781 ;; Draw "-" lines leftwards.
9b40100a 782 (while (and (not (bobp))
16409b0b 783 (eq (char-after (1- (point))) ? ))
a8151ef7
LMI
784 (delete-char -1)
785 (insert (car gnus-tree-parent-child-edges))
786 (forward-char -1))
eec82323
LMI
787 (goto-char beg)
788 (gnus-tree-forward-line 1)))
789 (setq dummyp nil)
790 ;; Insert the article node.
791 (gnus-tree-indent-vertical)
792 (gnus-tree-node-insert (pop thread) gnus-tmp-sparse adopted)
793 (gnus-tree-forward-line 1))
794 (if (null thread)
795 ;; End of the thread, so we go to the next line.
796 (progn
797 (goto-char (point-min))
798 (end-of-line)
799 (incf gnus-tmp-indent))
800 ;; Recurse downwards in all children of this article.
801 (while thread
802 (gnus-generate-vertical-tree
803 (pop thread) (if do (1+ level) level)
804 (or dummyp dummy) dummy)))))
805
806;;; Interface functions.
807
808(defun gnus-possibly-generate-tree (article &optional force)
809 "Generate the thread tree for ARTICLE if it isn't displayed already."
67d0660b 810 (when (with-current-buffer gnus-summary-buffer
eec82323
LMI
811 (and gnus-use-trees
812 gnus-show-threads
813 (vectorp (gnus-summary-article-header article))))
814 (save-excursion
67d0660b 815 (let ((top (with-current-buffer gnus-summary-buffer
eec82323
LMI
816 (gnus-cut-thread
817 (gnus-remove-thread
818 (mail-header-id
819 (gnus-summary-article-header article))
820 t))))
821 (gnus-tmp-limit gnus-newsgroup-limit)
822 (gnus-tmp-sparse gnus-newsgroup-sparse))
823 (when (or force
824 (not (eq top gnus-tree-displayed-thread)))
825 (gnus-generate-tree top)
826 (setq gnus-tree-displayed-thread top))))))
827
828(defun gnus-tree-open (group)
829 (gnus-get-tree-buffer))
830
831(defun gnus-tree-close (group)
6748645f 832 (gnus-kill-buffer gnus-tree-buffer))
eec82323 833
23f87bed
MB
834(defun gnus-tree-perhaps-minimize ()
835 (when (and gnus-tree-minimize-window
836 (get-buffer gnus-tree-buffer))
67d0660b 837 (with-current-buffer gnus-tree-buffer
23f87bed
MB
838 (gnus-tree-minimize))))
839
eec82323
LMI
840(defun gnus-highlight-selected-tree (article)
841 "Highlight the selected article in the tree."
842 (let ((buf (current-buffer))
843 region)
844 (set-buffer gnus-tree-buffer)
845 (when (setq region (gnus-tree-article-region article))
846 (when (or (not gnus-selected-tree-overlay)
847 (gnus-extent-detached-p gnus-selected-tree-overlay))
848 ;; Create a new overlay.
849 (gnus-overlay-put
9b40100a
SM
850 (setq gnus-selected-tree-overlay
851 (gnus-make-overlay (point-min) (1+ (point-min))))
eec82323
LMI
852 'face gnus-selected-tree-face))
853 ;; Move the overlay to the article.
854 (gnus-move-overlay
855 gnus-selected-tree-overlay (goto-char (car region)) (cdr region))
856 (gnus-tree-minimize)
857 (gnus-tree-recenter)
858 (let ((selected (selected-window)))
23f87bed
MB
859 (when (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t)
860 (select-window (gnus-get-buffer-window (set-buffer gnus-tree-buffer) t))
eec82323
LMI
861 (gnus-horizontal-recenter)
862 (select-window selected))))
23f87bed 863;; If we remove this save-excursion, it updates the wrong mode lines?!?
67d0660b 864 (with-current-buffer gnus-tree-buffer
eec82323
LMI
865 (gnus-set-mode-line 'tree))
866 (set-buffer buf)))
867
868(defun gnus-tree-highlight-article (article face)
67d0660b 869 (with-current-buffer (gnus-get-tree-buffer)
eec82323
LMI
870 (let (region)
871 (when (setq region (gnus-tree-article-region article))
872 (gnus-put-text-property (car region) (cdr region) 'face face)
873 (set-window-point
23f87bed 874 (gnus-get-buffer-window (current-buffer) t) (cdr region))))))
eec82323
LMI
875
876;;;
877;;; gnus-carpal
878;;;
879
880(defvar gnus-carpal-group-buffer-buttons
881 '(("next" . gnus-group-next-unread-group)
882 ("prev" . gnus-group-prev-unread-group)
883 ("read" . gnus-group-read-group)
884 ("select" . gnus-group-select-group)
885 ("catch-up" . gnus-group-catchup-current)
886 ("new-news" . gnus-group-get-new-news-this-group)
887 ("toggle-sub" . gnus-group-unsubscribe-current-group)
888 ("subscribe" . gnus-group-unsubscribe-group)
889 ("kill" . gnus-group-kill-group)
890 ("yank" . gnus-group-yank-group)
891 ("describe" . gnus-group-describe-group)
892 "list"
893 ("subscribed" . gnus-group-list-groups)
894 ("all" . gnus-group-list-all-groups)
895 ("killed" . gnus-group-list-killed)
896 ("zombies" . gnus-group-list-zombies)
897 ("matching" . gnus-group-list-matching)
898 ("post" . gnus-group-post-news)
899 ("mail" . gnus-group-mail)
23f87bed 900 ("local" . (lambda () (interactive) (gnus-group-news 0)))
eec82323
LMI
901 ("rescan" . gnus-group-get-new-news)
902 ("browse-foreign" . gnus-group-browse-foreign)
903 ("exit" . gnus-group-exit)))
904
905(defvar gnus-carpal-summary-buffer-buttons
906 '("mark"
907 ("read" . gnus-summary-mark-as-read-forward)
908 ("tick" . gnus-summary-tick-article-forward)
909 ("clear" . gnus-summary-clear-mark-forward)
910 ("expirable" . gnus-summary-mark-as-expirable)
911 "move"
912 ("scroll" . gnus-summary-next-page)
913 ("next-unread" . gnus-summary-next-unread-article)
914 ("prev-unread" . gnus-summary-prev-unread-article)
915 ("first" . gnus-summary-first-unread-article)
916 ("best" . gnus-summary-best-unread-article)
917 "article"
918 ("headers" . gnus-summary-toggle-header)
919 ("uudecode" . gnus-uu-decode-uu)
920 ("enter-digest" . gnus-summary-enter-digest-group)
921 ("fetch-parent" . gnus-summary-refer-parent-article)
922 "mail"
923 ("move" . gnus-summary-move-article)
924 ("copy" . gnus-summary-copy-article)
925 ("respool" . gnus-summary-respool-article)
926 "threads"
927 ("lower" . gnus-summary-lower-thread)
928 ("kill" . gnus-summary-kill-thread)
929 "post"
930 ("post" . gnus-summary-post-news)
23f87bed
MB
931 ("local" . gnus-summary-news-other-window)
932 ("mail" . gnus-summary-mail-other-window)
eec82323
LMI
933 ("followup" . gnus-summary-followup-with-original)
934 ("reply" . gnus-summary-reply-with-original)
935 ("cancel" . gnus-summary-cancel-article)
936 "misc"
937 ("exit" . gnus-summary-exit)
938 ("fed-up" . gnus-summary-catchup-and-goto-next-group)))
939
940(defvar gnus-carpal-server-buffer-buttons
941 '(("add" . gnus-server-add-server)
942 ("browse" . gnus-server-browse-server)
943 ("list" . gnus-server-list-servers)
944 ("kill" . gnus-server-kill-server)
945 ("yank" . gnus-server-yank-server)
946 ("copy" . gnus-server-copy-server)
947 ("exit" . gnus-server-exit)))
948
949(defvar gnus-carpal-browse-buffer-buttons
950 '(("subscribe" . gnus-browse-unsubscribe-current-group)
951 ("exit" . gnus-browse-exit)))
952
953(defvar gnus-carpal-group-buffer "*Carpal Group*")
954(defvar gnus-carpal-summary-buffer "*Carpal Summary*")
955(defvar gnus-carpal-server-buffer "*Carpal Server*")
956(defvar gnus-carpal-browse-buffer "*Carpal Browse*")
957
958(defvar gnus-carpal-attached-buffer nil)
959
960(defvar gnus-carpal-mode-hook nil
961 "*Hook run in carpal mode buffers.")
962
963(defvar gnus-carpal-button-face 'bold
964 "*Face used on carpal buttons.")
965
966(defvar gnus-carpal-header-face 'bold-italic
967 "*Face used on carpal buffer headers.")
968
969(defvar gnus-carpal-mode-map nil)
970(put 'gnus-carpal-mode 'mode-class 'special)
971
972(if gnus-carpal-mode-map
973 nil
974 (setq gnus-carpal-mode-map (make-keymap))
975 (suppress-keymap gnus-carpal-mode-map)
976 (define-key gnus-carpal-mode-map " " 'gnus-carpal-select)
977 (define-key gnus-carpal-mode-map "\r" 'gnus-carpal-select)
978 (define-key gnus-carpal-mode-map gnus-mouse-2 'gnus-carpal-mouse-select))
979
980(defun gnus-carpal-mode ()
981 "Major mode for clicking buttons.
982
983All normal editing commands are switched off.
984\\<gnus-carpal-mode-map>
985The following commands are available:
986
987\\{gnus-carpal-mode-map}"
988 (interactive)
989 (kill-all-local-variables)
a8151ef7 990 (setq mode-line-modified (cdr gnus-mode-line-modified))
eec82323
LMI
991 (setq major-mode 'gnus-carpal-mode)
992 (setq mode-name "Gnus Carpal")
993 (setq mode-line-process nil)
994 (use-local-map gnus-carpal-mode-map)
16409b0b 995 (buffer-disable-undo)
eec82323
LMI
996 (setq buffer-read-only t)
997 (make-local-variable 'gnus-carpal-attached-buffer)
cfcd5c91 998 (gnus-run-mode-hooks 'gnus-carpal-mode-hook))
eec82323
LMI
999
1000(defun gnus-carpal-setup-buffer (type)
1001 (let ((buffer (symbol-value (intern (format "gnus-carpal-%s-buffer" type)))))
1002 (if (get-buffer buffer)
1003 ()
67d0660b 1004 (with-current-buffer (gnus-get-buffer-create buffer)
eec82323
LMI
1005 (gnus-carpal-mode)
1006 (setq gnus-carpal-attached-buffer
1007 (intern (format "gnus-%s-buffer" type)))
eec82323
LMI
1008 (let ((buttons (symbol-value
1009 (intern (format "gnus-carpal-%s-buffer-buttons"
1010 type))))
1011 (buffer-read-only nil)
1012 button)
1013 (while buttons
1014 (setq button (car buttons)
1015 buttons (cdr buttons))
1016 (if (stringp button)
01c52d31 1017 (set-text-properties
eec82323
LMI
1018 (point)
1019 (prog2 (insert button) (point) (insert " "))
1020 (list 'face gnus-carpal-header-face))
01c52d31 1021 (set-text-properties
eec82323
LMI
1022 (point)
1023 (prog2 (insert (car button)) (point) (insert " "))
1024 (list 'gnus-callback (cdr button)
1025 'face gnus-carpal-button-face
1026 gnus-mouse-face-prop 'highlight))))
1027 (let ((fill-column (- (window-width) 2)))
1028 (fill-region (point-min) (point-max)))
1029 (set-window-point (get-buffer-window (current-buffer))
1030 (point-min)))))))
1031
1032(defun gnus-carpal-select ()
1033 "Select the button under point."
1034 (interactive)
1035 (let ((func (get-text-property (point) 'gnus-callback)))
1036 (if (null func)
1037 ()
1038 (pop-to-buffer (symbol-value gnus-carpal-attached-buffer))
1039 (call-interactively func))))
1040
1041(defun gnus-carpal-mouse-select (event)
1042 "Select the button under the mouse pointer."
1043 (interactive "e")
1044 (mouse-set-point event)
1045 (gnus-carpal-select))
1046
1047;;; Allow redefinition of functions.
1048(gnus-ems-redefine)
1049
1050(provide 'gnus-salt)
1051
9b40100a 1052;; arch-tag: 35449164-77b3-4398-bcbd-a2e3e998f810
eec82323 1053;;; gnus-salt.el ends here