Add 2012 to FSF copyright years for Emacs files (do not merge to trunk)
[bpt/emacs.git] / lisp / mh-e / mh-speed.el
CommitLineData
dda00b2c 1;;; mh-speed.el --- MH-E speedbar support
bdcfe844 2
49f70d46 3;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
dcf71371 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
b5553d47 69 (with-current-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."
b5553d47
SM
122 (cond ((with-current-buffer speedbar-buffer
123 (get-text-property (point-min) 'mh-level))
dda00b2c
BW
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."
b5553d47 328 (with-current-buffer buffer
bdcfe844
BW
329 (cond ((eq major-mode 'mh-folder-mode)
330 mh-current-folder)
331 ((eq major-mode 'mh-show-mode)
332 (set-buffer mh-show-folder-buffer)
333 mh-current-folder)
c3d9274a 334 ((eq major-mode 'mh-letter-mode)
bdcfe844
BW
335 (when (string-match mh-user-path buffer-file-name)
336 (let* ((rel-path (substring buffer-file-name (match-end 0)))
c3d9274a 337 (directory-end (mh-search-from-end ?/ rel-path)))
bdcfe844
BW
338 (when directory-end
339 (format "+%s" (substring rel-path 0 directory-end)))))))))
340
341(defun mh-speed-add-buttons (folder level)
342 "Add speedbar button for FOLDER which is at indented by LEVEL amount."
3d7ca223 343 (let ((folder-list (mh-sub-folders folder)))
bdcfe844
BW
344 (mapc
345 (lambda (f)
346 (let* ((folder-name (format "%s%s%s" (or folder "+")
347 (if folder "/" "") (car f)))
348 (counts (gethash folder-name mh-speed-flists-cache)))
349 (speedbar-with-writable
350 (speedbar-make-tag-line
351 'bracket (if (cdr f) ?+ ? )
352 'mh-speed-toggle nil
353 (format "%s%s"
354 (car f)
355 (if counts
356 (format " (%s/%s)" (car counts) (cdr counts))
357 ""))
358 'mh-speed-view nil
359 (if (and counts (> (car counts) 0))
44d55491
MB
360 'mh-speedbar-folder-with-unseen-messages
361 'mh-speedbar-folder)
bdcfe844
BW
362 level)
363 (save-excursion
364 (forward-line -1)
365 (setf (gethash folder-name mh-speed-folder-map)
924df208
BW
366 (set-marker (or (gethash folder-name mh-speed-folder-map)
367 (make-marker))
d5dc8c56 368 (1+ (mh-line-beginning-position))))
bdcfe844 369 (add-text-properties
d5dc8c56 370 (mh-line-beginning-position) (1+ (mh-line-beginning-position))
bdcfe844 371 `(mh-folder ,folder-name
c3d9274a
BW
372 mh-expanded nil
373 mh-children-p ,(not (not (cdr f)))
374 ,@(if counts `(mh-count
375 (,(car counts) . ,(cdr counts))) ())
376 mh-level ,level))))))
bdcfe844
BW
377 folder-list)))
378
3d7ca223 379(defvar mh-speed-current-folder nil)
924df208 380(defvar mh-speed-flists-folder nil)
bdcfe844 381
f0d73c14
BW
382(defmacro mh-process-kill-without-query (process)
383 "PROCESS can be killed without query on Emacs exit.
2dcf34f9
BW
384Avoid using `process-kill-without-query' if possible since it is
385now obsolete."
f0d73c14
BW
386 (if (fboundp 'set-process-query-on-exit-flag)
387 `(set-process-query-on-exit-flag ,process nil)
388 `(process-kill-without-query ,process)))
389
c3d9274a 390;;;###mh-autoload
a66894d8 391(defun mh-speed-flists (force &rest folders)
bdcfe844 392 "Execute flists -recurse and update message counts.
a66894d8
BW
393If FORCE is non-nil the timer is reset.
394
2dcf34f9
BW
395Any number of optional FOLDERS can be specified. If specified,
396flists is run only for that one folder."
bdcfe844
BW
397 (interactive (list t))
398 (when force
924df208 399 (when mh-speed-flists-timer
d5dc8c56 400 (mh-cancel-timer mh-speed-flists-timer)
924df208 401 (setq mh-speed-flists-timer nil))
bdcfe844
BW
402 (when (and (processp mh-speed-flists-process)
403 (not (eq (process-status mh-speed-flists-process) 'exit)))
924df208 404 (set-process-filter mh-speed-flists-process t)
bdcfe844 405 (kill-process mh-speed-flists-process)
924df208 406 (setq mh-speed-partial-line "")
bdcfe844 407 (setq mh-speed-flists-process nil)))
a66894d8 408 (setq mh-speed-flists-folder folders)
bdcfe844
BW
409 (unless mh-speed-flists-timer
410 (setq mh-speed-flists-timer
411 (run-at-time
6b960c10
BW
412 nil (if (> mh-speed-update-interval 0)
413 mh-speed-update-interval
414 nil)
bdcfe844
BW
415 (lambda ()
416 (unless (and (processp mh-speed-flists-process)
417 (not (eq (process-status mh-speed-flists-process)
418 'exit)))
3d7ca223
BW
419 (setq mh-speed-current-folder
420 (concat
a66894d8
BW
421 (if mh-speed-flists-folder
422 (substring (car (reverse mh-speed-flists-folder)) 1)
423 (with-temp-buffer
424 (call-process (expand-file-name "folder" mh-progs)
425 nil '(t nil) nil "-fast")
426 (buffer-substring (point-min) (1- (point-max)))))
3d7ca223 427 "+"))
bdcfe844 428 (setq mh-speed-flists-process
a66894d8
BW
429 (apply #'start-process "*flists*" nil
430 (expand-file-name "flists" mh-progs)
431 (if mh-speed-flists-folder "-noall" "-all")
432 "-sequence" (symbol-name mh-unseen-seq)
433 (or mh-speed-flists-folder '("-recurse"))))
924df208
BW
434 ;; Run flists on all folders the next time around...
435 (setq mh-speed-flists-folder nil)
f0d73c14 436 (mh-process-kill-without-query mh-speed-flists-process)
bdcfe844
BW
437 (set-process-filter mh-speed-flists-process
438 'mh-speed-parse-flists-output)))))))
439
440;; Copied from mh-make-folder-list-filter...
dda00b2c 441;; XXX Refactor to use mh-make-folder-list-filer?
bdcfe844
BW
442(defun mh-speed-parse-flists-output (process output)
443 "Parse the incremental results from flists.
2dcf34f9
BW
444PROCESS is the flists process and OUTPUT is the results that must
445be handled next."
bdcfe844
BW
446 (let ((prevailing-match-data (match-data))
447 (position 0)
448 line-end line folder unseen total)
449 (unwind-protect
450 (while (setq line-end (string-match "\n" output position))
451 (setq line (format "%s%s"
452 mh-speed-partial-line
453 (substring output position line-end))
454 mh-speed-partial-line "")
c3d9274a 455 (multiple-value-setq (folder unseen total)
86e1c36a 456 (values-list
7c730dd6 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 462 (setf (gethash folder mh-speed-flists-cache) (cons unseen total))
b5553d47
SM
463 (when (buffer-live-p (get-buffer speedbar-buffer))
464 (with-current-buffer speedbar-buffer
c3d9274a
BW
465 (speedbar-with-writable
466 (when (get-text-property (point-min) 'mh-level)
467 (let ((pos (gethash folder mh-speed-folder-map))
468 face)
469 (when pos
470 (goto-char pos)
d5dc8c56 471 (goto-char (mh-line-beginning-position))
c3d9274a
BW
472 (cond
473 ((null (get-text-property (point) 'mh-count))
d5dc8c56 474 (goto-char (mh-line-end-position))
c3d9274a
BW
475 (setq face (get-text-property (1- (point)) 'face))
476 (insert (format " (%s/%s)" unseen total))
477 (mh-speed-highlight 'unknown face)
d5dc8c56 478 (goto-char (mh-line-beginning-position))
c3d9274a
BW
479 (add-text-properties (point) (1+ (point))
480 `(mh-count (,unseen . ,total))))
481 ((not (equal (get-text-property (point) 'mh-count)
482 (cons unseen total)))
d5dc8c56 483 (goto-char (mh-line-end-position))
c3d9274a 484 (setq face (get-text-property (1- (point)) 'face))
d5dc8c56
BW
485 (re-search-backward " " (mh-line-beginning-position) t)
486 (delete-region (point) (mh-line-end-position))
c3d9274a
BW
487 (insert (format " (%s/%s)" unseen total))
488 (mh-speed-highlight 'unknown face)
d5dc8c56 489 (goto-char (mh-line-beginning-position))
c3d9274a
BW
490 (add-text-properties
491 (point) (1+ (point))
492 `(mh-count (,unseen . ,total))))))))))))
bdcfe844
BW
493 (setq position (1+ line-end)))
494 (set-match-data prevailing-match-data))
c3d9274a 495 (setq mh-speed-partial-line (substring output position))))
bdcfe844 496
c3d9274a 497;;;###mh-autoload
bdcfe844
BW
498(defun mh-speed-invalidate-map (folder)
499 "Remove FOLDER from various optimization caches."
500 (interactive (list ""))
b5553d47 501 (with-current-buffer speedbar-buffer
bdcfe844 502 (let* ((speedbar-update-flag nil)
c3d9274a 503 (last-slash (mh-search-from-end ?/ folder))
bdcfe844
BW
504 (parent (if last-slash (substring folder 0 last-slash) nil))
505 (parent-position (gethash parent mh-speed-folder-map))
506 (parent-change nil))
bdcfe844 507 (when parent-position
3d7ca223 508 (let ((parent-kids (mh-sub-folders parent)))
bdcfe844
BW
509 (cond ((null parent-kids)
510 (setq parent-change ?+))
511 ((and (null (cdr parent-kids))
512 (equal (if last-slash
513 (substring folder (1+ last-slash))
514 (substring folder 1))
515 (caar parent-kids)))
516 (setq parent-change ? ))))
517 (goto-char parent-position)
d5dc8c56 518 (when (equal (get-text-property (mh-line-beginning-position) 'mh-folder)
bdcfe844 519 parent)
d5dc8c56 520 (when (get-text-property (mh-line-beginning-position) 'mh-expanded)
bdcfe844
BW
521 (mh-speed-toggle))
522 (when parent-change
523 (speedbar-with-writable
524 (mh-speedbar-change-expand-button-char parent-change)
525 (add-text-properties
d5dc8c56 526 (mh-line-beginning-position) (1+ (mh-line-beginning-position))
bdcfe844 527 `(mh-children-p ,(equal parent-change ?+)))))
44d55491 528 (mh-speed-highlight mh-speed-last-selected-folder 'mh-speedbar-folder)
bdcfe844
BW
529 (setq mh-speed-last-selected-folder nil)
530 (setq mh-speed-refresh-flag t)))
531 (when (equal folder "")
dda00b2c 532 (mh-clear-sub-folders-cache)))))
6b960c10 533
dda00b2c
BW
534;; Make it slightly more general to allow for [ ] buttons to be
535;; changed to [+].
536(defun mh-speedbar-change-expand-button-char (char)
537 "Change the expansion button character to CHAR for the current line."
538 (save-excursion
539 (beginning-of-line)
d5dc8c56 540 (if (re-search-forward "\\[.\\]" (mh-line-end-position) t)
dda00b2c
BW
541 (speedbar-with-writable
542 (backward-char 2)
543 (delete-char 1)
544 (insert-char char 1 t)
545 (put-text-property (point) (1- (point)) 'invisible nil)
546 ;; make sure we fix the image on the text here.
547 (mh-funcall-if-exists
548 speedbar-insert-image-button-maybe (- (point) 2) 3)))))
f0d73c14 549
c3d9274a 550;;;###mh-autoload
bdcfe844
BW
551(defun mh-speed-add-folder (folder)
552 "Add FOLDER since it is being created.
553The function invalidates the latest ancestor that is present."
b5553d47 554 (with-current-buffer speedbar-buffer
bdcfe844 555 (let ((speedbar-update-flag nil)
c3d9274a 556 (last-slash (mh-search-from-end ?/ folder))
bdcfe844
BW
557 (ancestor folder)
558 (ancestor-pos nil))
559 (block while-loop
560 (while last-slash
561 (setq ancestor (substring ancestor 0 last-slash))
562 (setq ancestor-pos (gethash ancestor mh-speed-folder-map))
563 (when ancestor-pos
564 (return-from while-loop))
c3d9274a 565 (setq last-slash (mh-search-from-end ?/ ancestor))))
bdcfe844
BW
566 (unless ancestor-pos (setq ancestor nil))
567 (goto-char (or ancestor-pos (gethash nil mh-speed-folder-map)))
568 (speedbar-with-writable
569 (mh-speedbar-change-expand-button-char ?+)
570 (add-text-properties
d5dc8c56 571 (mh-line-beginning-position) (1+ (mh-line-beginning-position))
bdcfe844 572 `(mh-children-p t)))
d5dc8c56 573 (when (get-text-property (mh-line-beginning-position) 'mh-expanded)
bdcfe844 574 (mh-speed-toggle))
bdcfe844
BW
575 (setq mh-speed-refresh-flag t))))
576
bdcfe844
BW
577(provide 'mh-speed)
578
cee9f5c6
BW
579;; Local Variables:
580;; indent-tabs-mode: nil
581;; sentence-end-double-space: nil
582;; End:
bdcfe844 583
cee9f5c6 584;; arch-tag: d38ddcd4-3c00-4e37-99bf-8b89dda7b32c
bdcfe844 585;;; mh-speed.el ends here