1 ;;; xetla-browse.el --- Arch archives/library browser
3 ;; Copyright (C) 2004 by Stefan Reichoer (GPL)
4 ;; Copyright (C) 2004 Steve Youngs (BSD)
6 ;; Author: Steve Youngs <steve@eicq.org>
7 ;; Maintainer: Steve Youngs <steve@eicq.org>
9 ;; Keywords: archive arch tla
11 ;; Based on xtla-browse.el by: Masatake YAMATO <jet@gyve.org>
13 ;; This file is part of XEtla.
15 ;; Redistribution and use in source and binary forms, with or without
16 ;; modification, are permitted provided that the following conditions
19 ;; 1. Redistributions of source code must retain the above copyright
20 ;; notice, this list of conditions and the following disclaimer.
22 ;; 2. Redistributions in binary form must reproduce the above copyright
23 ;; notice, this list of conditions and the following disclaimer in the
24 ;; documentation and/or other materials provided with the distribution.
26 ;; 3. Neither the name of the author nor the names of any contributors
27 ;; may be used to endorse or promote products derived from this
28 ;; software without specific prior written permission.
30 ;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
31 ;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 ;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33 ;; DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 ;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 ;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 ;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
37 ;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
38 ;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
39 ;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
40 ;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 ;; Contributions from:
45 ;; Stefan Reichoer, <stefan@xsteve.at>
46 ;; Matthieu Moy <Matthieu.Moy@imag.fr>
47 ;; Masatake YAMATO <jet@gyve.org>
48 ;; Milan Zamazal <pdm@zamazal.org>
49 ;; Martin Pool <mbp@sourcefrog.net>
50 ;; Robert Widhopf-Fenk <hack@robf.de>
51 ;; Mark Triggs <mst@dishevelled.net>
53 ;; 1. Load xetla-browse.el
54 ;; 2. M-x xetla-browse RET
66 (autoload 'easy-mmode-define-keymap "easy-mmode")
67 (autoload 'ad-add-advice "advice"))
69 (require 'jde-tree-widget)
72 (defvar xetla-browse-buffer-name "*xetla-browse*")
73 (defvar xetla-browse-buffer-type 'browse)
74 (xetla-add-buffer-type xetla-browse-buffer-type
75 xetla-browse-buffer-name)
77 ;; --------------------------------------
79 ;; --------------------------------------
80 (defvar xetla-browse-open-list '()
81 "List holding the name of open nodes.")
83 (defun xetla-browse-open-list-member (archive
84 &optional category branch version)
85 "Return a node, ARCHIVE/CATEGORY-BRANCH-VERSION is opend or not.
86 CATEGORY, BRANCH, VERSION are optional."
87 (let ((name (list archive category branch version nil)))
88 (member name xetla-browse-open-list)))
90 (defun xetla-browse-open-list-add (archive
91 &optional category branch version)
92 "Add a node specified by the arguments to 'xetla-browse-open-list'.
93 ARCHIVE/CATEGORY-BRANCH-VERSION, ARCHIVE/CATEGORY-BRANCH,
94 ARCHIVE/CATEGORY, ARCHIVE are added. CATEGORY, BRANCH, VERSION
96 (xetla-browse-open-list-add-internal (list archive category branch version nil))
97 (xetla-browse-open-list-add-internal (list archive category branch nil nil))
98 (xetla-browse-open-list-add-internal (list archive category nil nil nil))
99 (xetla-browse-open-list-add-internal (list archive nil nil nil nil))
100 (xetla-browse-open-list-add-internal (list nil nil nil nil nil)))
102 (defun xetla-browse-open-list-add-internal (name)
103 "Add NAME to `xetla-browse-open-list'."
104 (unless (xetla-browse-open-list-member (xetla-name-archive name)
105 (xetla-name-category name)
106 (xetla-name-branch name)
107 (xetla-name-version name))
108 (push name xetla-browse-open-list)))
110 (defun xetla-browse-open-list-remove (archive
111 &optional category branch version)
112 "Remove ARCHIVE/CATEGORY-BRANCH-VERSION from `xetla-browse-open-list'.
113 CATEGORY, BRANCH and VERSION are optional."
114 (let ((name (list archive category branch version nil)))
115 (setq xetla-browse-open-list (delete name xetla-browse-open-list))))
117 (defun xetla-browse-open-tracker (tree)
118 "Add or remove a node represented by TREE to/from `xetla-browse-open-list'.
119 If TREE is opened, it is added. Else it is removed."
120 (let* ((node (widget-get tree :node))
121 (a (widget-get node :archive))
122 (c (widget-get node :category))
123 (b (widget-get node :branch))
124 (v (widget-get node :version)))
125 (if (widget-get tree :open)
126 (xetla-browse-open-list-add a c b v)
127 (xetla-browse-open-list-remove a c b v))))
129 (defun xetla-browse-find-archives-root-widget ()
130 "Return the root widget of archives tree."
132 (goto-char (point-min))
133 (re-search-forward " Archives$")
135 (xetla-widget-node-get-at)))
137 (defun xetla-browse-find-named-widget (parent name type)
138 "Find a widget specified with arguments.
139 PARENT specifies the parent widget.
140 NAME is the name of the widget.
141 TYPE is the type of widget. You can specify :archive, :category,
142 :branch, or :version."
143 (let* ((args (widget-get parent :args))
144 (index (position name args :test (lambda (e w)
145 (let ((node (widget-get w :node)))
146 ;; Next line is hack for version node.
147 (unless node (setq node w))
148 (string= e (widget-get node type))))))
149 (tree (when index (nth index (widget-get parent :children))))
150 (node (when tree (save-excursion (goto-char (widget-get tree :from))
151 (goto-char (next-single-property-change (point) 'widget))
152 (xetla-widget-node-get-at)))))
156 (defun xetla-browse-find-widget (archive
157 &optional category branch version)
158 "Return a list of widgets: (root archive category branch version)
159 root is always the root of the tree, of type `xetla-widget-root-node'.
160 archive is the widget representing ARCHIVE, of type
161 `xetla-widget-archive-node'. The last items are potentially nil if
162 CATEGORY, BRANCH or VERSION is nil. Otherwise, they are respectively
163 of type `xetla-widget-category-node', `xetla-widget-revision-node' and
164 `xetla-widget-version-node'."
165 (let* ((root (xetla-browse-find-archives-root-widget))
166 (a (xetla-browse-find-named-widget
167 (widget-get root :parent) archive :archive))
169 (xetla-browse-find-named-widget
170 (widget-get a :parent) category :category)))
172 (xetla-browse-find-named-widget
173 (widget-get c :parent) branch :branch)))
175 (xetla-browse-find-named-widget
176 (widget-get b :parent) version :version))))
177 (list root a c b v)))
179 (defun xetla-browse-find-single-widget (archive
180 &optional category branch
182 "Similar to `xetla-browse-find-widget'.
183 Difference is it returns only the widget representing the last non-nil
184 widget of the list. The means of ARCHIVE, CATEGORY, BRANCH and VERSION
185 are the same as that of `xetla-browse-find-widget'."
186 (let ((widgets (xetla-browse-find-widget archive category branch
192 (error "Widget not found. Please fill-in a bug report"))))
194 (defun xetla-browse-find-real-widget (widget)
195 "Find real(complete) widget from incomplete WIDGET.
196 When trying to find widgets using (widget-get ... :args), we
197 sometimes find an incomplete widget, having no :from or :to
198 information for example. This function takes as an argument an
199 incomplete widget, and finds the corresponding full widget.
201 WIDGET must be of type xetla-widget-*-node."
202 (case (widget-type widget)
203 (xetla-widget-archive-node
204 (xetla-browse-find-single-widget
205 (widget-get widget :archive)))
206 (xetla-widget-category-node
207 (xetla-browse-find-single-widget
208 (widget-get widget :archive)
209 (widget-get widget :category)))
210 (xetla-widget-branch-node
211 (xetla-browse-find-single-widget
212 (widget-get widget :archive)
213 (widget-get widget :category)
214 (widget-get widget :branch)))
215 (xetla-widget-version-node
216 (xetla-browse-find-single-widget
217 (widget-get widget :archive)
218 (widget-get widget :category)
219 (widget-get widget :version)))))
221 (defun* xetla-browse-open (flash archive
222 &optional category branch version)
223 (let (widgets root a c b v)
226 (return-from xetla-browse-open nil))
227 (setq widgets (xetla-browse-find-widget archive category branch nil))
228 (setq root (nth 0 widgets))
230 (error "Cannot find root archives node"))
231 (xetla-widget-node-toggle-subtree-internal root 'open)
233 (setq widgets (xetla-browse-find-widget archive category branch nil))
234 (setq a (nth 1 widgets))
238 (goto-char (widget-get a :from))
240 (return-from xetla-browse-open nil))
241 (error "Cannot find archive node for: %s" archive)))
242 (xetla-widget-node-toggle-subtree-internal a 'open)
244 (setq widgets (xetla-browse-find-widget archive category branch nil))
245 (setq c (nth 2 widgets))
249 (goto-char (widget-get c :from))
251 (return-from xetla-browse-open nil))
252 (error "Cannot find category node for: %s/%s" archive category)))
253 (xetla-widget-node-toggle-subtree-internal c 'open)
255 (setq widgets (xetla-browse-find-widget archive category branch nil))
256 (setq b (nth 3 widgets))
260 (goto-char (widget-get b :from))
262 (return-from xetla-browse-open nil))
263 (error "Cannot find branch node for: %s/%s-%s" archive category branch)))
264 (xetla-widget-node-toggle-subtree-internal b 'open)
266 (setq widgets (xetla-browse-find-widget archive category branch version))
267 (setq v (nth 4 widgets))
270 (goto-char (widget-get v :from))
272 (return-from xetla-browse-open nil))
273 (error "Cannot find branch node for: %s/%s-%s-%s" archive category branch version)))
276 ;; --------------------------------------
277 ;; Abstract Super Widget
278 ;; --------------------------------------
279 (define-widget 'xetla-widget-node 'item
280 "Abstract super widget for xetla-widget-*-node."
282 :format "%[ %t%]%{%v%}\n"
287 :keep '(:marks :open)
288 :open-subtree (if (fboundp 'tree-widget-open-node)
289 'tree-widget-open-node
290 'xetla-tree-widget-node-toggle-subtree-for-tree-widget-v1)
291 :close-subtree (if (fboundp 'tree-widget-open-node)
292 'tree-widget-close-node
293 'xetla-tree-widget-node-toggle-subtree-for-tree-widget-v1))
295 (defvar xetla-widget-node-map
296 (let ((map (copy-keymap xetla-context-map-template)))
297 (define-key map [return]
298 'xetla-widget-node-toggle-subtree)
299 (define-key map [button2]
300 'xetla-widget-node-toggle-subtree-by-mouse)
301 (define-key map "\C-m"
302 'xetla-widget-node-toggle-subtree)
303 (define-key map (xetla-prefix-buffer ?p)
304 'xetla-show-process-buffer)
305 (define-key map (xetla-prefix-buffer ?L)
306 'xetla-open-internal-log-buffer)
307 (define-key map (xetla-prefix-buffer xetla-key-show-bookmark)
309 (define-key map xetla-keyvec-kill-ring
310 'xetla-widget-node-save-name-to-kill-ring)
311 (define-key map xetla-keyvec-add-bookmark
312 'xetla-widget-node-add-bookmark)
314 "Keymap commonly used in xetla-widget-*-node.")
316 (defun xetla-widget-node-value-create (widget keyword)
317 "Create value for WIDGET.
318 KEYWORD is used to get the base string to create the value."
319 (insert (let* ((marks (widget-get widget :marks))
320 (string (widget-get widget keyword))
321 (value (xetla-widget-node-install-ui-element
322 widget (if (string= string "") "<empty>"
324 (concat marks value))))
326 (defun xetla-widget-node-install-ui-element (widget value &optional face)
327 "Create a string with keymap, menu and face properties.
328 The keymap and menu are retrieved from WIDGET.
329 The string is copied from VALUE.
330 FACE is useds as the face."
331 (let ((prop-value (xetla-face-add value
332 (if face face (widget-get widget :face))
333 (widget-get widget :keymap)
334 (widget-get widget :menu))))
335 (put-text-property 0 (length value)
340 (defun xetla-widget-node-get-at (&optional point)
341 "Get widget at POINT."
342 (get-text-property (if point point (point)) 'widget))
344 (defun xetla-widget-node-get-name (&optional point)
345 "Get name list associated widget under the POINT."
346 (let ((widget (xetla-widget-node-get-at point)))
347 (list (widget-get widget :archive)
348 (widget-get widget :category)
349 (widget-get widget :branch)
350 (widget-get widget :version)
353 (defun xetla-widget-node-get-type (&optional point)
354 "Get type of widget under the POINT.
356 Can be either 'archive, 'category, 'branch, 'version or nil for the
358 (let ((widget (xetla-widget-node-get-at point)))
359 (widget-get widget :xetla-type)))
361 (defun xetla-widget-get-ancestor (widget level)
362 "Get the ancestor widget of WIDGET.
363 \"ancestor\" widget stands for the LEVEL upper widget
364 in the archives tree."
368 (setq parent (widget-get parent :parent)
372 (defun xetla-widget-node-refresh (&optional level point
376 "Refresh node and LEVEL subnode at the POINT.
377 Before refreshing node, names cache are also refreshed if
378 ARCHIVE, CATEGORY, and/or BRANCH are specified."
380 (unless level (setq level 1))
381 (unless point (setq point (point)))
383 (xetla-archive-tree-build-versions archive
388 (xetla-archive-tree-build-branches archive
392 (xetla-archive-tree-build-categories archive
395 (xetla-archive-tree-build-archives nil t))))
396 (let* ((widget (xetla-widget-node-get-at point))
397 (tree (xetla-widget-get-ancestor widget level)))
398 (widget-put tree :args nil)
399 (widget-value-set tree (widget-value tree))
402 (defun xetla-widget-node-synchronize-mirror-to-remote ()
403 "Synchronizes the mirror for the archive at point to remote from local."
405 (let* ((name (xetla-widget-node-get-name))
406 (archive (xetla-name-archive name))
407 (type (xetla-archive-type archive))
411 (setq mirror (xetla-archive-name-mirror archive t))
413 (error "No mirror archive for `%s'" archive)))
415 (setq source (xetla-archive-name-source archive t))
417 (setq archive source)
418 (error "No source archive for `%s'" archive)))
419 (t (error "Cannot mirror to a source archive: `%s'" archive)))
420 (xetla-archive-mirror archive
421 (xetla-name-category name)
422 (xetla-name-branch name)
423 (xetla-name-version name)
426 (defun xetla-widget-node-synchronize-mirror-to-local ()
427 "Synchronizes the mirror for the archive at point to local from remote."
432 (defun xetla-widget-node-save-name-to-kill-ring ()
433 "Save the name under point to `kill-ring'."
435 (let ((name (xetla-name-construct (xetla-widget-node-get-name))))
436 (when (equal "" name)
437 (error "No widget under the point"))
439 (message "Name: %s" name)))
441 (defun xetla-widget-node-add-bookmark ()
442 "Add a name associated with a widget at point to xetla's bookmarks."
444 (let* ((target (xetla-widget-node-get-name))
445 (target-fq (xetla-name-construct target))
446 (bookmark (read-from-minibuffer (format "Name of Bookmark for `%s': "
448 (xetla-bookmarks-add bookmark target)
449 (when (y-or-n-p "View bookmarks? ")
451 (message "bookmark %s(=> %s) added." bookmark target-fq)))
453 (defun xetla-widget-node-toggle-subtree (&optional point force)
454 "Toggle between closing and opening the node at POINT.
455 You can specify a symbol, `open' or `close' to FORCE to force
456 the node to open or to close."
458 (xetla-widget-node-toggle-subtree-internal
459 (xetla-widget-node-get-at point) force))
461 (defun xetla-widget-node-toggle-subtree-recursive (&optional point
463 "Same as `xetla-widget-node-toggle-subtree'.
464 The difference is that when the node is expanded, expands it
465 recursively, which means all the children will also be expanded. (this
467 Meaning of POINT and FORCE are the same as that of
468 `xetla-widget-node-toggle-subtree'."
470 (xetla-widget-node-toggle-subtree-internal
471 (xetla-widget-node-get-at point) force t))
473 (defun xetla-widget-node-toggle-subtree-internal (widget force
476 "Toggle between closing and opening the WIDGET.
477 You can specify a symbol, `open' or `close' to FORCE to force
478 the node to open or to close. If RECURSIVE is non-nil, the opening
479 or closing are applied recursively."
480 (let* ((open-subtree (widget-get widget :open-subtree))
481 (close-subtree (widget-get widget :close-subtree)))
483 ((or (eq force 'open)
485 (not (widget-get (widget-get widget :parent) :open))))
486 (when open-subtree (funcall open-subtree widget))
488 (xetla-widget-node-toggle-subtree-recursion widget 'open)))
489 ((or (eq force 'close)
491 (widget-get (widget-get widget :parent) :open)))
493 (widget-get (widget-get widget :parent) :open))
494 (when open-subtree (funcall open-subtree widget))
495 (xetla-widget-node-toggle-subtree-recursion widget 'close))
496 (when close-subtree (funcall close-subtree widget))))))
498 (defun xetla-widget-node-toggle-subtree-recursion (widget force)
499 "A helper function for 'xetla-widget-node-toggle-subtree-internal'.
500 Apply all sub node of WIDGET opening or closing which is specified
502 (let ((args (widget-get (widget-get widget :parent) :args)))
504 (let* ((t-widget (widget-get arg :node))
505 ;; surprisingly, t-widget doesn't have all the
506 ;; necessary fields. Look for the _real_ widget.
508 (xetla-browse-find-real-widget t-widget)))
509 (unless (eq (widget-type t-widget)
510 (widget-type full-widget))
511 (error "Incorrect widget. Please contact the developers"))
513 (xetla-widget-node-toggle-subtree-internal
514 full-widget force t))))))
516 (defun xetla-tree-widget-node-toggle-subtree-for-tree-widget-v1 (widget)
517 "Toggle tree node function used in `xetla-browse' with tree-widget ver.1.0.5.
518 The code is the almost same as in tree-widget-toggle-folding tree-widget version
521 Original documents say:
522 \"Toggle a `tree-widget' folding.
523 WIDGET is a `tree-widget-node-handle-widget' and its parent the
524 `tree-widget' itself. IGNORE other arguments.\""
525 (let* ((parent (widget-get widget :parent))
527 ; (open (widget-value widget))
528 ;; Here `parent' is used instead of `widget'.
529 (open (widget-value parent)))
531 (tree-widget-children-value-save parent))
532 (widget-put parent :open (not open))
533 (widget-value-set parent (not open))
534 (run-hook-with-args 'tree-widget-after-toggle-functions parent)))
536 (xetla-make-bymouse-function xetla-widget-node-toggle-subtree)
538 ;; --------------------------------------
540 ;; --------------------------------------
541 (define-widget 'xetla-widget-my-id 'push-button
542 "Widget to control xetla's my-id."
543 :format "%{My-id:%} %[%t%]"
545 :button-face 'widget-field-face
546 :notify 'xetla-widget-my-id-set
547 :help-echo "Click here to change my-id")
549 (defun xetla-widget-my-id-set (self changed event)
550 "Set my-id to my-id-widget.
551 SELF is not used. CHANGED is just passed to `widget-value-set'.
552 EVENT is also not used."
553 (let ((new-id (xetla-my-id t)))
554 (widget-value-set changed new-id)
557 ;; --------------------------------------
559 ;; --------------------------------------
560 (define-widget 'xetla-widget-root-node 'xetla-widget-node
561 "Root node widget for trees in xetla-browse buffer."
562 :value-create 'xetla-widget-root-node-value-create
566 (defun xetla-widget-root-node-value-create (widget)
567 "Create a value for root node represented by WIDGET."
568 (insert (xetla-widget-node-install-ui-element
570 (widget-get widget :tag))))
572 (defvar xetla-widget-archives-root-node-map
573 (let ((map (copy-keymap xetla-widget-node-map)))
574 (define-key map xetla-keyvec-refresh
575 'xetla-widget-node-refresh)
576 (define-key map (xetla-prefix-add ?a)
577 'xetla-widget-archives-root-node-make-archive)
578 (define-key map (xetla-prefix-add ?r)
579 'xetla-widget-archives-root-node-register-archive)
581 "Keymap used on the archives root node.")
583 (easy-menu-define xetla-widget-archives-root-node-menu nil
584 "Menu used on the root archives item in `xetla-browse-mode' buffer."
586 ["Update Archives List"
587 xetla-widget-node-refresh t]
588 ["Make New Archive..."
589 xetla-widget-archives-root-node-make-archive t]
591 xetla-widget-archives-root-node-register-archive t]))
593 (defun xetla-widget-archives-root-node-make-archive ()
594 "Call `xetla-make-archive-internal' interactively then update the tree of `xetla-browse'."
596 (call-interactively 'xetla-make-archive-internal)
597 (xetla-widget-node-refresh 1))
599 (defun xetla-widget-archives-root-node-goto (name)
600 "Move the point to beginning of line in where the NAME is.
601 This may be useful to search an archive named NAME."
602 (goto-char (point-min))
603 (search-forward name)
606 (defun xetla-widget-archives-root-node-register-archive ()
607 "Call `xetla-register-archive-internal' interactively ; then update the tree of `xetla-browse'."
609 (let* ((result (call-interactively 'xetla-register-archive-internal))
610 (archive-registered (nth 0 result))
611 (archive (nth 1 result))
612 (xetla-response (nth 3 result)))
613 (when archive-registered
614 (xetla-widget-node-refresh 1)
615 (message xetla-response)
616 (xetla-widget-archives-root-node-goto
617 (if (string-match ".+: \\(.+\\)" xetla-response)
618 (match-string 1 xetla-response)
620 (xetla-flash-line))))
623 ;; --------------------------------------
625 ;; --------------------------------------
626 (defface xetla-location
627 '((((class color) (background dark)) (:foreground "gray"))
628 (((class color) (background light)) (:foreground "gray"))
630 "Face to highlight xetla's archive location."
633 (make-face 'xetla-location-ftp
634 "Face to highlight xetla's archive ftp location.")
635 (set-face-parent 'xetla-location-ftp 'xetla-location)
637 (make-face 'xetla-location-sftp
638 "Face to highlight xetla's archive sftp location.")
639 (set-face-parent 'xetla-location-sftp 'xetla-location)
640 (set-face-foreground 'xetla-location-sftp "gray50")
642 (make-face 'xetla-location-http
643 "Face to highlight xetla's archive sftp location.")
644 (set-face-parent 'xetla-location-http 'xetla-location)
645 (set-face-foreground 'xetla-location-http "gray60")
647 (make-face 'xetla-location-local
648 "Face to highlight xetla's local archive.")
649 (set-face-parent 'xetla-location-local 'xetla-location)
650 (set-face-foreground 'xetla-location-local "gray30")
652 (defvar xetla-widget-archive-node-map
653 (let ((map (copy-keymap xetla-widget-node-map)))
654 (define-key map xetla-keyvec-refresh
655 'xetla-widget-archive-node-refresh)
656 (define-key map "*" 'xetla-widget-archive-node-select-default)
657 (define-key map xetla-keyvec-remove
658 'xetla-widget-archive-node-unregister-archive)
659 (define-key map (xetla-prefix-add ?c)
660 'xetla-widget-archive-node-make-category)
661 (define-key map (xetla-prefix-apply-from-here xetla-key-reflect)
662 'xetla-widget-archive-node-start-project)
663 (define-key map xetla-keyvec-reflect
664 'xetla-widget-node-synchronize-mirror-to-remote)
665 (define-key map xetla-keyvec-get
666 'xetla-widget-node-synchronize-mirror-to-local)
667 (define-key map (xetla-prefix-add xetla-key-reflect)
668 'xetla-widget-archive-node-make-mirror-at-remote)
669 (define-key map (xetla-prefix-add xetla-key-get)
670 'xetla-widget-archive-node-make-mirror-at-local)
672 "Keymap used on xetla-widget-archive-node.")
674 (easy-menu-define xetla-widget-archive-node-menu nil
675 "Menu used on a archive item in `xetla-browse-mode' buffer."
677 ["Update Categories List" xetla-widget-archive-node-refresh t]
678 ["Set Default Archive" xetla-widget-archive-node-select-default t]
679 ["Remove Archive Registration" xetla-widget-archive-node-unregister-archive t]
680 ["Make New Category..." xetla-widget-archive-node-make-category t]
681 ["Start Project from Here" xetla-widget-archive-node-start-project t]
682 ["Add a Bookmark" xetla-widget-node-add-bookmark t]
684 ["Synchronize Mirror to Remote From Local"
685 xetla-widget-node-synchronize-mirror-to-remote
686 (let* ((archive (xetla-name-archive (xetla-widget-node-get-name)))
687 (type (xetla-archive-type archive)))
688 (or (and (eq type 'normal)
689 (xetla-archive-name-mirror archive t))
690 (and (eq type 'mirror)
691 (xetla-archive-name-source archive t))))]
692 ["Create a Mirror at Remote"
693 xetla-widget-archive-node-make-mirror-at-remote
694 (eq (xetla-archive-type (xetla-name-archive (xetla-widget-node-get-name)))
697 ["Synchronize Mirror to Local[TODO]"
699 xetla-widget-node-synchronize-mirror-to-local nil]
700 ["Create a Mirror at Local" xetla-widget-archive-node-make-mirror-at-local
701 (eq (xetla-archive-type (xetla-name-archive (xetla-widget-node-get-name)))
704 ["Convert to SOURCE archive" xetla-widget-archive-node-convert-to-source
705 (eq (xetla-archive-type (xetla-name-archive (xetla-widget-node-get-name)))
707 ["Save Name to Kill Ring" xetla-widget-node-save-name-to-kill-ring t]))
709 (defconst xetla-widget-archive-node-tag "a")
710 (defconst xetla-widget-archive-node-default-tag "A")
712 (define-widget 'xetla-widget-archive-node 'xetla-widget-node
713 "Archive node in xetla-browse."
714 :tag xetla-widget-archive-node-tag
715 :value-create 'xetla-widget-archive-node-value-create
717 :face 'xetla-archive-name
718 :keymap 'xetla-widget-archive-node-map
719 :menu xetla-widget-archive-node-menu
721 :archive-location nil
722 :archive-defaultp nil)
724 (defvar xetla-widget-archive-node-list nil)
725 (defun xetla-browse-expand-archives (root)
726 "Expand ROOT widget."
727 (or (and (not current-prefix-arg) (widget-get root :args))
728 (let ((default-archive (xetla-my-default-archive)))
729 (setq xetla-widget-archive-node-list nil)
734 :open ,(xetla-browse-open-list-member (car archive))
736 :dynargs xetla-browse-expand-categories
737 :node (xetla-widget-archive-node
738 :tag ,(if (equal default-archive (car archive))
739 xetla-widget-archive-node-default-tag
740 xetla-widget-archive-node-tag)
741 :archive ,(car archive)
742 :archive-location ,(cadr archive)
743 :archive-defaultp ,(equal
747 (widget-put (widget-get res :node) :parent res)
749 (let* ((l xetla-archive-tree))
750 (when (or (null l) current-prefix-arg)
751 (xetla-archive-tree-build-archives nil t))
752 xetla-archive-tree)))))
754 (defun xetla-widget-archive-node-value-create (widget)
755 "Create values for WIDGET."
756 (push widget xetla-widget-archive-node-list)
757 (insert (let* ((archive (widget-get widget :archive))
758 (location (widget-get widget :archive-location))
759 (defaultp (widget-get widget :archive-defaultp))
760 (marks (widget-get widget :marks))
762 (case (xetla-archive-type archive)
763 (mirror (widget-put widget :face 'xetla-mirror-archive-name))
764 (source (widget-put widget :face 'xetla-source-archive-name)))
766 ;; It seems that XEmacs's format hides text properties.
769 (xetla-widget-node-install-ui-element
770 widget archive (when defaultp
773 (xetla-widget-archive-put-face-on-location
777 (defun xetla-widget-archive-put-face-on-location (location)
778 "Set face to LOCATION based on the location type(ftp, sftp, http or local)."
779 (let ((face (case (xetla-location-type location)
780 (ftp 'xetla-location-ftp)
781 (sftp 'xetla-location-sftp)
782 (http 'xetla-location-http)
783 (local 'xetla-location-local)))
784 (location (copy-sequence location)))
785 (put-text-property 0 (length location)
789 (defun xetla-widget-archive-node-refresh ()
790 "Refresh an archive node under the point."
792 (xetla-widget-node-refresh 1 nil
794 (xetla-widget-node-get-name))))
796 (defun xetla-widget-archive-node-select-default ()
797 "Mark a widget associated with the default archive.
798 Unmark widgets not associated with the default archive.
799 `:archive-defaultp' keyword is used to mark."
803 (when (equal xetla-widget-archive-node-default-tag
804 (widget-get widget :tag))
805 (widget-put widget :tag xetla-widget-archive-node-tag)
806 (widget-put widget :archive-defaultp nil)
807 (widget-value-set widget (widget-value widget))))
808 xetla-widget-archive-node-list)
809 (let* ((widget (xetla-widget-node-get-at))
810 (archive (xetla-name-archive (xetla-widget-node-get-name) )))
811 (xetla-my-default-archive archive)
812 (widget-put widget :tag xetla-widget-archive-node-default-tag)
813 (widget-put widget :archive-defaultp t)
814 (widget-value-set widget (widget-value widget))))
816 (defun xetla-widget-archive-node-unregister-archive ()
817 "Delete the registration of the archive under the point."
819 (let ((archive (xetla-name-archive (xetla-widget-node-get-name))))
821 (progn (xetla-unregister-archive archive t)
822 (xetla-widget-node-refresh 2))
823 (error "No archive under the point"))))
825 (defun xetla-widget-archive-node-make-category ()
826 "Make new category in the archive under the point."
828 (let* ((name (xetla-widget-node-get-name))
829 (archive (xetla-name-archive name))
830 (l (xetla-name-read "New Category: "
833 (xetla-make-category (xetla-name-archive l) (xetla-name-category l))
834 (xetla-widget-node-refresh 1 nil (xetla-name-archive l))
836 (xetla-name-archive l)
837 (xetla-name-category l))
840 (defun xetla-widget-archive-node-convert-to-source ()
841 "Convert the archive under the point to a source archive."
843 (let* ((widget (xetla-widget-node-get-at))
844 (archive (widget-get widget :archive))
845 (location (widget-get widget :archive-location))
846 (result (xetla-archive-convert-to-source-archive archive location)))
847 (let ((archive-registered (nth 0 result))
848 (archive (nth 1 result))
849 (xetla-response (nth 3 result)))
850 (when archive-registered
851 (xetla-widget-node-refresh 2)
852 (message xetla-response)
853 (xetla-widget-archives-root-node-goto
854 (if (string-match ".+: \\(.+\\)" xetla-response)
855 (match-string 1 xetla-response)
857 (xetla-flash-line)))))
859 (defun xetla-widget-archive-node-start-project ()
860 "Start new project in the archive unde the point."
862 (let* ((archive (xetla-name-archive (xetla-widget-node-get-name)))
863 (buffer (current-buffer))
865 (result (xetla-start-project archive 'synchronously))
866 (category (xetla-name-category (car result)))
867 (branch (xetla-name-branch (car result)))
868 (version (xetla-name-version (car result)))
870 (with-current-buffer buffer
871 (xetla-widget-node-refresh 1 p archive)
873 archive category branch version))))
875 (defun xetla-widget-archive-node-make-mirror-at-remote ()
876 "Create a mirror for the local archive under the point at somewhere remote."
878 (let ((archive (xetla-name-archive (xetla-widget-node-get-name))))
880 (error "No archive under the point"))
881 (xetla-mirror-archive archive nil nil nil nil)
882 (xetla-widget-node-refresh 2)
883 (xetla-widget-archives-root-node-goto (format "%s-MIRROR" archive))
886 (defun xetla-widget-archive-node-make-mirror-at-local ()
887 "Create a mirror for the remote archive under the point to local."
889 (let ((archive (xetla-name-archive (xetla-widget-node-get-name))))
891 (error "No archive under the point"))
892 (xetla-mirror-from-archive archive nil)
893 (xetla-widget-node-refresh 2)
894 (string-match "\\(.*\\)-SOURCE$" archive)
895 (xetla-widget-archives-root-node-goto
896 ;; Adding a space not to match SOURCE archive.
897 (concat (match-string 1 archive) " "))
900 ;; --------------------------------------
902 ;; --------------------------------------
903 (defvar xetla-widget-category-node-map
904 (let ((map (copy-keymap xetla-widget-node-map)))
905 (define-key map xetla-keyvec-refresh
906 'xetla-widget-category-node-refresh)
907 (define-key map (xetla-prefix-add ?b)
908 'xetla-widget-category-node-make-branch)
910 "Keymap used on xetla-widget-category-node.")
912 (easy-menu-define xetla-widget-category-node-menu nil
913 "Menu used on a archive item in `xetla-browse-mode' buffer."
915 ["Update Branches List" xetla-widget-category-node-refresh t]
916 ["Remove Category[NOT IMPLEMENTED]" nil t]
917 ["Make New Branch..." xetla-widget-category-node-make-branch t]
918 ["Add a Bookmark" xetla-widget-node-add-bookmark t]
919 ["Synchronize Mirror to Remote"
920 xetla-widget-node-synchronize-mirror-to-remote t]
921 ["Save Name to Kill Ring" xetla-widget-node-save-name-to-kill-ring t]))
923 (define-widget 'xetla-widget-category-node 'xetla-widget-node
924 "Category node in xetla-browse."
926 :value-create 'xetla-widget-category-node-value-create
927 :xetla-type 'category
928 :face 'xetla-category-name
929 :keymap 'xetla-widget-category-node-map
930 :menu xetla-widget-category-node-menu
934 (defun xetla-browse-expand-categories (archive)
935 "Expand ARCHIVE widget."
936 (or (and (not current-prefix-arg) (widget-get archive :args))
937 (let ((archive-name (widget-get
938 (widget-get archive :node)
942 (let ((res `(tree-widget
943 :open ,(xetla-browse-open-list-member archive-name
946 :dynargs xetla-browse-expand-branches
947 :node (xetla-widget-category-node
948 :archive ,archive-name
949 :category ,(car category)))))
950 (widget-put (widget-get res :node) :parent res)
952 (let* ((l (cddr (xetla-archive-tree-get-archive
954 (when (or (null l) current-prefix-arg)
955 (xetla-archive-tree-build-categories archive-name nil t))
956 (cddr (xetla-archive-tree-get-archive archive-name)))))))
958 (defun xetla-widget-category-node-value-create (widget)
959 "Create values for category WIDGET."
960 (xetla-widget-node-value-create widget :category))
962 (defun xetla-widget-category-node-refresh ()
963 "Refresh a category widget at the point."
965 (let ((name (xetla-widget-node-get-name)))
966 (xetla-widget-node-refresh 1 nil
967 (xetla-name-archive name)
968 (xetla-name-category name))))
970 (defun xetla-widget-category-node-make-branch ()
971 "Make new branch in the category under the point."
973 (let* ((name (xetla-widget-node-get-name))
974 (archive (xetla-name-archive name))
975 (category (xetla-name-category name))
976 (l (xetla-name-read "New Branch: "
980 (xetla-make-branch (xetla-name-archive l)
981 (xetla-name-category l)
982 (xetla-name-branch l))
983 (xetla-widget-node-refresh 1 nil
984 (xetla-name-archive l)
985 (xetla-name-category l))
987 (xetla-name-archive l)
988 (xetla-name-category l)
989 (xetla-name-branch l))))
991 ;; --------------------------------------
993 ;; --------------------------------------
994 (defvar xetla-widget-branch-node-map
995 (let ((map (copy-keymap xetla-widget-node-map)))
996 (define-key map xetla-keyvec-refresh
997 'xetla-widget-branch-node-refresh)
998 (define-key map (xetla-prefix-add ?v)
999 'xetla-widget-branch-node-make-version)
1000 (define-key map xetla-keyvec-get
1001 'xetla-widget-branch-node-get-branch)
1003 "Keymap used on xetla-widget-branch-node.")
1005 (easy-menu-define xetla-widget-branch-node-menu nil
1006 "Menu used on a archive item in `xetla-browse-mode' buffer."
1008 ["Update Version List" xetla-widget-branch-node-refresh t]
1009 ["Remove Branch Registration[NOT IMPLEMENTED]" nil t]
1010 ["Make New Version..." xetla-widget-branch-node-make-version t]
1011 ["Get..." xetla-widget-branch-node-get-branch t]
1012 ["Add a Bookmark" xetla-widget-node-add-bookmark t]
1013 ["Synchronize Mirror to Remote"
1014 xetla-widget-node-synchronize-mirror-to-remote t]
1015 ["Save Name to Kill Ring" xetla-widget-node-save-name-to-kill-ring t]))
1017 (define-widget 'xetla-widget-branch-node 'xetla-widget-node
1018 "Branch node in xetla-browse."
1020 :value-create 'xetla-widget-branch-node-value-create
1022 :face 'xetla-branch-name
1023 :keymap 'xetla-widget-branch-node-map
1024 :menu xetla-widget-branch-node-menu
1029 (defun xetla-browse-expand-branches (category)
1030 "Expand CATEGORY widget."
1031 (or (and (not current-prefix-arg) (widget-get category :args))
1032 (let* ((parent-node (widget-get category :node))
1033 (archive-name (widget-get parent-node :archive))
1034 (category-name (widget-get parent-node :category)))
1039 :open ,(xetla-browse-open-list-member archive-name
1043 :leaf-control xetla-widget-version-control
1044 :dynargs xetla-browse-expand-versions
1045 :node (xetla-widget-branch-node
1046 :archive ,archive-name
1047 :category ,category-name
1048 :branch ,(car branch)))))
1049 (widget-put (widget-get res :node) :parent res)
1051 (let* ((l (cdr (xetla-archive-tree-get-category
1054 (when (or (null l) current-prefix-arg)
1055 (xetla-archive-tree-build-branches archive-name
1058 (cdr (xetla-archive-tree-get-category archive-name
1059 category-name)))))))
1061 (defun xetla-widget-branch-node-value-create (widget)
1062 "Create values for branch WIDGET."
1063 (xetla-widget-node-value-create widget :branch))
1065 (defun xetla-widget-branch-node-refresh ()
1066 "Refresh a branch widget at the point."
1068 (let ((name (xetla-widget-node-get-name)))
1069 (xetla-widget-node-refresh 1 nil
1070 (xetla-name-archive name)
1071 (xetla-name-category name)
1072 (xetla-name-branch name))))
1074 (defun xetla-widget-branch-node-make-version ()
1075 "Make new version in the branch under the point."
1077 (let* ((name (xetla-widget-node-get-name))
1078 (archive (xetla-name-archive name))
1079 (category (xetla-name-category name))
1080 (branch (xetla-name-category name))
1081 (l (xetla-name-read "New Version: "
1086 (xetla-make-version (xetla-name-archive l)
1087 (xetla-name-category l)
1088 (xetla-name-branch l)
1089 (xetla-name-version l))
1090 (xetla-widget-node-refresh 1 nil
1091 (xetla-name-archive l)
1092 (xetla-name-category l)
1093 (xetla-name-branch l))
1094 (xetla-browse-open t
1095 (xetla-name-archive l)
1096 (xetla-name-category l)
1097 (xetla-name-branch l)
1098 (xetla-name-version l))))
1100 (defun xetla-widget-branch-node-get-branch ()
1101 "Run `tla get' against the branch at point."
1103 (let* ((name (xetla-widget-node-get-name))
1104 (archive (xetla-name-archive name))
1105 (category (xetla-name-category name))
1106 (branch (xetla-name-branch name))
1107 (directory (expand-file-name
1108 (read-directory-name
1109 (format "Restore \"%s\" to: "
1112 (error "No branch under the point"))
1113 (xetla-name-construct
1114 archive category branch)))))))
1116 (xetla-get directory
1121 (error "No branch under the point"))))
1124 ;; --------------------------------------
1126 ;; --------------------------------------
1127 (defvar xetla-widget-version-node-map
1128 (let ((map (copy-keymap xetla-widget-node-map)))
1129 (define-key map xetla-keyvec-refresh
1130 'xetla-widget-version-node-show-revisions)
1131 (define-key map xetla-keyvec-get
1132 'xetla-widget-version-node-get-version)
1133 (define-key map xetla-keyvec-tag 'xetla-widget-version-node-tag)
1135 "Keymap used on xetla-widget-version-node.")
1137 (easy-menu-define xetla-widget-version-node-menu nil
1138 "Menu used on a archive item in `xetla-browse-mode' buffer."
1140 ["Show Revisions" xetla-widget-version-node-show-revisions t]
1141 ["Remove Version Registration[NOT IMPLEMENTED]" nil t]
1142 ["Get..." xetla-widget-version-node-get-version t]
1143 ["Add a Bookmark" xetla-widget-node-add-bookmark t]
1144 ["Synchronize Mirror to Remote"
1145 xetla-widget-node-synchronize-mirror-to-remote t]
1146 ["Put Tag..." xetla-widget-version-node-tag t]
1147 ["Save Name to Kill Ring" xetla-widget-node-save-name-to-kill-ring t]))
1149 (define-widget 'xetla-widget-version-node 'xetla-widget-node
1150 "Version node in xetla-browse."
1152 :value-create 'xetla-widget-version-node-value-create
1153 :xetla-type 'version
1154 :face 'xetla-version-name
1155 :keymap 'xetla-widget-version-node-map
1156 :menu xetla-widget-version-node-menu
1161 :open-subtree 'xetla-widget-version-node-open-subtree
1162 :close-subtree 'xetla-widget-version-node-open-subtree)
1165 (define-widget 'xetla-widget-version-control 'tree-widget-empty-control
1166 "Control widget that represents a leaf version node."
1169 :action 'xetla-widget-version-control-show-revisions)
1171 (defun xetla-widget-version-control-show-revisions (widget &optional event)
1172 "Show revisions in a version associated with WIDGET.
1173 The version is under the point or place where click EVENT is created."
1175 (mouse-set-point event))
1176 (let ((pos (next-single-property-change (point)
1181 (xetla-widget-version-node-show-revisions pos))))
1183 (defun xetla-browse-expand-versions (branch)
1184 "Expand BRANCH widget."
1185 (or (and (not current-prefix-arg) (widget-get branch :args))
1186 (let* ((parent-node (widget-get branch :node))
1187 (archive-name (widget-get parent-node :archive))
1188 (category-name (widget-get parent-node :category))
1189 (branch-name (widget-get parent-node :branch)))
1190 (mapcar (lambda (version)
1191 `(xetla-widget-version-node
1192 :archive ,archive-name
1193 :category ,category-name
1194 :branch ,branch-name
1195 :version ,(car version)))
1196 (let* ((l (cdr (xetla-archive-tree-get-branch archive-name
1199 (when (or (null l) current-prefix-arg)
1200 (xetla-archive-tree-build-versions archive-name
1204 (cdr (xetla-archive-tree-get-branch archive-name
1208 (defun xetla-widget-version-node-value-create (widget)
1209 "Create values for version WIDGET."
1210 (xetla-widget-node-value-create widget :version))
1212 (defun xetla-widget-version-node-show-revisions (&optional point)
1213 "Show revisions in the version under the POINT.
1214 If POINT is nil, use the point under `point'."
1216 (let ((name (xetla-widget-node-get-name (or point (point)))))
1217 (xetla-revisions (xetla-name-archive name)
1218 (xetla-name-category name)
1219 (xetla-name-branch name)
1220 (xetla-name-version name)
1223 (defun xetla-widget-version-node-get-version ()
1224 "Run \"tla get\" against the version at point."
1226 (let* ((name (xetla-widget-node-get-name))
1227 (archive (xetla-name-archive name))
1228 (category (xetla-name-category name))
1229 (branch (xetla-name-branch name))
1230 (version (xetla-name-version name))
1231 (directory (expand-file-name
1232 (read-directory-name
1233 (format "Restore \"%s\" to: "
1236 (error "No version under the point"))
1237 (xetla-name-construct
1238 archive category branch version)))))))
1240 (xetla-get directory
1246 (error "No version under the point"))))
1248 (defun xetla-widget-version-node-tag ()
1249 "Run tla tag from the version under the point."
1251 (let* ((from (xetla-widget-node-get-name))
1252 (from-fq (xetla-name-construct from))
1253 (to (xetla-name-read (format "Tag from `%s' to: " from-fq)
1254 'prompt 'prompt 'prompt 'prompt))
1255 (to-fq (xetla-name-construct to)))
1257 (error "No version under the point"))
1259 (error "Wrong version tagged to is given"))
1261 (xetla-version-tag-internal from-fq to-fq 'synchronously))
1262 (xetla-widget-node-refresh 1 nil
1263 (xetla-name-archive to-fq)
1264 (xetla-name-category to-fq)
1265 (xetla-name-branch to-fq))
1266 (xetla-browse-open t
1267 (xetla-name-archive to-fq)
1268 (xetla-name-category to-fq)
1269 (xetla-name-branch to-fq)
1270 (xetla-name-version to-fq))))
1272 (defun xetla-widget-version-node-open-subtree (widget)
1273 "List revisions in the version associated with WIDGET."
1274 (xetla-revisions (widget-get widget :archive)
1275 (widget-get widget :category)
1276 (widget-get widget :branch)
1277 (widget-get widget :version)
1280 ;; --------------------------------------
1282 ;; --------------------------------------
1283 ;; TODO: Filtered by GROUP in bookmark
1285 (defun xetla-browse (&optional initial-open-list append)
1286 "Browse registered archives as trees within one buffer.
1287 You can specify the node should be opened by alist,
1288 INITIAL-OPEN-LIST. If APPEND is nil, the nodes not in
1289 INITIAL-OPEN-LIST are made closed. If non-nil, the nodes
1290 already opened are kept open."
1293 (switch-to-buffer (xetla-get-buffer-create
1294 xetla-browse-buffer-type))
1295 (make-local-variable 'xetla-browse-open-list)
1296 (setq truncate-lines t)
1299 (if (zerop (buffer-size))
1300 (progn (setq building t)
1301 (xetla-browse-set-initial-open-list initial-open-list t))
1305 (xetla-browse-set-initial-open-list initial-open-list nil))
1306 (if (y-or-n-p (format "Remove old %s? " (buffer-name)))
1307 (progn (setq building t)
1308 (xetla-browse-set-initial-open-list initial-open-list nil))
1310 (xetla-browse-set-initial-open-list initial-open-list t))))
1314 (xetla-browse-erase-buffer)
1315 (xetla-browse-build-buffer))
1318 (xetla-browse-open nil
1319 (xetla-name-archive elt)
1320 (xetla-name-category elt)
1321 (xetla-name-branch elt)
1322 (xetla-name-version elt)))
1323 xetla-browse-open-list)))
1324 (goto-char (point-min))
1325 (xetla-browse-mode))
1327 (defun xetla-browse-set-initial-open-list (list clearp)
1328 "Insert LIST to `xetla-browse-open-list'.
1329 If CLEARP is set, clear `xetla-browse-open-list' before insertion.
1330 This is a helper function for `xetla-browse'."
1332 (setq xetla-browse-open-list nil))
1335 (xetla-browse-open-list-add (xetla-name-archive elt)
1336 (xetla-name-category elt)
1337 (xetla-name-branch elt)
1338 (xetla-name-version elt)))
1340 (defun xetla-browse-erase-buffer ()
1341 "Erase *xetla-browse* buffer."
1342 (let ((inhibit-read-only t))
1344 ;; remove-extent is not portable enough.
1345 (mapc #'delete-extent
1346 (mapcar-extents #'identity
1347 nil nil (point-min) (point-max)
1348 'all-extents-closed-open)))
1350 (defun xetla-browse-build-buffer ()
1351 "Insert contents of *xetla-buffer*."
1353 (widget-create 'tree-widget
1355 :node '(item :format "%[%t%]\n"
1356 :tag "Personal Configuration")
1358 `(xetla-widget-my-id ,(xetla-my-id)))
1360 (widget-insert "\n")
1363 (add-hook 'tree-widget-after-toggle-functions
1364 'xetla-browse-open-tracker)
1365 (widget-create 'tree-widget
1367 :node `(xetla-widget-root-node
1368 :xetla-type archives-root
1370 :keymap xetla-widget-archives-root-node-map
1371 :menu ,xetla-widget-archives-root-node-menu)
1373 :dynargs 'xetla-browse-expand-archives)
1378 (defun xetla-browse-toggle-subtree-maybe ()
1379 "Run `xetla-browse-toggle-subtree'.
1380 Before running a widget is searched and move the point to
1381 the widget if it is found. If no widget is found,
1382 `widget-button-press'."
1384 (let ((p (next-single-property-change (point-at-bol)
1388 (if (and p (xetla-widget-node-get-type p))
1389 (xetla-widget-node-toggle-subtree p)
1390 (widget-button-press (point)))))
1392 (defun xetla-browse-dash ()
1393 "Move the point to the place where a widget is in the current line."
1395 (let ((p (next-single-property-change (point-at-bol)
1399 (when (and p (xetla-widget-node-get-type p))
1401 (xetla-flash-line))))
1403 (defvar xetla-browse-map
1404 (let ((map (copy-keymap widget-keymap)))
1405 (define-key map xetla-keyvec-help 'describe-mode)
1406 (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
1407 (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
1408 (define-key map (xetla-prefix-buffer xetla-key-show-bookmark) 'xetla-bookmarks)
1409 (define-key map [return] 'xetla-browse-toggle-subtree-maybe)
1410 (define-key map "\C-m" 'xetla-browse-toggle-subtree-maybe)
1411 (define-key map " " 'xetla-browse-dash)
1412 (define-key map xetla-keyvec-next 'next-line)
1413 (define-key map xetla-keyvec-previous 'previous-line)
1414 (define-key map xetla-keyvec-quit 'kill-this-buffer)
1415 (define-key map [?+] 'xetla-widget-node-toggle-subtree-recursive)
1417 "Keymap used in `xetla-browse-mode'.")
1419 (defun xetla-browse-mode ()
1420 "Mode for browsing xetla's archives.
1421 Don't use this function. Instead call `xetla-browse'."
1422 (setq major-mode 'xetla-browse-mode
1423 mode-name "xetla-browse")
1424 (use-local-map xetla-browse-map)
1425 (set-buffer-modified-p nil)
1426 (run-hooks 'xetla-browse-mode-hook))
1428 (provide 'xetla-browse)
1430 ;;; xetla-browse.el ends here