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