(mh-invisible-header-fields-internal): Sort list in a case-insensitive
[bpt/emacs.git] / lisp / mh-e / mh-speed.el
CommitLineData
dda00b2c 1;;; mh-speed.el --- MH-E speedbar support
bdcfe844 2
2f043267 3;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
bdcfe844 4
c3d9274a 5;; Author: Satyaki Das <satyaki@theforce.stanford.edu>
bdcfe844
BW
6;; Maintainer: Bill Wohler <wohler@newt.com>
7;; Keywords: mail
8;; See: mh-e.el
9
10;; This file is part of GNU Emacs.
11
5e809f55 12;; GNU Emacs is free software: you can redistribute it and/or modify
bdcfe844 13;; it under the terms of the GNU General Public License as published by
5e809f55
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
bdcfe844
BW
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
5e809f55 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
bdcfe844
BW
24
25;;; Commentary:
bdcfe844 26
dda00b2c 27;; Future versions should only use flists.
bdcfe844
BW
28
29;;; Change Log:
30
bdcfe844
BW
31;;; Code:
32
bdcfe844 33(require 'mh-e)
dda00b2c
BW
34(mh-require-cl)
35
36(require 'gnus-util)
bdcfe844 37(require 'speedbar)
f0d73c14 38(require 'timer)
bdcfe844 39
dda00b2c 40;; Global variables.
bdcfe844
BW
41(defvar mh-speed-refresh-flag nil)
42(defvar mh-speed-last-selected-folder nil)
43(defvar mh-speed-folder-map (make-hash-table :test #'equal))
bdcfe844
BW
44(defvar mh-speed-flists-cache (make-hash-table :test #'equal))
45(defvar mh-speed-flists-process nil)
46(defvar mh-speed-flists-timer nil)
47(defvar mh-speed-partial-line "")
48
dda00b2c
BW
49\f
50
51;;; Speedbar Hook
52
bdcfe844
BW
53(unless (member 'mh-speed-stealth-update
54 (cdr (assoc "files" speedbar-stealthy-function-list)))
55 ;; Is changing constant lists in elisp safe?
56 (setq speedbar-stealthy-function-list
57 (copy-tree speedbar-stealthy-function-list))
58 (push 'mh-speed-stealth-update
59 (cdr (assoc "files" speedbar-stealthy-function-list))))
60
dda00b2c
BW
61\f
62
63;;; Speedbar Menus
64
65(defvar mh-folder-speedbar-menu-items
66 '("--"
67 ["Visit Folder" mh-speed-view
68 (save-excursion
69 (set-buffer speedbar-buffer)
d5dc8c56 70 (get-text-property (mh-line-beginning-position) 'mh-folder))]
dda00b2c 71 ["Expand Nested Folders" mh-speed-expand-folder
d5dc8c56
BW
72 (and (get-text-property (mh-line-beginning-position) 'mh-children-p)
73 (not (get-text-property (mh-line-beginning-position) 'mh-expanded)))]
dda00b2c 74 ["Contract Nested Folders" mh-speed-contract-folder
d5dc8c56
BW
75 (and (get-text-property (mh-line-beginning-position) 'mh-children-p)
76 (get-text-property (mh-line-beginning-position) 'mh-expanded))]
dda00b2c
BW
77 ["Refresh Speedbar" mh-speed-refresh t])
78 "Extra menu items for speedbar.")
79
80(defvar mh-show-speedbar-menu-items mh-folder-speedbar-menu-items)
81(defvar mh-letter-speedbar-menu-items mh-folder-speedbar-menu-items)
82
83\f
84
85;;; Speedbar Keys
86
87(defvar mh-folder-speedbar-key-map (speedbar-make-specialized-keymap)
88 "Specialized speedbar keymap for MH-E buffers.")
89
90(gnus-define-keys mh-folder-speedbar-key-map
91 "+" mh-speed-expand-folder
92 "-" mh-speed-contract-folder
93 "\r" mh-speed-view
94 "r" mh-speed-refresh)
95
96(defvar mh-show-speedbar-key-map mh-folder-speedbar-key-map)
97(defvar mh-letter-speedbar-key-map mh-folder-speedbar-key-map)
98
99\f
100
101;;; Speedbar Commands
102
103;; Alphabetical.
104
105(defalias 'mh-speed-contract-folder 'mh-speed-toggle)
106
107(defalias 'mh-speed-expand-folder 'mh-speed-toggle)
108
109(defun mh-speed-refresh ()
110 "Regenerates the list of folders in the speedbar.
111
112Run this command if you've added or deleted a folder, or want to
113update the unseen message count before the next automatic
114update."
115 (interactive)
116 (mh-speed-flists t)
117 (mh-speed-invalidate-map ""))
118
119(defun mh-speed-stealth-update (&optional force)
120 "Do stealth update.
121With non-nil FORCE, the update is always carried out."
122 (cond ((save-excursion (set-buffer speedbar-buffer)
123 (get-text-property (point-min) 'mh-level))
124 ;; Execute this hook and *don't* run anything else
125 (mh-speed-update-current-folder force)
126 nil)
127 ;; Otherwise on to your regular programming
128 (t t)))
129
130(defun mh-speed-toggle (&rest args)
131 "Toggle the display of child folders in the speedbar.
132The optional ARGS from speedbar are ignored."
133 (interactive)
134 (declare (ignore args))
135 (beginning-of-line)
136 (let ((parent (get-text-property (point) 'mh-folder))
137 (kids-p (get-text-property (point) 'mh-children-p))
138 (expanded (get-text-property (point) 'mh-expanded))
139 (level (get-text-property (point) 'mh-level))
140 (point (point))
141 start-region)
142 (speedbar-with-writable
143 (cond ((not kids-p) nil)
144 (expanded
145 (forward-line)
146 (setq start-region (point))
147 (while (and (get-text-property (point) 'mh-level)
148 (> (get-text-property (point) 'mh-level) level))
149 (let ((folder (get-text-property (point) 'mh-folder)))
150 (when (gethash folder mh-speed-folder-map)
151 (set-marker (gethash folder mh-speed-folder-map) nil)
152 (remhash folder mh-speed-folder-map)))
153 (forward-line))
154 (delete-region start-region (point))
155 (forward-line -1)
156 (speedbar-change-expand-button-char ?+)
157 (add-text-properties
d5dc8c56 158 (mh-line-beginning-position) (1+ (line-beginning-position))
dda00b2c
BW
159 '(mh-expanded nil)))
160 (t
161 (forward-line)
162 (mh-speed-add-buttons parent (1+ level))
163 (goto-char point)
164 (speedbar-change-expand-button-char ?-)
165 (add-text-properties
d5dc8c56 166 (mh-line-beginning-position) (1+ (line-beginning-position))
dda00b2c
BW
167 `(mh-expanded t)))))))
168
169(defun mh-speed-view (&rest args)
170 "Visits the selected folder just as if you had used \\<mh-folder-mode-map>\\[mh-visit-folder].
171The optional ARGS from speedbar are ignored."
172 (interactive)
173 (declare (ignore args))
d5dc8c56 174 (let* ((folder (get-text-property (mh-line-beginning-position) 'mh-folder))
dda00b2c
BW
175 (range (and (stringp folder)
176 (mh-read-range "Scan" folder t nil nil
177 mh-interpret-number-as-range-flag))))
178 (when (stringp folder)
179 (speedbar-with-attached-buffer
180 (mh-visit-folder folder range)
181 (delete-other-windows)))))
182
183\f
184
185;;; Support Routines
186
c3d9274a 187;;;###mh-autoload
bdcfe844
BW
188(defun mh-folder-speedbar-buttons (buffer)
189 "Interface function to create MH-E speedbar buffer.
2dcf34f9
BW
190BUFFER is the MH-E buffer for which the speedbar buffer is to be
191created."
bdcfe844
BW
192 (unless (get-text-property (point-min) 'mh-level)
193 (erase-buffer)
194 (clrhash mh-speed-folder-map)
195 (speedbar-make-tag-line 'bracket ?+ 'mh-speed-toggle nil " " 'ignore nil
44d55491 196 'mh-speedbar-folder 0)
bdcfe844
BW
197 (forward-line -1)
198 (setf (gethash nil mh-speed-folder-map)
924df208 199 (set-marker (or (gethash nil mh-speed-folder-map) (make-marker))
d5dc8c56 200 (1+ (mh-line-beginning-position))))
bdcfe844 201 (add-text-properties
d5dc8c56 202 (mh-line-beginning-position) (1+ (line-beginning-position))
bdcfe844
BW
203 `(mh-folder nil mh-expanded nil mh-children-p t mh-level 0))
204 (mh-speed-stealth-update t)
6b960c10 205 (when (> mh-speed-update-interval 0)
bdcfe844
BW
206 (mh-speed-flists nil))))
207
c3d9274a 208;;;###mh-autoload
bdcfe844 209(defalias 'mh-show-speedbar-buttons 'mh-folder-speedbar-buttons)
c3d9274a 210;;;###mh-autoload
bdcfe844
BW
211(defalias 'mh-letter-speedbar-buttons 'mh-folder-speedbar-buttons)
212
bdcfe844
BW
213(defmacro mh-speed-select-attached-frame ()
214 "Compatibility macro to handle speedbar versions 0.11a and 0.14beta4."
215 (cond ((fboundp 'dframe-select-attached-frame)
216 '(dframe-select-attached-frame speedbar-frame))
217 ((boundp 'speedbar-attached-frame)
218 '(select-frame speedbar-attached-frame))
219 (t (error "Installed speedbar version not supported by MH-E"))))
220
221(defun mh-speed-update-current-folder (force)
222 "Update speedbar highlighting of the current folder.
2dcf34f9
BW
223The function tries to be smart so that work done is minimized.
224The currently highlighted folder is cached and no highlighting
225happens unless it changes.
bdcfe844 226Also highlighting is suspended while the speedbar frame is selected.
2dcf34f9
BW
227Otherwise you get the disconcerting behavior of folders popping open
228on their own when you are trying to navigate around in the speedbar
229buffer.
bdcfe844
BW
230
231The update is always carried out if FORCE is non-nil."
232 (let* ((lastf (selected-frame))
c3d9274a 233 (newcf (save-excursion
bdcfe844
BW
234 (mh-speed-select-attached-frame)
235 (prog1 (mh-speed-extract-folder-name (buffer-name))
236 (select-frame lastf))))
c3d9274a
BW
237 (lastb (current-buffer))
238 (case-fold-search t))
bdcfe844
BW
239 (when (or force
240 (and mh-speed-refresh-flag (not (eq lastf speedbar-frame)))
241 (and (stringp newcf)
242 (equal (substring newcf 0 1) "+")
243 (not (equal newcf mh-speed-last-selected-folder))))
244 (setq mh-speed-refresh-flag nil)
245 (select-frame speedbar-frame)
246 (set-buffer speedbar-buffer)
247
248 ;; Remove highlight from previous match...
44d55491 249 (mh-speed-highlight mh-speed-last-selected-folder 'mh-speedbar-folder)
bdcfe844
BW
250
251 ;; If we found a match highlight it...
252 (when (mh-speed-goto-folder newcf)
44d55491 253 (mh-speed-highlight newcf 'mh-speedbar-selected-folder))
bdcfe844
BW
254
255 (setq mh-speed-last-selected-folder newcf)
256 (speedbar-position-cursor-on-line)
257 (set-window-point (frame-first-window speedbar-frame) (point))
258 (set-buffer lastb)
259 (select-frame lastf))
260 (when (eq lastf speedbar-frame)
261 (setq mh-speed-refresh-flag t))))
262
dda00b2c
BW
263(defun mh-speed-highlight (folder face)
264 "Set FOLDER to FACE."
265 (save-excursion
266 (speedbar-with-writable
267 (goto-char (gethash folder mh-speed-folder-map (point)))
268 (beginning-of-line)
d5dc8c56 269 (if (re-search-forward "([1-9][0-9]*/[0-9]+)" (mh-line-end-position) t)
dda00b2c
BW
270 (setq face (mh-speed-bold-face face))
271 (setq face (mh-speed-normal-face face)))
272 (beginning-of-line)
d5dc8c56
BW
273 (when (re-search-forward "\\[.\\] " (mh-line-end-position) t)
274 (put-text-property (point) (mh-line-end-position) 'face face)))))
dda00b2c 275
bdcfe844
BW
276(defun mh-speed-normal-face (face)
277 "Return normal face for given FACE."
44d55491
MB
278 (cond ((eq face 'mh-speedbar-folder-with-unseen-messages)
279 'mh-speedbar-folder)
280 ((eq face 'mh-speedbar-selected-folder-with-unseen-messages)
281 'mh-speedbar-selected-folder)
bdcfe844
BW
282 (t face)))
283
284(defun mh-speed-bold-face (face)
285 "Return bold face for given FACE."
44d55491
MB
286 (cond ((eq face 'mh-speedbar-folder)
287 'mh-speedbar-folder-with-unseen-messages)
288 ((eq face 'mh-speedbar-selected-folder)
289 'mh-speedbar-selected-folder-with-unseen-messages)
bdcfe844
BW
290 (t face)))
291
bdcfe844
BW
292(defun mh-speed-goto-folder (folder)
293 "Move point to line containing FOLDER.
294The function will expand out parent folders of FOLDER if needed."
295 (let ((prefix folder)
296 (suffix-list ())
297 (last-slash t))
298 (while (and (not (gethash prefix mh-speed-folder-map)) last-slash)
c3d9274a 299 (setq last-slash (mh-search-from-end ?/ prefix))
bdcfe844
BW
300 (when (integerp last-slash)
301 (push (substring prefix (1+ last-slash)) suffix-list)
302 (setq prefix (substring prefix 0 last-slash))))
303 (let ((prefix-position (gethash prefix mh-speed-folder-map)))
304 (if prefix-position
305 (goto-char prefix-position)
306 (goto-char (point-min))
307 (mh-speed-toggle)
308 (unless (get-text-property (point) 'mh-expanded)
309 (mh-speed-toggle))
310 (goto-char (gethash prefix mh-speed-folder-map))))
311 (while suffix-list
312 ;; We always need atleast one toggle. We need two if the directory list
313 ;; is stale since a folder was added.
d5dc8c56 314 (when (equal prefix (get-text-property (mh-line-beginning-position)
bdcfe844
BW
315 'mh-folder))
316 (mh-speed-toggle)
317 (unless (get-text-property (point) 'mh-expanded)
318 (mh-speed-toggle)))
319 (setq prefix (format "%s/%s" prefix (pop suffix-list)))
320 (goto-char (gethash prefix mh-speed-folder-map (point))))
321 (beginning-of-line)
322 (equal folder (get-text-property (point) 'mh-folder))))
323
324(defun mh-speed-extract-folder-name (buffer)
325 "Given an MH-E BUFFER find the folder that should be highlighted.
2dcf34f9
BW
326Do the right thing for the different kinds of buffers that MH-E
327uses."
bdcfe844
BW
328 (save-excursion
329 (set-buffer buffer)
330 (cond ((eq major-mode 'mh-folder-mode)
331 mh-current-folder)
332 ((eq major-mode 'mh-show-mode)
333 (set-buffer mh-show-folder-buffer)
334 mh-current-folder)
c3d9274a 335 ((eq major-mode 'mh-letter-mode)
bdcfe844
BW
336 (when (string-match mh-user-path buffer-file-name)
337 (let* ((rel-path (substring buffer-file-name (match-end 0)))
c3d9274a 338 (directory-end (mh-search-from-end ?/ rel-path)))
bdcfe844
BW
339 (when directory-end
340 (format "+%s" (substring rel-path 0 directory-end)))))))))
341
342(defun mh-speed-add-buttons (folder level)
343 "Add speedbar button for FOLDER which is at indented by LEVEL amount."
3d7ca223 344 (let ((folder-list (mh-sub-folders folder)))
bdcfe844
BW
345 (mapc
346 (lambda (f)
347 (let* ((folder-name (format "%s%s%s" (or folder "+")
348 (if folder "/" "") (car f)))
349 (counts (gethash folder-name mh-speed-flists-cache)))
350 (speedbar-with-writable
351 (speedbar-make-tag-line
352 'bracket (if (cdr f) ?+ ? )
353 'mh-speed-toggle nil
354 (format "%s%s"
355 (car f)
356 (if counts
357 (format " (%s/%s)" (car counts) (cdr counts))
358 ""))
359 'mh-speed-view nil
360 (if (and counts (> (car counts) 0))
44d55491
MB
361 'mh-speedbar-folder-with-unseen-messages
362 'mh-speedbar-folder)
bdcfe844
BW
363 level)
364 (save-excursion
365 (forward-line -1)
366 (setf (gethash folder-name mh-speed-folder-map)
924df208
BW
367 (set-marker (or (gethash folder-name mh-speed-folder-map)
368 (make-marker))
d5dc8c56 369 (1+ (mh-line-beginning-position))))
bdcfe844 370 (add-text-properties
d5dc8c56 371 (mh-line-beginning-position) (1+ (mh-line-beginning-position))
bdcfe844 372 `(mh-folder ,folder-name
c3d9274a
BW
373 mh-expanded nil
374 mh-children-p ,(not (not (cdr f)))
375 ,@(if counts `(mh-count
376 (,(car counts) . ,(cdr counts))) ())
377 mh-level ,level))))))
bdcfe844
BW
378 folder-list)))
379
3d7ca223 380(defvar mh-speed-current-folder nil)
924df208 381(defvar mh-speed-flists-folder nil)
bdcfe844 382
f0d73c14
BW
383(defmacro mh-process-kill-without-query (process)
384 "PROCESS can be killed without query on Emacs exit.
2dcf34f9
BW
385Avoid using `process-kill-without-query' if possible since it is
386now obsolete."
f0d73c14
BW
387 (if (fboundp 'set-process-query-on-exit-flag)
388 `(set-process-query-on-exit-flag ,process nil)
389 `(process-kill-without-query ,process)))
390
c3d9274a 391;;;###mh-autoload
a66894d8 392(defun mh-speed-flists (force &rest folders)
bdcfe844 393 "Execute flists -recurse and update message counts.
a66894d8
BW
394If FORCE is non-nil the timer is reset.
395
2dcf34f9
BW
396Any number of optional FOLDERS can be specified. If specified,
397flists is run only for that one folder."
bdcfe844
BW
398 (interactive (list t))
399 (when force
924df208 400 (when mh-speed-flists-timer
d5dc8c56 401 (mh-cancel-timer mh-speed-flists-timer)
924df208 402 (setq mh-speed-flists-timer nil))
bdcfe844
BW
403 (when (and (processp mh-speed-flists-process)
404 (not (eq (process-status mh-speed-flists-process) 'exit)))
924df208 405 (set-process-filter mh-speed-flists-process t)
bdcfe844 406 (kill-process mh-speed-flists-process)
924df208 407 (setq mh-speed-partial-line "")
bdcfe844 408 (setq mh-speed-flists-process nil)))
a66894d8 409 (setq mh-speed-flists-folder folders)
bdcfe844
BW
410 (unless mh-speed-flists-timer
411 (setq mh-speed-flists-timer
412 (run-at-time
6b960c10
BW
413 nil (if (> mh-speed-update-interval 0)
414 mh-speed-update-interval
415 nil)
bdcfe844
BW
416 (lambda ()
417 (unless (and (processp mh-speed-flists-process)
418 (not (eq (process-status mh-speed-flists-process)
419 'exit)))
3d7ca223
BW
420 (setq mh-speed-current-folder
421 (concat
a66894d8
BW
422 (if mh-speed-flists-folder
423 (substring (car (reverse mh-speed-flists-folder)) 1)
424 (with-temp-buffer
425 (call-process (expand-file-name "folder" mh-progs)
426 nil '(t nil) nil "-fast")
427 (buffer-substring (point-min) (1- (point-max)))))
3d7ca223 428 "+"))
bdcfe844 429 (setq mh-speed-flists-process
a66894d8
BW
430 (apply #'start-process "*flists*" nil
431 (expand-file-name "flists" mh-progs)
432 (if mh-speed-flists-folder "-noall" "-all")
433 "-sequence" (symbol-name mh-unseen-seq)
434 (or mh-speed-flists-folder '("-recurse"))))
924df208
BW
435 ;; Run flists on all folders the next time around...
436 (setq mh-speed-flists-folder nil)
f0d73c14 437 (mh-process-kill-without-query mh-speed-flists-process)
bdcfe844
BW
438 (set-process-filter mh-speed-flists-process
439 'mh-speed-parse-flists-output)))))))
440
441;; Copied from mh-make-folder-list-filter...
dda00b2c 442;; XXX Refactor to use mh-make-folder-list-filer?
bdcfe844
BW
443(defun mh-speed-parse-flists-output (process output)
444 "Parse the incremental results from flists.
2dcf34f9
BW
445PROCESS is the flists process and OUTPUT is the results that must
446be handled next."
bdcfe844
BW
447 (let ((prevailing-match-data (match-data))
448 (position 0)
449 line-end line folder unseen total)
450 (unwind-protect
451 (while (setq line-end (string-match "\n" output position))
452 (setq line (format "%s%s"
453 mh-speed-partial-line
454 (substring output position line-end))
455 mh-speed-partial-line "")
c3d9274a 456 (multiple-value-setq (folder unseen total)
3d7ca223 457 (mh-parse-flist-output-line line mh-speed-current-folder))
924df208
BW
458 (when (and folder unseen total
459 (let ((old-pair (gethash folder mh-speed-flists-cache)))
460 (or (not (equal (car old-pair) unseen))
461 (not (equal (cdr old-pair) total)))))
c3d9274a
BW
462 (setf (gethash folder mh-speed-flists-cache) (cons unseen total))
463 (save-excursion
464 (when (buffer-live-p (get-buffer speedbar-buffer))
465 (set-buffer speedbar-buffer)
466 (speedbar-with-writable
467 (when (get-text-property (point-min) 'mh-level)
468 (let ((pos (gethash folder mh-speed-folder-map))
469 face)
470 (when pos
471 (goto-char pos)
d5dc8c56 472 (goto-char (mh-line-beginning-position))
c3d9274a
BW
473 (cond
474 ((null (get-text-property (point) 'mh-count))
d5dc8c56 475 (goto-char (mh-line-end-position))
c3d9274a
BW
476 (setq face (get-text-property (1- (point)) 'face))
477 (insert (format " (%s/%s)" unseen total))
478 (mh-speed-highlight 'unknown face)
d5dc8c56 479 (goto-char (mh-line-beginning-position))
c3d9274a
BW
480 (add-text-properties (point) (1+ (point))
481 `(mh-count (,unseen . ,total))))
482 ((not (equal (get-text-property (point) 'mh-count)
483 (cons unseen total)))
d5dc8c56 484 (goto-char (mh-line-end-position))
c3d9274a 485 (setq face (get-text-property (1- (point)) 'face))
d5dc8c56
BW
486 (re-search-backward " " (mh-line-beginning-position) t)
487 (delete-region (point) (mh-line-end-position))
c3d9274a
BW
488 (insert (format " (%s/%s)" unseen total))
489 (mh-speed-highlight 'unknown face)
d5dc8c56 490 (goto-char (mh-line-beginning-position))
c3d9274a
BW
491 (add-text-properties
492 (point) (1+ (point))
493 `(mh-count (,unseen . ,total))))))))))))
bdcfe844
BW
494 (setq position (1+ line-end)))
495 (set-match-data prevailing-match-data))
c3d9274a 496 (setq mh-speed-partial-line (substring output position))))
bdcfe844 497
c3d9274a 498;;;###mh-autoload
bdcfe844
BW
499(defun mh-speed-invalidate-map (folder)
500 "Remove FOLDER from various optimization caches."
501 (interactive (list ""))
502 (save-excursion
503 (set-buffer speedbar-buffer)
504 (let* ((speedbar-update-flag nil)
c3d9274a 505 (last-slash (mh-search-from-end ?/ folder))
bdcfe844
BW
506 (parent (if last-slash (substring folder 0 last-slash) nil))
507 (parent-position (gethash parent mh-speed-folder-map))
508 (parent-change nil))
bdcfe844 509 (when parent-position
3d7ca223 510 (let ((parent-kids (mh-sub-folders parent)))
bdcfe844
BW
511 (cond ((null parent-kids)
512 (setq parent-change ?+))
513 ((and (null (cdr parent-kids))
514 (equal (if last-slash
515 (substring folder (1+ last-slash))
516 (substring folder 1))
517 (caar parent-kids)))
518 (setq parent-change ? ))))
519 (goto-char parent-position)
d5dc8c56 520 (when (equal (get-text-property (mh-line-beginning-position) 'mh-folder)
bdcfe844 521 parent)
d5dc8c56 522 (when (get-text-property (mh-line-beginning-position) 'mh-expanded)
bdcfe844
BW
523 (mh-speed-toggle))
524 (when parent-change
525 (speedbar-with-writable
526 (mh-speedbar-change-expand-button-char parent-change)
527 (add-text-properties
d5dc8c56 528 (mh-line-beginning-position) (1+ (mh-line-beginning-position))
bdcfe844 529 `(mh-children-p ,(equal parent-change ?+)))))
44d55491 530 (mh-speed-highlight mh-speed-last-selected-folder 'mh-speedbar-folder)
bdcfe844
BW
531 (setq mh-speed-last-selected-folder nil)
532 (setq mh-speed-refresh-flag t)))
533 (when (equal folder "")
dda00b2c 534 (mh-clear-sub-folders-cache)))))
6b960c10 535
dda00b2c
BW
536;; Make it slightly more general to allow for [ ] buttons to be
537;; changed to [+].
538(defun mh-speedbar-change-expand-button-char (char)
539 "Change the expansion button character to CHAR for the current line."
540 (save-excursion
541 (beginning-of-line)
d5dc8c56 542 (if (re-search-forward "\\[.\\]" (mh-line-end-position) t)
dda00b2c
BW
543 (speedbar-with-writable
544 (backward-char 2)
545 (delete-char 1)
546 (insert-char char 1 t)
547 (put-text-property (point) (1- (point)) 'invisible nil)
548 ;; make sure we fix the image on the text here.
549 (mh-funcall-if-exists
550 speedbar-insert-image-button-maybe (- (point) 2) 3)))))
f0d73c14 551
c3d9274a 552;;;###mh-autoload
bdcfe844
BW
553(defun mh-speed-add-folder (folder)
554 "Add FOLDER since it is being created.
555The function invalidates the latest ancestor that is present."
556 (save-excursion
557 (set-buffer speedbar-buffer)
558 (let ((speedbar-update-flag nil)
c3d9274a 559 (last-slash (mh-search-from-end ?/ folder))
bdcfe844
BW
560 (ancestor folder)
561 (ancestor-pos nil))
562 (block while-loop
563 (while last-slash
564 (setq ancestor (substring ancestor 0 last-slash))
565 (setq ancestor-pos (gethash ancestor mh-speed-folder-map))
566 (when ancestor-pos
567 (return-from while-loop))
c3d9274a 568 (setq last-slash (mh-search-from-end ?/ ancestor))))
bdcfe844
BW
569 (unless ancestor-pos (setq ancestor nil))
570 (goto-char (or ancestor-pos (gethash nil mh-speed-folder-map)))
571 (speedbar-with-writable
572 (mh-speedbar-change-expand-button-char ?+)
573 (add-text-properties
d5dc8c56 574 (mh-line-beginning-position) (1+ (mh-line-beginning-position))
bdcfe844 575 `(mh-children-p t)))
d5dc8c56 576 (when (get-text-property (mh-line-beginning-position) 'mh-expanded)
bdcfe844 577 (mh-speed-toggle))
bdcfe844
BW
578 (setq mh-speed-refresh-flag t))))
579
bdcfe844
BW
580(provide 'mh-speed)
581
cee9f5c6
BW
582;; Local Variables:
583;; indent-tabs-mode: nil
584;; sentence-end-double-space: nil
585;; End:
bdcfe844 586
cee9f5c6 587;; arch-tag: d38ddcd4-3c00-4e37-99bf-8b89dda7b32c
bdcfe844 588;;; mh-speed.el ends here