;;; xetla-defs.el --- UI XEtla's element definitions

;; Copyright (C) 2003-2004 by Stefan Reichoer (GPL)
;; Copyright (C) 2004 Steve Youngs (BSD)

;; Author:        Steve Youngs <steve@eicq.org>
;; Maintainer:    Steve Youngs <steve@eicq.org>
;; Created:       2004-11-25
;; Keywords:      arch archive tla

;; Based on xtla-defs.el by: Stefan Reichoer, <stefan@xsteve.at>

;; This file is part of XEtla.

;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions
;; are met:
;;
;; 1. Redistributions of source code must retain the above copyright
;;    notice, this list of conditions and the following disclaimer.
;;
;; 2. Redistributions in binary form must reproduce the above copyright
;;    notice, this list of conditions and the following disclaimer in the
;;    documentation and/or other materials provided with the distribution.
;;
;; 3. Neither the name of the author nor the names of any contributors
;;    may be used to endorse or promote products derived from this
;;    software without specific prior written permission.
;;
;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;; DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

;;; Commentary:

;; Contributions from:
;;    Matthieu Moy <Matthieu.Moy@imag.fr>
;;    Masatake YAMATO <jet@gyve.org>
;;    Milan Zamazal <pdm@zamazal.org>
;;    Martin Pool <mbp@sourcefrog.net>
;;    Robert Widhopf-Fenk <hack@robf.de>
;;    Mark Triggs <mst@dishevelled.net>

;; In order to keep UI consistency, especially about key binding,
;; we gather all UI definition in this separated file.
;;


;;; History:
;;

;;; Code:

(eval-when-compile
  (require 'cl))

(eval-and-compile
  (autoload 'ad-add-advice "advice")
  (require 'ediff)
  (require 'diff-mode)
  (require 'font-lock)
  (require 'add-log)
  (require 'ffap)
  (require 'easymenu))

;; Macros to generate correct code for different emacs variants
;; This doesn't really belong here, but then again it doesn't "fit"
;; anywhere else.
;;;###autoload
(defmacro xetla-do-in-gnu-emacs (&rest body)
  "Execute BODY if in GNU/Emacs."
  (unless running-xemacs `(progn ,@body)))
(put 'xetla-do-in-gnu-emacs 'lisp-indent-hook 'defun)

;;;###autoload
(defmacro xetla-do-in-xemacs (&rest body)
  "Execute BODY if in XEmacs."
  (when running-xemacs `(progn ,@body)))
(put 'xetla-do-in-xemacs 'lisp-indent-hook 'defun)

(defmacro xetla-funcall-if-exists (function &rest args)
  "Call FUNCTION with ARGS as parameters if it exists."
  (if (fboundp function)
      `(funcall ',function ,@args)))

(defun xetla-clone-process (process &optional newname)
  "Create a twin copy of PROCESS.
If NEWNAME is nil, it defaults to PROCESS' name;
NEWNAME is modified by adding or incrementing <N> at the end as necessary.
If PROCESS is associated with a buffer, the new process will be associated
  with the current buffer instead.
Returns nil if PROCESS has already terminated."
  (setq newname (or newname (process-name process)))
  (if (string-match "<[0-9]+>\\'" newname)
      (setq newname (substring newname 0 (match-beginning 0))))
  (when (memq (process-status process) '(run stop open))
    (let* ((process-connection-type (process-tty-name process))
	   (old-kwoq (process-kill-without-query process nil))
	   (new-process
	    (if (memq (process-status process) '(open))
		(apply 'open-network-stream newname
		       (if (process-buffer process) (current-buffer)))
	      (apply 'start-process newname
		     (if (process-buffer process) (current-buffer))
		     (process-command process)))))
      (process-kill-without-query new-process old-kwoq)
      (process-kill-without-query process old-kwoq)
      (set-process-filter new-process (process-filter process))
      (set-process-sentinel new-process (process-sentinel process))
      new-process)))

(defun-when-void clone-buffer (&optional newname display-flag)
  "Create a twin copy of the current buffer.
If NEWNAME is nil, it defaults to the current buffer's name;
NEWNAME is modified by adding or incrementing <N> at the end as necessary.

If DISPLAY-FLAG is non-nil, the new buffer is shown with `pop-to-buffer'.
This runs the normal hook `clone-buffer-hook' in the new buffer
after it has been set up properly in other respects."
  (interactive (list (if current-prefix-arg (read-string "Name: "))
		     t))
  (if buffer-file-name
      (error "Cannot clone a file-visiting buffer"))
  (if (get major-mode 'no-clone)
      (error "Cannot clone a buffer in %s mode" mode-name))
  (setq newname (or newname (buffer-name)))
  (if (string-match "<[0-9]+>\\'" newname)
      (setq newname (substring newname 0 (match-beginning 0))))
  (let ((buf (current-buffer))
	(ptmin (point-min))
	(ptmax (point-max))
	(pt (point))
	(mk (mark t))
	(modified (buffer-modified-p))
	(mode major-mode)
	(lvars (buffer-local-variables))
	(process (get-buffer-process (current-buffer)))
	(new (generate-new-buffer (or newname (buffer-name)))))
    (save-restriction
      (widen)
      (with-current-buffer new
	(insert-buffer-substring buf)))
    (with-current-buffer new
      (narrow-to-region ptmin ptmax)
      (goto-char pt)
      (if mk (set-mark mk))
      (set-buffer-modified-p modified)

      ;; Clone the old buffer's process, if any.
      (when process (xetla-clone-process process))

      ;; Now set up the major mode.
      (funcall mode)

      ;; Set up other local variables.
      (mapcar (lambda (v)
		(condition-case ()	;in case var is read-only
		    (if (symbolp v)
			(makunbound v)
		      (set (make-local-variable (car v)) (cdr v)))
		  (error nil)))
	      lvars)

        ;; Run any hooks (typically set up by the major mode
        ;; for cloning to work properly).
        (run-hooks 'clone-buffer-hook))
      (if display-flag (pop-to-buffer new))
      new))


;; --------------------------------------
;; Key bindings
;; --------------------------------------
;;
;; Conventions
;;
;; - Meta Rules:
;; 0. If you feel a binding odd more than 3 times, report it to xetla dev mailing
;;    list. Especially about some danger functions like undo, merge; and functions
;;    taking longer time to be executed.
;;
;; 1. Our key binding should not surprise "general users" even if the
;;    binding is convenience. Instead, provide hooks for customization.
;;    We know it is difficult to define "general users".
;;
;; 2. Write the result of discussion here.
;;
;; 3. See http://mail.gnu.org/archive/html/emacs-devel/2004-03/msg00608.html
;;
;;
;; - Generic Rules:
;;
;; 1. xetla-inventory should have similar key bindings to pcl-cvs.
;;    If a pcl-cvs's binding is too odd, talk it in xetla dev mailing list.
;;
;; 2. Define common prefix for command groups like '>'.
;;    So a key binding for a grouped command has following structure:
;;
;;    ?{prefix} ?{suffix}
;;
;;    e.g. `get something commands' should have `>' as prefix.
;;
;;    About suffix part, ? should show the help for the groups.
;;
;;    e.g. `help for `get something commands'' is >?.
;;
;;    BTW, The prefix ? is for help related command.
;;    So `? >' can stand for "show the help for get-something related
;;    command". In other word, prefix and suffix is swappable if
;;    prefix or suffix is `?'.
;;
;; 3. Upper case for commands taking longer time to be executed.
;; 4. Lower case for commands taking shorter time to be executed.
;; 5. dired's binding is also helpful.
;;
;;
;; - Concrete Rules:
;;

;; t  ?    list all toggles
;; c       xetla-edit-log
;; RET     Open the thing at point
;;

;;
;; Definitions for key concrete rules
;;

;; common keys
(defvar xetla-key-help        ??)        ; help
(defvar xetla-key-mark-prefix ?*)   ; other mark related command prefix
(defvar xetla-key-apply-from-here ?.)    ; apply something from here
(defvar xetla-key-add-bookmark    ?b)    ; add this to bookmark
(defvar xetla-key-get      ?>)           ; prefix for getting something
(defvar xetla-key-reflect  ?<)           ; mirror, apply, install...
(defvar xetla-key-parent   ?^)       ; visit uppper XX. e.g. directory
(defvar xetla-key-apply-from-head ?@)    ; Do something head revision
(defvar xetla-key-diff     ?=)           ; one shot

(defvar xetla-key-add      ?a)           ; prefix for adding something
(defvar xetla-key-show-bookmark ?b)      ; show bookmark
(defvar xetla-key-diff-prefix ?d)
(defvar xetla-key-file-diff ?d)
(defvar xetla-key-tree-lint ?l)
(defvar xetla-key-logs      ?L)
(defvar xetla-key-ediff     ?e)
(defvar xetla-key-log-entry ?a)
(defvar xetla-key-refresh   ?g)           ; refresh buffer
(defvar xetla-key-inventory ?i)           ; inventory
(defvar xetla-key-mark      ?m)           ; mark
(defvar xetla-key-next      ?n)           ; next item
(defvar xetla-key-previous  ?p)           ; previous item
(defvar xetla-key-quit      ?q)           ; quit
(defvar xetla-key-remove    ?r)           ; prefix for remove something
(defvar xetla-key-move      ?R)           ; prefix for move/rename something
(defvar xetla-key-toggle    ?t)           ; prefix for toggle
(defvar xetla-key-unmark    ?u)           ; unmark
(defvar xetla-key-popup-menu ?\C-j)
(defvar xetla-key-kill-ring-prefix ?w)
(defvar xetla-key-commit    ?c)          ; actually edit-log, but
                                        ; that's what you do when you
                                        ; want to commit.
(defvar xetla-key-update     ?u)           ; to run tla update
(defvar xetla-key-replay     ?r)           ; to run tla replay
(defvar xetla-key-star-merge ?s)           ; to run tla star-merge
(defvar xetla-key-missing    ?m)           ; to run tla missing

(defvar xetla-key-buffer-prefix ?B)   ; perfix for switching XX buffer
(defvar xetla-key-directory-prefix ?D)
(defvar xetla-key-merge-prefix ?M)
(defvar xetla-key-tag ?T)
(defvar xetla-key-revert ?U)
(defvar xetla-key-working-copy ?W)       ; Affecting on working copy
(defvar xetla-key-partner-file-prefix ?f)
(defvar xetla-key-tagging-method-prefix ?#)
(defvar xetla-key-id ?i)

;; functions for creating key groups
(defun xetla-key-group (prefix &rest keys)
  (apply 'vector prefix keys))

(defun  xetla-prefix-toggle (&rest keys)
  (xetla-key-group xetla-key-toggle keys))

(defun xetla-prefix-add (&rest keys)
  (xetla-key-group xetla-key-add keys))

(defun xetla-prefix-remove (&rest keys)
  (xetla-key-group xetla-key-remove keys))

(defun xetla-prefix-move (&rest keys)
  (xetla-key-group xetla-key-move keys))

(defun xetla-prefix-apply-from-here (&rest keys)
  (xetla-key-group xetla-key-apply-from-here keys))

(defun xetla-prefix-apply-from-head (&rest keys)
  (xetla-key-group xetla-key-apply-from-head keys))

(defun xetla-prefix-mark (&rest keys)
  (xetla-key-group xetla-key-mark-prefix keys))

(defun xetla-prefix-diff (&rest keys)
  (xetla-key-group xetla-key-diff-prefix keys))

(defun xetla-prefix-merge (&rest keys)
  (xetla-key-group xetla-key-merge-prefix keys))

(defun xetla-prefix-directory (&rest keys)
  (xetla-key-group xetla-key-directory-prefix keys))

(defun xetla-prefix-kill-ring (&rest keys)
  (xetla-key-group xetla-key-kill-ring-prefix keys))

(defun xetla-prefix-buffer (&rest keys)
  (xetla-key-group xetla-key-buffer-prefix keys))

(defun xetla-prefix-working-copy (&rest keys)
  (xetla-key-group xetla-key-working-copy keys))

(defun xetla-prefix-partner-file (&rest keys)
  (xetla-key-group xetla-key-partner-file-prefix keys))

(defun xetla-prefix-tag (&rest keys)
  (xetla-key-group xetla-key-tag keys))

(defun xetla-prefix-tagging-method (&rest keys)
  (xetla-key-group xetla-key-tagging-method-prefix keys))

;; predefined key vectors
(defvar xetla-keyvec-toggle-set     (xetla-prefix-toggle ?+))
(defvar xetla-keyvec-toggle-reset   (xetla-prefix-toggle ?-))
(defvar xetla-keyvec-toggle-invert  (xetla-prefix-toggle ?~))


(defvar xetla-keyvec-help    (vector xetla-key-help))
(defvar xetla-keyvec-parent  (vector xetla-key-parent))
(defvar xetla-keyvec-add     (vector xetla-key-add))
(defvar xetla-keyvec-remove  (vector xetla-key-remove))
(defvar xetla-keyvec-get     (vector xetla-key-get))
(defvar xetla-keyvec-refresh (vector xetla-key-refresh))

(defvar xetla-keyvec-next     (vector xetla-key-next))
(defvar xetla-keyvec-previous (vector xetla-key-previous))

(defvar xetla-keyvec-mark     (vector xetla-key-mark))
(defvar xetla-keyvec-unmark   (vector xetla-key-unmark))
(defvar xetla-keyvec-mark-all (xetla-prefix-mark ?*))
(defvar xetla-keyvec-unmark-all (xetla-prefix-mark ?!))
(defvar xetla-keyvec-quit (vector xetla-key-quit))
(defvar xetla-keyvec-popup-menu   (vector xetla-key-popup-menu))



(defvar xetla-keyvec-ediff (vector xetla-key-ediff))

(defvar xetla-keyvec-tree-lint (vector xetla-key-tree-lint))

(defvar xetla-keyvec-logs      (vector xetla-key-logs))

(defvar xetla-keyvec-log-entry (vector xetla-key-log-entry))

(defvar xetla-keyvec-diff (vector xetla-key-diff))

(defvar xetla-keyvec-file-diff (vector xetla-key-file-diff))

(defvar xetla-keyvec-file-diff (vector xetla-key-file-diff))

(defvar xetla-keyvec-commit (vector xetla-key-commit))

(defvar xetla-keyvec-update     (vector xetla-key-update))
(defvar xetla-keyvec-replay     (vector xetla-key-replay))
(defvar xetla-keyvec-star-merge (vector xetla-key-star-merge))

(defvar xetla-keyvec-reflect  (vector xetla-key-reflect))
(defvar xetla-keyvec-revert   (vector xetla-key-revert))


(defvar xetla-keyvec-inventory (vector xetla-key-inventory))


(defvar xetla-keyvec-show-bookmark (vector xetla-key-show-bookmark))
(defvar xetla-keyvec-add-bookmark (vector xetla-key-add-bookmark))

(defvar xetla-keyvec-tag (vector xetla-key-tag))
(defvar xetla-keyvec-kill-ring (vector xetla-key-kill-ring-prefix))

(defvar xetla-keyvec-id (vector xetla-key-id))
(defvar xetla-keyvec-toggle (vector xetla-key-toggle))
;;
;; Global
;;

(defvar xetla-global-keymap
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-log-entry     'xetla-add-log-entry)
    (define-key map [?A] 'xetla-archives)
    (define-key map xetla-keyvec-show-bookmark 'xetla-bookmarks)
    (define-key map xetla-keyvec-file-diff     'xetla-file-diff)
    (define-key map xetla-keyvec-ediff         'xetla-file-ediff)
    (define-key map [?o]                      'xetla-file-view-original)
    (define-key map xetla-keyvec-diff          'xetla-changes)
    (define-key map xetla-keyvec-commit        'xetla-edit-log)
    (define-key map [?t]                      'xetla-tag-insert)
    (define-key map xetla-keyvec-inventory     'xetla-inventory)
    (define-key map [?r]                      'xetla-tree-revisions)
    (define-key map xetla-keyvec-logs          'xetla-logs)
    (define-key map xetla-keyvec-tree-lint     'xetla-tree-lint)
    (define-key map xetla-keyvec-update        'xetla-update)
    (define-key map xetla-keyvec-help          'xetla-help)
    map)
  "Global keymap used by Xetla.")


(define-key ctl-x-4-map [?T] 'xetla-add-log-entry)

;;
;; Minibuffer(for reading engine)
;;
(defvar xetla-name-read-partner-menu (cons "Insert Partner Version" nil))
(fset 'xetla-name-read-partner-menu (cons 'keymap xetla-name-read-partner-menu))
(defvar xetla-name-read-bookmark-menu (cons "Insert Version in Bookmarks" nil))
(fset 'xetla-name-read-bookmark-menu (cons 'keymap xetla-name-read-bookmark-menu))


(defvar xetla-name-read-extension-keydefs
  '(([(control r)] . xetla-name-read-refresh-cache)
    ([(meta *)]    . xetla-name-read-insert-default-archive)
    ([(meta \.)]   . xetla-name-read-insert-info-at-point)
    ([(meta \;)]   . xetla-name-read-insert-version-associated-with-default-directory)
    ([(control n)] . xetla-name-read-insert-partner-next)
    ([(control p)] . xetla-name-read-insert-partner-previous)
    ([(control v)] . xetla-name-read-insert-bookmark-next)
    ([(meta v)]    . xetla-name-read-insert-bookmark-previous)
    ([(meta ^)]    . xetla-name-read-insert-ancestor)
    ([(control h)] . xetla-name-read-help)
    ([(meta \?)]    . xetla-name-read-inline-help))
    "Key definitions table for `xetla-name-read-minibuf-map'.
The reason these definitions are defined separately from
`xetla-name-read-minibuf-map' is that to reuse these definitions
in `xetla-name-read-help'. Don't forget to evalute
`xetla-name-read-minibuf-map' again after updating this value.")


(defvar xetla-name-read-minibuf-map
  (let ((map (copy-keymap minibuffer-local-completion-map)))
    ;; Keys
    (mapc
     (lambda (pair)
       (let ((key (car pair))
             (func (cdr pair)))
         (define-key map key func)))
     xetla-name-read-extension-keydefs)
    ;; Menus
    (define-key map [menu-bar xetla]
      (cons "XEtla" (make-sparse-keymap "XEtla")))
    (define-key map [menu-bar xetla refresh]
      (list 'menu-item "Refresh Completion Cache"
            'xetla-name-read-refresh-cache))
    (define-key map [menu-bar xetla ancestor]
      (list 'menu-item "Insert Ancestor"
            'xetla-name-read-insert-ancestor
            :enable '(and
                      (window-minibuffer-p)
                      (equal "" (buffer-substring))
                      (member archive '(prompt maybe))
                      (not (eq this-command 'xetla-compute-direct-ancestor))
                      )))
    (define-key map [menu-bar xetla default]
      (list 'menu-item "Insert Default Archive"
            'xetla-name-read-insert-default-archive
            :enable '(and
                      (window-minibuffer-p)
                      (equal "" (buffer-substring))
                      (member archive '(prompt maybe)))))
    (define-key map [menu-bar xetla here]
      (list 'menu-item "Insert Thing at Point"
            'xetla-name-read-insert-info-at-point
            :enable '(and (window-minibuffer-p)
                          (equal "" (buffer-substring))
                          xetla-name-read-insert-info-at-point)))
    (define-key map [menu-bar xetla bookmark]
      (list 'menu-item "Insert Version in Bookmark" 'xetla-name-read-bookmark-menu
            :enable '(let* ((l (condition-case nil
                                   (let ((default-version (xetla-tree-version-list default-directory)))
                                     (xetla-bookmarks-get-partner-versions default-version))
                                 (error nil))))
                       (and l (< 0 (length l))))))
    (define-key map [menu-bar xetla partner]
      (list 'menu-item "Insert Partner Version" 'xetla-name-read-partner-menu
            :enable '(let* ((l (condition-case nil (xetla-partner-list)
                                 (error nil))))
                       (and l (< 0 (length l))))))
    map)
  "Keymap to input a gnuarch revision at the minibuffer.")

;;
;; Context keymap template
;;
(defvar xetla-context-map-template
  (let ((map (make-sparse-keymap)))
    ;; TODO: [return[, "\C-m" => xetla-generic-context-action
    (define-key map (xetla-prefix-apply-from-here xetla-key-help) 'describe-bindings)
    (define-key map xetla-keyvec-help 'describe-mode)
    (define-key map [button3] 'xetla-generic-popup-menu)
    (define-key map xetla-keyvec-popup-menu 'xetla-generic-popup-menu-by-keyboard)
    map)
  "Template for keymaps used in items, files, changes, etc.")

;;
;; Bookmarks mode
;;
(defvar xetla-bookmarks-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-help 'describe-mode)
    ;; Move
    (define-key map xetla-keyvec-next       'xetla-bookmarks-next)
    (define-key map xetla-keyvec-previous   'xetla-bookmarks-previous)
    (define-key map [?N] 'xetla-bookmarks-move-down)
    (define-key map [?P] 'xetla-bookmarks-move-up)
    ;; Actions
    (define-key map (xetla-prefix-merge xetla-key-star-merge)
      'xetla-bookmarks-star-merge)
    (define-key map (xetla-prefix-merge xetla-key-replay)
      'xetla-bookmarks-replay)
    (define-key map (xetla-prefix-merge xetla-key-update)
      'xetla-bookmarks-update)
    (define-key map (xetla-prefix-merge xetla-key-missing)
      'xetla-bookmarks-missing)
    (define-key map (xetla-prefix-merge xetla-key-tag)
      'xetla-bookmarks-tag)
    (define-key map [?o] 'xetla-bookmarks-open-tree)
    (define-key map [(control x) (control f)] 'xetla-bookmarks-find-file)
    (define-key map xetla-keyvec-diff 'xetla-bookmarks-changes)
    (define-key map xetla-keyvec-get  'xetla-bookmarks-get)
    (define-key map "\C-m"           'xetla-bookmarks-goto)
    ;; Marks
    (define-key map xetla-keyvec-mark       'xetla-bookmarks-mark)
    (define-key map xetla-keyvec-unmark     'xetla-bookmarks-unmark)
    (define-key map xetla-keyvec-unmark-all 'xetla-bookmarks-unmark-all)
    (define-key map (xetla-prefix-mark ?g)  'xetla-bookmarks-select-by-group)
    ;; Partners
    (define-key map [(meta p)] 'xetla-bookmarks-marked-are-partners)
    (define-key map (xetla-prefix-add    ?p)
      'xetla-bookmarks-add-partner-interactive)
    (define-key map (xetla-prefix-remove ?p)
      'xetla-bookmarks-delete-partner-interactive)
    (define-key map (xetla-prefix-partner-file ?r)
      'xetla-bookmarks-add-partners-from-file)
    (define-key map (xetla-prefix-partner-file ?w)
      'xetla-bookmarks-write-partners-to-file)
    ;; Bookmark manipulation
    (define-key map (xetla-prefix-add    ?b) 'xetla-bookmarks-add)
    (define-key map (xetla-prefix-remove ?b) 'xetla-bookmarks-delete)
    (define-key map [?e] 'xetla-bookmarks-edit)
    (define-key map xetla-keyvec-toggle  'xetla-bookmarks-toggle-details)
    ;; Fields
    (define-key map (xetla-prefix-add    ?t) 'xetla-bookmarks-add-tree-interactive)
    (define-key map (xetla-prefix-remove ?t) 'xetla-bookmarks-delete-tree-interactive)
    (define-key map (xetla-prefix-add    ?g) 'xetla-bookmarks-add-group-interactive)
    (define-key map (xetla-prefix-remove ?g) 'xetla-bookmarks-delete-group-interactive)
    (define-key map (xetla-prefix-add    ?n) 'xetla-bookmarks-add-nickname-interactive)
    (define-key map (xetla-prefix-remove ?n) 'xetla-bookmarks-delete-nickname-interactive)
    ;; Switch to other buffers
    (define-key map xetla-keyvec-inventory 'xetla-bookmarks-inventory)
    (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    map)
  "Keymap used in `xetla-bookmarks-mode' buffers.")

(defvar xetla-bookmarks-entry-map
  (let ((map (copy-keymap xetla-context-map-template)))
    (define-key map [button2] 'xetla-bookmarks-goto-by-mouse)
    map)
  "Keymap used on entries in `xetla-bookmarks-mode' buffers.")

;;
;; Inventory mode
;;
(defvar xetla-inventory-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-help    'describe-mode)
    (define-key map xetla-keyvec-refresh 'xetla-generic-refresh)
    (define-key map xetla-keyvec-add     'xetla-inventory-add-files)
    (define-key map xetla-keyvec-remove  'xetla-inventory-remove-files)
    (define-key map xetla-keyvec-quit    'xetla-buffer-quit)
    (define-key map xetla-keyvec-next     'xetla-inventory-next)
    (define-key map xetla-keyvec-previous 'xetla-inventory-previous)
    (define-key map xetla-keyvec-parent   'xetla-inventory-parent-directory)
    ;;
    ;;
    ;;
    (define-key map [?X] 'xetla-inventory-delete-files)
    (define-key map (xetla-prefix-move xetla-key-move) 'xetla-inventory-move)
    (define-key map xetla-keyvec-commit 'xetla-inventory-edit-log) ;; mnemonic for commit
    (define-key map [?l] 'xetla-changelog)
    (define-key map xetla-keyvec-logs 'xetla-logs)
    ;;
    ;; Find file group
    ;;
    (define-key map [?f] 'xetla-inventory-find-file)
    (define-key map [return] 'xetla-inventory-find-file)
    (define-key map "\C-m" 'xetla-inventory-find-file)
    (define-key map [?o] 'xetla-generic-find-file-other-window)
    (define-key map [?v] 'xetla-generic-view-file)
    ;;
    ;; Diffs group
    ;;
    (define-key map (xetla-prefix-merge xetla-key-missing)
      'xetla-inventory-missing)
    (define-key map (xetla-prefix-diff xetla-key-diff)
      'xetla-inventory-changes)
    (define-key map (xetla-prefix-diff ?l) 'xetla-changes-last-revision)
    (define-key map (xetla-prefix-diff xetla-key-ediff)
      'xetla-inventory-file-ediff)
    (define-key map (xetla-prefix-diff xetla-key-get)
      'xetla-inventory-delta)
    ;; Alias for above bindings
    (define-key map xetla-keyvec-diff    'xetla-inventory-changes)
    (define-key map xetla-keyvec-ediff   'xetla-inventory-file-ediff)
    ;;
    (define-key map xetla-keyvec-reflect 'xetla-inventory-mirror)
    ;;
    ;; Merge group
    ;;
    (define-key map (xetla-prefix-merge xetla-key-star-merge)
      'xetla-inventory-star-merge)
    (define-key map (xetla-prefix-merge xetla-key-replay)
      'xetla-inventory-replay)
    (define-key map (xetla-prefix-merge xetla-key-update)
      'xetla-inventory-update)
    (define-key map (xetla-prefix-merge xetla-key-reflect)
      'xetla-inventory-apply-changeset)
    ;;
    ;; Buffers group
    ;;
    (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
    (define-key map (xetla-prefix-buffer xetla-key-show-bookmark) 'xetla-bookmarks)
    ;;
    ;; Undo and redo group
    ;;
    (define-key map xetla-keyvec-revert        'xetla-inventory-revert)
    (define-key map (xetla-prefix-working-copy xetla-key-revert) 'xetla-inventory-undo)
    (define-key map (xetla-prefix-working-copy ?R) 'xetla-inventory-redo)
    ;;
    ;; Patches group
    ;;
    (define-key map (xetla-prefix-working-copy ?S) 'xetla-changes-save)
    (define-key map (xetla-prefix-working-copy ?s) 'xetla-changes-save-as-tgz)
    (define-key map (xetla-prefix-working-copy ?V) 'xetla-show-changeset)
    (define-key map (xetla-prefix-working-copy ?v) 'xetla-show-changeset-from-tgz)
    (define-key map (xetla-prefix-working-copy ?A) 'xetla-inventory-apply-changeset)
    (define-key map (xetla-prefix-working-copy ?a) 'xetla-inventory-apply-changeset-from-tgz)
    ;;
    ;; Kill ring group
    ;;
    (define-key map (xetla-prefix-kill-ring ?a) 'xetla-save-archive-to-kill-ring)
    ;;
    ;; Tree lint
    ;;
    (define-key map (xetla-prefix-working-copy xetla-key-tree-lint)
      'xetla-tree-lint)
    ;;
    ;; Mark group
    ;;
    (define-key map (xetla-prefix-mark xetla-key-mark) 'xetla-inventory-mark-file)
    (define-key map (xetla-prefix-mark xetla-key-unmark) 'xetla-inventory-unmark-file)
    ;; (define-key map xetla-keyvec-mark-all      'xetla-inventory-mark-all)
    (define-key map xetla-keyvec-unmark-all    'xetla-inventory-unmark-all)
    ;; Alias for above bindings
    (define-key map xetla-keyvec-mark          'xetla-inventory-mark-file)
    (define-key map xetla-keyvec-unmark        'xetla-inventory-unmark-file)
    ;;
    ;; Tagging method
    ;;
    (define-key map (xetla-prefix-tagging-method ?=) 'xetla-edit-=tagging-method-file)
    (define-key map (xetla-prefix-tagging-method ?.) 'xetla-edit-.arch-inventory-file)
    ;;
    ;; Exclude, junk, precious, unrecognized...
    ;;
    (define-key map (xetla-prefix-move ?j) 'xetla-inventory-make-junk)
    (define-key map (xetla-prefix-move ?,) 'xetla-inventory-make-junk)
    (define-key map (xetla-prefix-move ?p) 'xetla-inventory-make-precious)
    (define-key map (xetla-prefix-move ?+) 'xetla-inventory-make-precious)
    (define-key map (xetla-prefix-tagging-method ?M) 'xetla-generic-set-id-tagging-method)
    (define-key map (xetla-prefix-tagging-method ?V) 'xetla-generic-set-tree-version)
    (define-key map (xetla-prefix-tagging-method ?x) 'xetla-generic-add-to-exclude) ; alias
    (define-key map (xetla-prefix-tagging-method ?e) 'xetla-generic-add-to-exclude) ; alias
    (define-key map (xetla-prefix-tagging-method ?j) 'xetla-generic-add-to-junk)
    (define-key map (xetla-prefix-tagging-method ?b) 'xetla-generic-add-to-backup)
    (define-key map (xetla-prefix-tagging-method ?~) 'xetla-generic-add-to-backup) ; alias
    (define-key map (xetla-prefix-tagging-method ?p) 'xetla-generic-add-to-precious)
    (define-key map (xetla-prefix-tagging-method ?u) 'xetla-generic-add-to-unrecognized)
    ;;
    ;; Toggles
    ;;
    (define-key map xetla-keyvec-toggle-set    'xetla-inventory-set-all-toggle-variables)
    (define-key map xetla-keyvec-toggle-reset  'xetla-inventory-reset-all-toggle-variables)
    (define-key map xetla-keyvec-toggle-invert 'xetla-inventory-toggle-all-toggle-variables)
    map)
  "Keymap used in `xetla-inventory-mode' buffers.")

(defvar xetla-inventory-item-map
  (let ((map (copy-keymap xetla-context-map-template)))
    (define-key map [button2] 'xetla-inventory-find-file-by-mouse)
    map)
  "Keymap used on items in `xetla-inventory-mode' buffers.")

(defvar xetla-inventory-default-version-map
  (let ((map (copy-keymap xetla-context-map-template)))
    (define-key map [return] 'xetla-generic-set-tree-version)
    (define-key map "\C-m" 'xetla-generic-set-tree-version)
    map)
  "Keymap used on the default version field in `xetla-inventory-mode' buffers.")

(defvar xetla-inventory-tagging-method-map
  (let ((map (copy-keymap xetla-context-map-template)))
    (define-key map [button2] 'xetla-generic-set-id-tagging-method-by-mouse)
    (define-key map [return] 'xetla-generic-set-id-tagging-method)
    (define-key map "\C-m" 'xetla-inventory-id-tagging-method)
    map)
  "Keymap used on the tagging method field in `xetla-inventory-mode' buffers.")


(defconst xetla-inventory-file-types-manipulators
  '((?S xetla-inventory-display-source
        xetla-inventory-toggle-source ?s "source")
    (?P xetla-inventory-display-precious
        xetla-inventory-toggle-precious ?p "precious")
    (?J xetla-inventory-display-junk
        xetla-inventory-toggle-junk ?j "junk")
    (?B xetla-inventory-display-backup
        xetla-inventory-toggle-backup ?b "backup")
    (?T xetla-inventory-display-tree
        xetla-inventory-toggle-tree ?t "tree root")
    (?U xetla-inventory-display-unrecognized
        xetla-inventory-toggle-unrecognized ?u "unrecognized"))
  "List of possible file types in inventory.")

(dolist (type-arg xetla-inventory-file-types-manipulators)
  (define-key xetla-inventory-mode-map `[?t ,(cadddr type-arg)] (caddr type-arg)))


(dolist (type-arg xetla-inventory-file-types-manipulators)
  (eval `(defcustom ,(cadr type-arg) t
           ,(concat "Whether " (nth 4 type-arg)
                    " should be printed in inventory")
           :group 'xetla-inventory
           :type 'boolean)))

(defvar xetla-tree-lint-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-help    'describe-mode)
    (define-key map xetla-keyvec-refresh 'xetla-generic-refresh)
    (define-key map xetla-keyvec-add     'xetla-tree-lint-add-files)
    (define-key map xetla-keyvec-remove  'xetla-tree-lint-delete-files)
    (define-key map xetla-keyvec-quit    'xetla-buffer-quit)
    (define-key map xetla-keyvec-next    'xetla-tree-lint-next)
    (define-key map xetla-keyvec-previous 'xetla-tree-lint-previous)
    (define-key map [down]              'xetla-tree-lint-next)
    (define-key map [up]                'xetla-tree-lint-previous)
    (define-key map xetla-keyvec-id      'xetla-tree-lint-regenerate-id)
    (define-key map (xetla-prefix-move ?j) 'xetla-tree-lint-make-junk)
    (define-key map (xetla-prefix-move ?,) 'xetla-tree-lint-make-junk)
    (define-key map (xetla-prefix-move ?p) 'xetla-tree-lint-make-precious)
    (define-key map (xetla-prefix-move ?+) 'xetla-tree-lint-make-precious)
    ;;
    (define-key map (xetla-prefix-tagging-method ?=) 'xetla-edit-=tagging-method-file)
    (define-key map (xetla-prefix-tagging-method ?.) 'xetla-edit-.arch-inventory-file)
    (define-key map (xetla-prefix-tagging-method ?M) 'xetla-generic-set-id-tagging-method)
    (define-key map (xetla-prefix-tagging-method ?V) 'xetla-generic-set-tree-version)
    (define-key map (xetla-prefix-tagging-method ?x) 'xetla-generic-add-to-exclude) ; alias
    (define-key map (xetla-prefix-tagging-method ?e) 'xetla-generic-add-to-exclude) ; alias
    (define-key map (xetla-prefix-tagging-method ?j) 'xetla-generic-add-to-junk)
    (define-key map (xetla-prefix-tagging-method ?b) 'xetla-generic-add-to-backup)
    (define-key map (xetla-prefix-tagging-method ?~) 'xetla-generic-add-to-backup) ; alias
    (define-key map (xetla-prefix-tagging-method ?p) 'xetla-generic-add-to-precious)
    (define-key map (xetla-prefix-tagging-method ?u) 'xetla-generic-add-to-unrecognized)
    ;;
    (define-key map [return]            'xetla-generic-find-file-at-point)
    (define-key map "\C-m"              'xetla-generic-find-file-at-point)
    (define-key map [?o]                'xetla-generic-find-file-other-window)
    (define-key map [?v]                'xetla-generic-view-file)
    ;;
    ;; Mark group
    ;;
    (define-key map (xetla-prefix-mark xetla-key-mark) 'xetla-tree-lint-mark-file)
    (define-key map (xetla-prefix-mark xetla-key-unmark) 'xetla-tree-lint-unmark-file)
    ;; TODO
    ;; (define-key map xetla-keyvec-mark-all      'xetla-tree-lint-mark-all)
    (define-key map xetla-keyvec-unmark-all    'xetla-tree-lint-unmark-all)
    ;; Alias for above bindings
    (define-key map xetla-keyvec-mark          'xetla-tree-lint-mark-file)
    (define-key map xetla-keyvec-unmark        'xetla-tree-lint-unmark-file)
    ;;
    ;; Buffers group
    ;;
    (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
    (define-key map (xetla-prefix-buffer xetla-key-show-bookmark) 'xetla-bookmarks)
    map)
  "Keymap used in `xetla-tree-lint-mode' buffers.")

(defvar xetla-tree-lint-file-map
  (let ((map (copy-keymap xetla-context-map-template)))
    (define-key map [button2] 'xetla-generic-find-file-at-point-by-mouse)
    map)
  "Keymap used on files in xetla-lint-mode buffers.")

;;
;; Cat-Log mdoe
;;
(defvar xetla-cat-log-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-help 'describe-mode)
    (define-key map xetla-keyvec-inventory 'xetla-pop-to-inventory)
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    map)
  "Keymap used in `xetla-cat-log-mode' buffers.")

;;
;; Log edit mode
;;
(defvar xetla-log-edit-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map [(control ?c) (control ?c)] 'xetla-log-edit-done)
    (define-key map [(control ?c) (control ?d)] 'xetla-changes)
    (define-key map [(control ?c) (control ?l)] 'xetla-changelog)
    (define-key map [(control ?c) (control ?m)] 'xetla-log-edit-insert-log-for-merge)
    (define-key map [(control ?c)          ?m ]
      'xetla-log-edit-insert-log-for-merge-and-headers)
    (define-key map [(control ?c) (control ?p)] 'xetla-log-edit-insert-memorized-log)
    (define-key map [(control ?c) (control ?q)] 'xetla-log-edit-abort)
    (define-key map [(control ?c) (control ?s)] 'xetla-log-goto-summary)
    (define-key map [(control ?c) (control ?b)] 'xetla-log-goto-body)
    (define-key map [(control ?c) (control ?k)] 'xetla-log-edit-keywords)
    (define-key map "\t" 'xetla-log-edit-next-field)
    map)
  "Keymap used in `xetla-log-edit-mode' buffers.")

;;
;; Archive list mode
;;
(defvar xetla-archive-list-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-help 'describe-mode)
    (define-key map (xetla-prefix-kill-ring ?a) 'xetla-save-archive-to-kill-ring)
    (define-key map "\C-m" 'xetla-archive-list-categories)
    (define-key map [return] 'xetla-archive-list-categories)

    ;; Buffers group
    (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
    (define-key map (xetla-prefix-buffer xetla-key-show-bookmark) 'xetla-bookmarks)

    (define-key map xetla-keyvec-add-bookmark 'xetla-bookmarks-add)
    (define-key map [?o] 'xetla-archive-browse-archive)
    (define-key map [?*] 'xetla-archive-select-default)
    (define-key map (xetla-prefix-add ?r) 'xetla-register-archive)
    (define-key map (xetla-prefix-add ?a) 'xetla-make-archive)
    (define-key map (xetla-prefix-add ?m) 'xetla-archive-mirror-archive)
    (define-key map xetla-keyvec-remove   'xetla-archive-unregister-archive)
    (define-key map [?g] 'xetla-archives)
    (define-key map [?s] 'xetla-archive-synchronize-archive)
    (define-key map [?e] 'xetla-archive-edit-archive-location)
    (define-key map [down] 'xetla-archive-next)
    (define-key map [up] 'xetla-archive-previous)
    (define-key map [?n] 'xetla-archive-next)
    (define-key map [?p] 'xetla-archive-previous)
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    map)
  "Keymap used in `xetla-archive-list-mode' buffers.")

(defvar xetla-archive-archive-map
  (let ((map (make-sparse-keymap)))
    (define-key map [button2] 'xetla-archive-list-categories-by-mouse)
    map)
  "Keymap used archives in `xetla-archive-list-mode' buffers.")

;;
;; Category list mode
;;
(defvar xetla-category-list-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-help 'describe-mode)
    (define-key map "\C-m" 'xetla-category-list-branches)
    (define-key map [return] 'xetla-category-list-branches)

    ;; Buffers group
    (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
    (define-key map (xetla-prefix-buffer xetla-key-show-bookmark) 'xetla-bookmarks)

    (define-key map xetla-keyvec-add-bookmark 'xetla-category-bookmarks-add)
    (define-key map (xetla-prefix-apply-from-here
                     xetla-key-add-bookmark) 'xetla-category-bookmarks-add-here)
    (define-key map [?^] 'xetla-archives)
    (define-key map (xetla-prefix-add ?c) 'xetla-category-make-category)
    (define-key map [?g] 'xetla-category-refresh)
    (define-key map [?s] 'xetla-category-mirror-archive)
    (define-key map [down] 'xetla-category-next)
    (define-key map [up] 'xetla-category-previous)
    (define-key map [?n] 'xetla-category-next)
    (define-key map [?p] 'xetla-category-previous)
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    map)
  "Keymap used in `xetla-category-list-mode' buffers.")

(defvar xetla-category-category-map
  (let ((map (make-sparse-keymap)))
    (define-key map [button2] 'xetla-category-list-branches-by-mouse)
    map)
  "Keymap used categories in `xetla-category-list-mode' buffers.")

;;
;; Branch list mode section
;;
(defvar xetla-branch-list-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-help 'describe-mode)
    (define-key map "\C-m" 'xetla-branch-list-versions)
    (define-key map [return] 'xetla-branch-list-versions)

    ;; Buffers group
    (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
    (define-key map (xetla-prefix-buffer xetla-key-show-bookmark) 'xetla-bookmarks)

    (define-key map xetla-keyvec-parent 'xetla-branch-list-parent-category)
    (define-key map (xetla-prefix-add ?b) 'xetla-branch-make-branch)
    (define-key map [?>] 'xetla-branch-get-branch)
    (define-key map [?g] 'xetla-branch-refresh)
    (define-key map [?s] 'xetla-branch-mirror-archive)
    (define-key map [down] 'xetla-category-next)
    (define-key map [up] 'xetla-category-previous)
    (define-key map [?n] 'xetla-category-next)
    (define-key map [?p] 'xetla-category-previous)
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    (define-key map (xetla-prefix-apply-from-here
                     xetla-key-add-bookmark) 'xetla-branch-bookmarks-add-here)
    (define-key map xetla-keyvec-add-bookmark 'xetla-branch-bookmarks-add)
    map)
  "Keymap used in `xetla-branch-list-mode' buffers.")

(defvar xetla-branch-branch-map
  (let ((map (make-sparse-keymap)))
    (define-key map [button2] 'xetla-branch-list-versions-by-mouse)
    map)
  "Keymap used branches in `xetla-branch-list-mode' buffers.")

;;
;; Version list mode
;;
(defvar xetla-version-list-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-help 'describe-mode)
    (define-key map "\C-m" 'xetla-version-list-revisions)
    (define-key map [return] 'xetla-version-list-revisions)

    ;; Buffers group
    (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
    (define-key map (xetla-prefix-buffer xetla-key-show-bookmark) 'xetla-bookmarks)

    (define-key map xetla-keyvec-parent 'xetla-version-list-parent-branch)
    (define-key map (xetla-prefix-add ?v) 'xetla-version-make-version)
    (define-key map [?>] 'xetla-version-get-version)
    (define-key map [?g] 'xetla-version-refresh)
    (define-key map [?s] 'xetla-version-mirror-archive)
    (define-key map [down] 'xetla-category-next)
    (define-key map [up] 'xetla-category-previous)
    (define-key map [?n] 'xetla-category-next)
    (define-key map [?p] 'xetla-category-previous)
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    (define-key map (xetla-prefix-apply-from-here
                     xetla-key-add-bookmark) 'xetla-version-bookmarks-add-here)
    (define-key map xetla-keyvec-add-bookmark 'xetla-version-bookmarks-add)
    (define-key map xetla-keyvec-tag 'xetla-version-tag)
    map)
  "Keymap used in `xetla-version-list-mode' buffers.")

(defvar xetla-version-version-map
  (let ((map (make-sparse-keymap)))
    (define-key map [button2] 'xetla-version-list-revisions-by-mouse)
    map)
  "Keymap used versions in `xetla-version-list-mode' buffers.")

;;
;; Revision list mode
;;
(defvar xetla-revision-list-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-help 'describe-mode)
    (define-key map xetla-keyvec-parent 'xetla-revision-list-parent-version)
    (define-key map [?> ?g] 'xetla-revision-get-revision)
    (define-key map [?> ?C] 'xetla-revision-cache-revision)
    (define-key map [?> ?L] 'xetla-revision-add-to-library)

    ;; Buffers group
    (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
    (define-key map (xetla-prefix-buffer xetla-key-show-bookmark) 'xetla-bookmarks)

    (define-key map [?b] 'xetla-bookmarks-add)
    (define-key map (xetla-prefix-toggle ??) 'xetla-revision-toggle-help)
    (define-key map (xetla-prefix-toggle ?d) 'xetla-revision-toggle-date)
    (define-key map (xetla-prefix-toggle ?c) 'xetla-revision-toggle-creator)
    (define-key map (xetla-prefix-toggle ?s) 'xetla-revision-toggle-summary)
    (define-key map (xetla-prefix-toggle ?l) 'xetla-revision-toggle-library)
    (define-key map (xetla-prefix-toggle ?m) 'xetla-revision-toggle-merges)
    (define-key map (xetla-prefix-toggle ?b) 'xetla-revision-toggle-merged-by)
    (define-key map (xetla-prefix-toggle ?r) 'xetla-revision-toggle-reverse)

    ;;
    ;; Star merge
    ;; from here
    (define-key map (xetla-prefix-apply-from-here
                     xetla-key-star-merge) 'xetla-revision-star-merge)
    ;; from head
    (define-key map (xetla-prefix-apply-from-head xetla-key-star-merge)
      'xetla-revision-star-merge-version)
    (define-key map (xetla-prefix-merge xetla-key-star-merge)
      'xetla-revision-star-merge-version)
    (define-key map xetla-keyvec-star-merge 'xetla-revision-star-merge-version)

    ;;
    ;; Replay
    ;; from here
    (define-key map (xetla-prefix-apply-from-here xetla-key-replay)
      'xetla-revision-replay)
    ;; from head
    (define-key map (xetla-prefix-apply-from-head xetla-key-replay)
      'xetla-revision-replay-version)
    (define-key map xetla-keyvec-replay 'xetla-revision-replay-version)

    (define-key map (xetla-prefix-apply-from-here ?y)
      'xetla-revision-sync-tree)
    ;;
    ;; Update
    (define-key map (xetla-prefix-merge xetla-key-update)
      'xetla-revision-update)
    ;;
    ;; Tag
    ;; from here
    (define-key map (xetla-prefix-apply-from-here
                     xetla-key-tag) 'xetla-revision-tag-from-here)

    (define-key map (xetla-prefix-tag
                     xetla-key-apply-from-here) 'xetla-revision-tag-from-here)
    ;; from head
    (define-key map (xetla-prefix-apply-from-head
                     xetla-key-tag) 'xetla-revision-tag-from-head)
    (define-key map (xetla-prefix-tag
                     xetla-key-apply-from-head) 'xetla-revision-tag-from-head)

    (define-key map [?g] 'xetla-generic-refresh)
    (define-key map [down] 'xetla-revision-next)
    (define-key map [up] 'xetla-revision-prev)
    (define-key map [?n] 'xetla-revision-next)
    (define-key map [?p] 'xetla-revision-prev)
    (define-key map [?N] 'xetla-revision-next-unmerged)
    (define-key map [?P] 'xetla-revision-prev-unmerged)
    (define-key map [?l] 'xetla-revision-cat-log)
    (define-key map "\C-m" 'xetla-revision-show-changeset)
    (define-key map [return] 'xetla-revision-show-changeset)
    (define-key map xetla-keyvec-mark   'xetla-revision-mark-revision)
    (define-key map xetla-keyvec-unmark 'xetla-revision-unmark-revision)
    (define-key map (xetla-prefix-diff xetla-key-diff) 'xetla-revision-delta)
    (define-key map (xetla-prefix-diff xetla-key-get)  'xetla-revision-store-delta)
    (define-key map [?=] 'xetla-revision-changeset)
    (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
    (define-key map (xetla-prefix-buffer xetla-key-show-bookmark) 'xetla-bookmarks)
    (define-key map xetla-keyvec-inventory 'xetla-pop-to-inventory)
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    (define-key map xetla-keyvec-add-bookmark 'xetla-revision-bookmarks-add)
    map)
  "Keymap used in `xetla-revision-list-mode' buffers.")

(defstruct (xetla-revision)
  revision ;; The revision, as a list
  summary creator date
  merges ;; List of patches merged by this revision
  merged-by ;; List of patches merging this revision
  )

(defvar xetla-revision-revision-map
  (let ((map (copy-keymap xetla-context-map-template)))
    (define-key map [button2] 'xetla-revision-show-changeset-by-mouse)
    map)
  "Keymap used on revisions in `xetla-revision-list-mode' buffers.")

;;
;; Changes mode
;;
(defvar xetla-changes-mode-map
  (let ((map (copy-keymap diff-mode-shared-map)))
    (define-key map xetla-keyvec-help 'describe-mode)
    (define-key map "\C-m" 'xetla-changes-jump-to-change)
    (define-key map [return] 'xetla-changes-jump-to-change)
    (define-key map [?=] 'xetla-changes-diff)
    (define-key map xetla-keyvec-ediff   'xetla-changes-ediff)
    (define-key map xetla-keyvec-refresh 'xetla-generic-refresh)
    (define-key map xetla-keyvec-commit  'xetla-changes-edit-log)
    (define-key map [?I] 'xetla-inventory)
    (define-key map xetla-keyvec-inventory 'xetla-pop-to-inventory)
    (define-key map xetla-keyvec-next      'xetla-changes-next)
    (define-key map xetla-keyvec-previous  'xetla-changes-prev)
    (define-key map xetla-keyvec-revert    'xetla-changes-revert)
    (define-key map xetla-keyvec-quit      'xetla-buffer-quit)
    (define-key map [?d] 'xetla-changes-rm)
    (define-key map xetla-keyvec-mark   'xetla-changes-mark-file)
    (define-key map xetla-keyvec-unmark 'xetla-changes-unmark-file)
    (define-key map [?v] 'xetla-changes-view-source)
    (define-key map xetla-keyvec-parent 'xetla-changes-master-buffer)
    (define-key map [?j] 'xetla-changes-diff-or-list)
    ;; Buffers group
    (define-key map (xetla-prefix-buffer ?p) 'xetla-show-process-buffer)
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)
    (define-key map (xetla-prefix-buffer xetla-key-show-bookmark) 'xetla-bookmarks)
    map)
  "Keymap used in `xetla-changes-mode'.")

(defvar xetla-changes-file-map
  (let ((map (copy-keymap xetla-context-map-template)))
    (define-key map [button2] 'xetla-changes-jump-to-change-by-mouse)
    map)
  "Keymap used on files in `xetla-changes-mode' buffers.")


;;
;; ChangeLog mode section
;;
(defvar xetla-changelog-mode-map
  (let ((map (copy-keymap change-log-mode-map)))
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    map)
  "Keymap used in `xetla-changelog-mode'.")


;;
;; Log buffer mode section
;;
(defvar xetla-log-buffer-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-help 'describe-mode)
    (define-key map [?o] 'xetla-switch-to-output-buffer)
    (define-key map "\C-m" 'xetla-switch-to-output-buffer)
    (define-key map [?e] 'xetla-switch-to-error-buffer)
    (define-key map [?r] 'xetla-switch-to-related-buffer)
    (define-key map [?n] 'xetla-log-next)
    (define-key map [?p] 'xetla-log-prev)
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    map)
  "Keymap used in XEtla's log buffer.")

;;
;; Process buffer mode section
;;
(defvar xetla-process-buffer-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (xetla-prefix-buffer ?L) 'xetla-open-internal-log-buffer)

    (define-key map xetla-keyvec-inventory 'xetla-show-inventory-buffer)
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    map)
  "Keymap used in XEtla's log buffer.")

;;
;; Log edit buffer mode section
;;

(defvar xetla-log-edit-keywords-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map [?n] 'xetla-log-edit-keywords-next)
    (define-key map [?p] 'xetla-log-edit-keywords-previous)
    (define-key map [?m] 'xetla-log-edit-keywords-mark)
    (define-key map [?u] 'xetla-log-edit-keywords-unmark)
    (define-key map [?t] 'xetla-log-edit-keywords-toggle-mark)
    (define-key map [?* ?!] 'xetla-log-edit-keywords-unmark-all)
    (define-key map [?* ?*] 'xetla-log-edit-keywords-mark-all)
    (define-key map "\C-c\C-c" 'xetla-log-edit-keywords-insert)
    map)
  "Keymap used in xetla-log-edit-keywords-mode buffers.")


;; --------------------------------------
;; Menu entries
;; --------------------------------------
;;
;; Conventions
;;
;; 1. Each Nouns and verbs in menu items are should be capitalized.
;; 2. TODO: Consider menu items order.

;;
;; Common submenus
;;

(defconst xetla-.arch-inventory-menu-list
  '("Put to .arch-inventory"
    ["Junk"         xetla-generic-add-to-junk         t]
    ["Backup"       xetla-generic-add-to-backup       t]
    ["Precious"     xetla-generic-add-to-precious     t]
    ["Unrecognized" xetla-generic-add-to-unrecognized t]))

(defconst xetla-=tagging-method-menu-list
  '("Put to =tagging-method"
    ["Junk"         (xetla-generic-add-to-junk t)     t]
    ["Backup"       (xetla-generic-add-to-backup t)   t]
    ["Precious"     (xetla-generic-add-to-precious t) t]
    ["Unrecognized" (xetla-generic-add-to-junk t)     t]))


;;
;; Global
;;

(easy-menu-add-item
 (or (xetla-do-in-gnu-emacs menu-bar-tools-menu) nil)
 (or (xetla-do-in-xemacs '("Tools")) nil)
 '("XEtla"
   ["Browse Archives" xetla-archives t]
   ["Show Bookmarks" xetla-bookmarks t]
   ["Start New Project" xetla-start-project t]
   "--"
   "Tree Commands:"
   ["View Changes" xetla-changes t]
   ["View Inventory" xetla-inventory t]
   ["View Tree Lint" xetla-tree-lint t]
   ["Show Tree Revisions" xetla-tree-revisions t]
   ["Edit Arch Log" xetla-edit-log t]
   "--"
   "File Commands:"
   ["Insert Arch Tag" xetla-tag-insert t]
   ["Add Log Entry" xetla-add-log-entry t]
   ["View File Diff" xetla-file-diff t]
   ["View File Ediff" xetla-file-ediff t]
   ["View Original" xetla-file-view-original t]
   ["View Conflicts" xetla-view-conflicts t]
   "--"
   ("Quick Configuration"
    ["Three Way Merge" xetla-toggle-three-way-merge
     :style toggle :selected xetla-three-way-merge]
    ["Use --forward" xetla-toggle-use-forward-option
     :style toggle :selected xetla-use-forward-option]
    ["Use --skip-present" xetla-toggle-use-skip-present-option
     :style toggle :selected xetla-use-skip-present-option]
    )
   )
 "PCL-CVS")

;;
;; Bookmarks mode
;;
(defconst xetla-bookmarks-entry-menu-list
  '("Bookmark Entry"
    ["Delete"         xetla-bookmarks-delete    t]
    ["Goto Location"  xetla-bookmarks-goto      t]
    ("File Tree"
     ["Find File"      xetla-bookmarks-find-file t]
     ["Run Dired"      xetla-bookmarks-open-tree t]
     ["Run Inventory"  xetla-bookmarks-inventory t]
     ["View Changes"   xetla-bookmarks-changes t]
     )
    ("Merge"
     ["View Missing Patches" xetla-bookmarks-missing t]
     ["Replay"       xetla-bookmarks-replay  t]
     ["Update"       xetla-bookmarks-update  t]
     ["Star-merge"   xetla-bookmarks-star-merge t]
     )
    ("Edit"
     ["Edit Bookmark"    xetla-bookmarks-edit t]
     ["Add Nickname"     xetla-bookmarks-add-nickname-interactive    t]
     ["Remove Nickname"  xetla-bookmarks-delete-nickname-interactive t]
     ["Add Local Tree"   xetla-bookmarks-add-tree-interactive        t]
     ["Remove Local Tree" xetla-bookmarks-delete-tree-interactive    t]
     ["Add Group"        xetla-bookmarks-add-group-interactive       t]
     ["Remove Group"     xetla-bookmarks-delete-group-interactive    t]
     ["Add Partner"      xetla-bookmarks-add-partner-interactive     t]
     ["Remove Partner"   xetla-bookmarks-delete-partner-interactive  t]
     )
    ("Partners"
     ["Add Partner"      xetla-bookmarks-add-partner-interactive     t]
     ["Remove Partner"   xetla-bookmarks-delete-partner-interactive  t]
     ["Write to Partner File" xetla-bookmarks-write-partners-to-file t]
     ["Load from Partner File" xetla-bookmarks-add-partners-from-file t]
     ["View Missing Patches" xetla-bookmarks-missing t]
     ))
  "Used both for the local and the global menu."
  )

(easy-menu-define xetla-bookmarks-mode-menu xetla-bookmarks-mode-map
  "`xetla-bookmarks-mode' menu"
  `("XEtla-Bookmarks"
    ["Add Bookmark" xetla-bookmarks-add t]
    ["Show Details" xetla-bookmarks-toggle-details
     :style toggle :selected xetla-bookmarks-show-details]
    ["Select by Group" xetla-bookmarks-select-by-group t]
    ["Cleanup 'local-tree fields" xetla-bookmarks-cleanup-local-trees t]
    ,xetla-bookmarks-entry-menu-list
    ))

(easy-menu-define xetla-bookmarks-entry-menu nil
  "Menu used on a xetla bookmark entry."
  xetla-bookmarks-entry-menu-list)

;;
;; Inventory mode
;;
(easy-menu-define xetla-inventory-mode-partners-menu xetla-inventory-mode-map
  "`xetla-inventory-mode' partners menu"
  '("Partners"
    ["Add Partner..." xetla-partner-add t]
    ("Set Tree Version" :filter (lambda (x)
                                  (xetla-partner-create-menu
                                   'xetla-generic-set-tree-version)))
    "--"
    ("Show Changes" :filter (lambda (x)
                              (xetla-partner-create-menu
                               '(lambda (x)
                                  (xetla-changes current-prefix-arg
                                               (list 'revision (xetla-name-split x)))))))
    ("Show Missing" :filter (lambda (x)
                              (xetla-partner-create-menu
                               '(lambda (x)
                                  (xetla-missing default-directory x)))))
    "--"
    ("Replay" :filter (lambda (x)
                            (xetla-partner-create-menu
                             'xetla-inventory-replay)))
    ("Star-merge" :filter (lambda (x)
                            (xetla-partner-create-menu
                             'xetla-inventory-star-merge)))))

(defconst xetla-inventory-item-menu-list
  `("Inventory Item"
    ["Open File" xetla-inventory-find-file t]
    ["Redo"      xetla-inventory-redo      (xetla-inventory-maybe-undo-directory)]
    "--"
    ["Add"    xetla-inventory-add-files    t]
    ["Move"   xetla-inventory-move         t]
    ["Remove" xetla-inventory-remove-files t]
    ["Delete" xetla-inventory-delete-files t]
    "--"
    ["Make Junk"     xetla-inventory-make-junk     t]
    ["Make Precious" xetla-inventory-make-precious t]
    ,xetla-.arch-inventory-menu-list
    ,xetla-=tagging-method-menu-list)
  "Used both in the context and the global menu for inventory.")

(easy-menu-define xetla-inventory-mode-menu xetla-inventory-mode-map
  "`xetla-inventory-mode' menu"
  `("Inventory"
    ["Edit Log" xetla-inventory-edit-log t]
    "--"
    ["Show Changes"   xetla-inventory-changes t]
    ["Show Changelog" xetla-changelog t]
    ["Show Logs"      xetla-logs t]
    ["Show Missing"   xetla-inventory-missing t]
    "--"
    ,xetla-inventory-item-menu-list
    "--"
    ["Update"     xetla-inventory-update t]
    ["Replay"     xetla-inventory-replay t]
    ["Star-merge" xetla-inventory-star-merge t]
    ("Changesets"
     ["Save actual changes in directory" xetla-changes-save t]
     ["Save actual changes in tarball" xetla-changes-save-as-tgz t]
     ["View changeset from directory" xetla-show-changeset t]
     ["View changeset from tarball" xetla-show-changeset-from-tgz t]
     ["Apply changeset from directory" xetla-inventory-apply-changeset t]
     ["Apply changeset from tarball" xetla-inventory-apply-changeset-from-tgz t]
     )
    "--"
    ["Undo" xetla-inventory-undo t]
    ["Redo" xetla-inventory-redo t]
    "--"
    ["Synchronize Mirror" xetla-inventory-mirror t]
    ("Taging Method"
     ["Edit .arch-inventory" xetla-edit-.arch-inventory-file t]
     ["Edit =tagging-method" xetla-edit-=tagging-method-file t]
     ["Set Tagging Method"   xetla-generic-set-id-tagging-method t]
     ["Set Tree Version From Scratch" xetla-generic-set-tree-version t]
     )
    ["Tree-lint" xetla-tree-lint t]
    "--"
    ("Toggles"
     ["Set All Toggle Variables" xetla-inventory-set-all-toggle-variables t]
     ["Reset All Toggle Variables" xetla-inventory-reset-all-toggle-variables t]
     ["Toggle All Toggle Variables" xetla-inventory-toggle-all-toggle-variables t] .
     ,(mapcar '(lambda (elem) `[,(concat "Toggle " (car (cddddr elem)))
                                ,(caddr elem)
                                :style toggle
                                :selected ,(cadr elem)])
              xetla-inventory-file-types-manipulators))))

(easy-menu-define xetla-inventory-item-menu nil
  "Menu used on a inventory item."
  xetla-inventory-item-menu-list)

(easy-menu-define xetla-inventory-tagging-method-menu nil
  "Menu used on the taggine method line in a inventory buffer."
  '("Switch Taggine Method"
    ["Tagline"  (xetla-generic-set-id-tagging-method "tagline") t]
    ["Explicit" (xetla-generic-set-id-tagging-method "explicit") t]
    ["Names"    (xetla-generic-set-id-tagging-method "names") t]
    ["Implicit" (xetla-generic-set-id-tagging-method "implicit") t]))

;;
;; Cat-log mode
;;
(easy-menu-define xetla-cat-log-mode-menu xetla-cat-log-mode-map
  "'xetla-cat-log-mode' menu"
  '("Cat-Log"
    ["Inventory" xetla-pop-to-inventory t]
    ["Quit" xetla-buffer-quit t]
    ))

;;
;; Log edit mode
;;
(easy-menu-define xetla-log-edit-mode-menu xetla-log-edit-mode-map
  "`xetla-log-edit-mode' menu"
  '("Log"
    ["Insert xetla log-for-merge" xetla-log-edit-insert-log-for-merge t]
    ["log-for-merge and headers"
     xetla-log-edit-insert-log-for-merge-and-headers t]
    ["Insert memorized log"     xetla-log-edit-insert-memorized-log t]
    ["Show changes"             xetla-changes                       t]
    ["Commit"                   xetla-log-edit-done                 t]
    ["Show Changelog"           xetla-changelog                     t]
    ["Goto Summary Field"       xetla-log-goto-summary              t]
    ["Goto Body"                xetla-log-goto-body                 t]
    ["Edit Keywords Field"      xetla-log-edit-keywords             t]
    ["Kill Body"                xetla-log-kill-body                 t]
    ["Tree Lint"                xetla-tree-lint                     t]
    ["Abort"                    xetla-log-edit-abort                t]))

;;
;; Archive list mode
;;
(easy-menu-define xetla-archive-list-mode-menu xetla-archive-list-mode-map
  "`xetla-archive-list-mode' menu"
  '("Archives"
    ["Register New Archive"        xetla-register-archive t]
    ["Add a Bookmark"              xetla-bookmarks-add t]
    ["Update Archives List"        xetla-archives t]
    ["Set Default Archive"         xetla-archive-select-default t]
    ["Remove Archive Registration" xetla-archive-unregister-archive t]
    ["Edit Archive Location"       xetla-archive-edit-archive-location t]
    ["Make New Archive..."         xetla-make-archive t]
    ["Create a Mirror"             xetla-archive-mirror-archive t]
    ["Use as default Mirror"       xetla-archive-use-as-default-mirror t]
    ["Synchronize Mirror"          xetla-archive-synchronize-archive t]
    ))

;;
;; Category list mode
;;
(easy-menu-define xetla-category-list-mode-menu xetla-category-list-mode-map
  "`xetla-category-list-mode' menu"
  '("Categories"
    ["List Archives"          xetla-archives                t]
    ["Update Categories List" xetla-category-refresh         t]
    ["Make New Category..."   xetla-category-make-category  t]
    ["Add a Bookmark"         xetla-bookmarks-add           t]
    ["Synchronize Mirror"     xetla-category-mirror-archive t]
    ))


;;
;; Branch list mode
;;
(easy-menu-define xetla-branch-list-mode-menu xetla-branch-list-mode-map
  "`xetla-branch-list-mode' menu"
  '("Branches"
    ["Update Branches List" xetla-branch-refresh               t]
    ["List Parent Category" xetla-branch-list-parent-category t]
    ["Make New Branch..."   xetla-branch-make-branch          t]
    ["Synchronize Mirror"   xetla-branch-mirror-archive       t]
    ["Bookmark Branch under Point"    xetla-branch-bookmarks-add        t]
    ["Get..."               xetla-branch-get-branch           t]
    ))

;;
;; Version list mode
;;
(easy-menu-define xetla-version-list-mode-menu xetla-version-list-mode-map
  "`xetla-version-list-mode' menu"
  '("Versions"
    ["Update Versions List" xetla-version-refresh             t]
    ["Get..."               xetla-version-get-version        t]
    ["Make New Version..."  xetla-version-make-version       t]
    ["List Parent Branch"   xetla-version-list-parent-branch t]
    ["Synchronize Mirror"   xetla-version-mirror-archive     t]
    ["Bookmark Version under Point"    xetla-version-bookmarks-add      t]
    ["Tag This Version"     xetla-version-tag      t]))

;;
;; Revision list mode
;;
(easy-menu-define xetla-revision-list-mode-menu xetla-revision-list-mode-map
  "`xetla-revision-list-mode' menu"
  '("Revisions"
    ["Refresh Revisions List" xetla-generic-refresh t]
    ["List Parent Version"    xetla-revision-list-parent-version t]
    "--"
    ["Bookmark Revision under Point"      xetla-revision-bookmarks-add t]
    ("Mark"
     ["Mark Revision"   xetla-revision-mark-revision t]
     ["Unmark Revision" xetla-revision-unmark-revision t])
    "--"
    ["Show Log"                            xetla-revision-cat-log t]
    ["Unify Patch Logs with This Revision" xetla-revision-sync-tree t]
    ["View changeset"                      xetla-revision-changeset t]
    ("Delta"
     ["View"  (xetla-revision-delta t) t]
     ["Store to Directory" (xetla-revision-store-delta t) t])
    "--"
    ["Update" xetla-revision-update t]
    ("Replay"
     ["From Head Revision" xetla-revision-replay-version t]
     ["From Revision under Point" xetla-revision-replay t])
    ("Star-Merge"
     ["From Head Revision" xetla-revision-star-merge-version t]
     ["From Revision under Point" xetla-revision-star-merge t])
    ("Get"
     ["Get a Local Copy" xetla-revision-get-revision t]
     ["Make Cache"       xetla-revision-cache-revision t]
     ["Add to Library"   xetla-revision-add-to-library t])
    ("Tag "
     ["From Head Revision" xetla-revision-tag-from-head t]
     ["From Revision under Point" xetla-revision-tag-from-here t])
    ["Send comment to author" xetla-revision-send-comments t]
    "--"
    ("Filter Display"
     ["Date"    xetla-revision-toggle-date
      :style toggle :selected xetla-revisions-shows-date]
     ["Creator" xetla-revision-toggle-creator
      :style toggle :selected xetla-revisions-shows-creator]
     ["Summary" xetla-revision-toggle-summary
     :style toggle :selected xetla-revisions-shows-summary]
     ["Presence in Revlib" xetla-revision-toggle-library
     :style toggle :selected xetla-revisions-shows-library]
     ["Merged Patches"   xetla-revision-toggle-merges
     :style toggle :selected xetla-revisions-shows-merges]
     ["Patches Merging ..." xetla-revision-toggle-merged-by
      :style toggle :selected xetla-revisions-shows-merged-by])))

(easy-menu-define xetla-revision-revision-menu nil
  "Menu used on a revision item in `xetla-revision-list-mode' buffer"
  '("Revision"
     ["Show Log"        xetla-revision-cat-log t]
     ["Unify Patch Logs with This Revision" xetla-revision-sync-tree t]
     ["View changeset"  xetla-revision-changeset t]
     ["Set Bookmark"    xetla-revision-bookmarks-add t]
     ("Mark"
      ["Mark Revision"   xetla-revision-mark-revision t]
      ["Unmark Revision"   xetla-revision-unmark-revision t])
     ("Delta"
      ["In This Version"                     xetla-revision-delta t]
      ["With Revision in Another Archive"    xetla-revision-store-delta t])
     ("Merge"
      ["Star-Merge"   xetla-revision-star-merge t]
      ["Replay"       xetla-revision-replay t])
     ("Get"
      ["Get a Local Copy" xetla-revision-get-revision t]
      ["Make Cache"       xetla-revision-cache-revision t]
      ["Add to Library"   xetla-revision-add-to-library t])
     ["Send comment to author" xetla-revision-send-comments t]
     ["Tag from Here"      xetla-revision-tag-from-here]))

;;
;; Changes mode
;;
(defconst xetla-changes-file-menu-list
  '("File Changes"
    ["Jump to File"                   xetla-changes-jump-to-change t]
    ["Jump to Diffs"                  xetla-changes-diff-or-list   t]
    ["View Diff in Separate Buffer"   xetla-changes-diff           t]
    ["View Diff with Ediff"           xetla-changes-ediff          t]
    "--"
    ["Delete File"                    xetla-changes-rm             t]
    ["Revert File"                    xetla-changes-revert         t]
    )
  "Used both in the global and the context menu of `xetla-changes-mode'.")

(easy-menu-define xetla-changes-mode-menu xetla-changes-mode-map
  "`xetla-changes' menu"
  `("Changes"
    ["Refresh Buffer" xetla-generic-refresh t]
    ["Edit log before commit" xetla-changes-edit-log t]
    ["View other revisions" xetla-tree-revisions t]
    ,xetla-changes-file-menu-list
    ))

(easy-menu-define xetla-changes-file-menu nil
  "Menu used on a `xetla-changes' file"
  xetla-changes-file-menu-list)

;;
;; Lint mode
;;
(defconst xetla-tree-lint-file-menu-list
  `("File"
    ["Jump to File"  xetla-generic-find-file-at-point t]
    ("Mark"
     ["Mark File" xetla-tree-lint-mark-file t]
     ["Unmark File" xetla-tree-lint-unmark-file t])
    "--"
    ["Add File"      xetla-tree-lint-add-files        t]
    ["Delete File"   xetla-tree-lint-delete-files     t]
    ["Regenerate ID" xetla-tree-lint-regenerate-id    t]
    "--"
    ["Make Junk"     xetla-tree-lint-make-junk        t]
    ["Make Precious" xetla-tree-lint-make-precious     t]
    ,xetla-.arch-inventory-menu-list
    ,xetla-=tagging-method-menu-list
    )
  "Used both for context and global menu.")

(easy-menu-define xetla-tree-lint-file-menu nil
  "Menu used on files listed in `xetla-tree-lint'"
  xetla-tree-lint-file-menu-list
  )

(easy-menu-define xetla-tree-lint-mode-menu xetla-tree-lint-mode-map
  "`xetla-tree-lint' menu"
  `("Tree Lint"
    ["Refresh Buffer"         xetla-generic-refresh t]
    ,xetla-tree-lint-file-menu-list
    ))

;;
;; Event Log buffer
;;
(easy-menu-define xetla-log-buffer-mode-menu xetla-log-buffer-mode-map
  "`xetla-log-buffer' menu"
  '("Logs"
    ["Show Related Buffer" xetla-switch-to-related-buffer t]
    ["Show Output Buffer"  xetla-switch-to-output-buffer  t]
    ["Show Error Buffer"   xetla-switch-to-error-buffer   t]
    ))


;; --------------------------------------
;; User customization section
;; --------------------------------------


(defgroup xetla nil
  "Arch interface for emacs."
  :group 'tools
  :prefix "xetla-")


(defgroup xetla-inventory nil
  "This group contains items used in inventory mode."
  :group 'xetla)


(defgroup xetla-revisions nil
  "This group contains items used in revisions mode."
  :group 'xetla)


(defgroup xetla-file-actions nil
  "This group contains items manipulating finding, saving and reverting files."
  :group 'xetla)


(defgroup xetla-bindings nil
  "This group contains items related to key bindings."
  :group 'xetla)


(defgroup xetla-faces nil
  "This group contains faces defined for Xetla."
  :group 'xetla)


(defcustom xetla-prefix-key [(control x) ?T]
  "Prefix key for most xetla commands."
  :type '(choice (const [(control x) ?T])
                 (const [(control x) ?t])
                 (const [(control x) ?v])
                 (const [(control x) ?V])
                 (const [(control x) ?v ?t])
                 (sexp))
  :group 'xetla-bindings
  :set  (lambda (var value)
          (if (boundp var)
              (global-unset-key (symbol-value var)))
          (set var value)
          (global-set-key (symbol-value var) xetla-global-keymap)))


(global-set-key xetla-prefix-key xetla-global-keymap)


(defcustom xetla-tla-executable "tla"
  "*The name of the xetla executable."
  :type 'string
  :group 'xetla)


(defcustom xetla-diff-executable "diff"
  "*The name of the diff executable."
  :type 'string
  :group 'xetla)


(defcustom xetla-patch-executable "patch"
  "*The name of the patch executable."
  :type 'string
  :group 'xetla)


(defcustom xetla-highlight t
  "*Use highlighting for XEtla buffers."
  :type 'boolean
  :group 'xetla)


(defcustom xetla-install-command-help-system t
  "*Use f1 to display help for the actual function call during minibuffer input.
Note: this functionality is provided for all minibuffer prompts."
  :type 'boolean
  :group 'xetla)


(defcustom xetla-do-not-prompt-for-save nil
  "*Whether or not xetla will prompt before saving.

If non nil, xetla will not prompt you before saving buffers of the
working local tree."
  :type 'boolean
  :group 'xetla-file-actions)


(defcustom xetla-automatically-revert-buffers t
  "*Whether or not xetla will automatically revert buffers.

If non nil, xetla will automatically revert unmodified buffers after an
arch operation modifying the file."
  :type 'boolean
  :group 'xetla-file-actions)


(defcustom xetla-changes-recursive t
  "*Whether or not xetla will compute changes recursively.

If non nil, `xetla-changes' will be applied recursively to subprojects
of the current tree"
  :type 'boolean
  :group 'xetla)


(defcustom xetla-strict-commits nil
  "*If non-nil, commit operations are invoked with the -strict option."
  :type 'boolean
  :group 'xetla)


(defcustom xetla-commit-check-log-buffer-functions
  '(xetla-commit-check-empty-headers
    xetla-commit-check-empty-line
    xetla-commit-check-missing-space)
  "*List of functions to check the ++log.. buffer.

Each function is called, from the log buffer, with no argument. It
should raise an error if commit should be canceled."
  :type 'hook
  :group 'xetla)


(defcustom xetla-commit-headers-allowed-to-be-empty
  "^\\(Keywords\\)$"
  "*Headers allowed to be empty in the ++log.. buffer.

This should be a regexp matching the header names. Headers not
matching this regexp should not be empty when committing."
  :type 'string
  :group 'xetla)


(defcustom xetla-commit-fix-missing-space t
  "*Whether or not xetla will add missing spaces after header names.

If non-nil, missing spaces after a space will be inserted
automatically instead of raising an error when committing."
  :type 'boolean
  :group 'xetla)


(defcustom xetla-three-way-merge t
  "*If non-nil, star-merge operations are invoked with -three-way."
  :type 'boolean
  :group 'xetla)


(defcustom xetla-use-forward-option nil
  "*If non-nil, use the -forward option with commands that allow it."
  :type 'boolean
  :group 'xetla)


(defcustom xetla-use-skip-present-option nil
  "*If non-nil, use -skip-present with commands that allow it."
  :type 'boolean
  :group 'xetla)


(defun xetla-toggle-use-forward-option ()
  "Toggle the value of `xetla-use-forward-option'."
  (interactive)
  (setq xetla-use-forward-option (not xetla-use-forward-option)))


(defun xetla-toggle-use-skip-present-option ()
  "Toggle the value of `xetla-use-skip-present-option'."
  (interactive)
  (setq xetla-use-skip-present-option
        (not xetla-use-skip-present-option)))


(defun xetla-toggle-three-way-merge ()
  "Toggle the value of `xetla-three-way-merge'."
  (interactive)
  (setq xetla-three-way-merge (not xetla-three-way-merge)))


(defgroup xetla-bookmarks nil
  "xetla bookmarks allows you to save places (archive, category,
branch, version) in the archive that you use often. Try M-x
xetla-bookmarks RET to see."
  :group 'xetla)


(defcustom xetla-bookmarks-file-name "bookmarks.el"
  "*File in which xetla bookmarks will be saved.
The bookmark file is stored in the `xetla-config-directory'"
  :type 'file
  :group 'xetla-bookmarks)


(defcustom xetla-tag-function 'xetla-tag-uuid
  "Function called to generate the value of the arch-tag.

The function must take no argument, and return a string without a
final newline."
  :type '(choice (const xetla-tag-uuid)
                 (const xetla-tag-name-date-filename)
                 function)
  :group 'xetla)


(defcustom xetla-config-directory "~/.xetla/"
  "*Directory in which the xetla config files will be stored."
  :type 'directory
  :group 'xetla)


(defcustom xetla-log-library "~/.arch-log-library/"
  "*Directory in which the log library will be stored."
  :type 'directory
  :group 'xetla-internal)


(defcustom xetla-log-library-greedy t
  "*Whether log files are automatically saved in the log library.

If non-nil, then, whenever xetla needs to access a log file, this file
will be copied to the log library."
  :type 'boolean
  :group 'xetla-internal)


(defcustom xetla-cache-xetla-get-changeset 2
  "*Cache `xetla-get-changeset' calls.
When nil, don't cache.
When a number, cache only if the `xetla-get-changeset' call takes
more seconds than the number.
Otherwise don't cache the results.
The cache is kept only in RAM."
  :type 'integer
  :group 'xetla)


(defcustom xetla-bookmarks-cleanup-dont-prompt nil
  "*Whether xetla should prompt before cleaning a local tree.

non nil means `xetla-bookmarks-cleanup-local-trees' shouldn't prompt
before removing a local-tree"
  :type 'boolean
  :group 'xetla-bookmarks)


(defgroup xetla-internal nil
  "This group contains items used mainly for debugging."
  :group 'xetla)


(defcustom xetla-log-commands t
  "*Non nil means log all xetla commands in the buffer *xetla-log*."
  :type 'boolean
  :group 'xetla-internal)


(defcustom xetla-log-buffer " *xetla-log*"
  "*Name of the buffer in which xetla logs main events."
  :type 'string
  :group 'xetla-internal)


(defcustom xetla-switch-to-buffer-mode 'pop-to-buffer
  "*Mode for switching to xetla buffers.
Recommended settings are: 'pop-to-buffer, and 'show-in-other-window
and 'single-window"
  :type '(choice (const pop-to-buffer)
                 (const single-window)
                 (const dedicated-frame)
                 (const show-in-other-window))
  :group 'xetla)

(defcustom xetla-switch-to-changes-buffer nil
  "Switch to the changes buffer or stay in the current buffer."
  :type 'boolean
  :group 'xetla)


(defcustom xetla-read-project-tree-mode 'sometimes
  "*Mode for prompting project tree directories. Possible values are:

- always: When running a tla command requiring a tree, always prompt
  for it.

- sometimes: If a command is ran inside a project tree, the tree root
  is used. Otherwise, prompt.

- never: If a command is run inside a project tree, use the tree root.
  Othwise, raise an error."
  :type '(choice (const always)
                 (const sometimes)
                 (const never))
  :group 'xetla)


(defcustom xetla-read-directory-mode 'sometimes
  "*How prompting project directories should be done.

Works similarly to `xetla-read-project-tree-mode', but this one is used
for commands like `xetla-inventory' for which a subdirectory of a
project tree is accepted."
  :type '(choice (const always)
                 (const sometimes)
                 (const never))
  :group 'xetla)


(defcustom xetla-switch-to-buffer-first t
  "*Switch to newly created buffer on creation of buffers?

If non-nil, xetla commands implementing this feature will switch to the
newly created buffer when the command is called. Further (potentially
asynchronous) processes are run without modifying your
window-configuration. Otherwise, xetla will switch to the new buffer on
command completion."
  :type 'boolean
  :group 'xetla)


(defcustom xetla-buffer-quit-mode 'kill
  "*How *xetla-...* buffer should be killed.
If the value is 'kill, buffers are actually killed. Otherwise, just
burry them."
  :type '(choice (const kill)
                 (const burry))
  :group 'xetla)


(defcustom xetla-log-insert-last t
  "*If non-nil, insert changelog entries at the end of the log file."
  :type 'boolean
  :group 'xetla)


(defgroup xetla-hooks nil
  "This group contains hooks into xetla."
  :prefix "xetla-"
  :group 'xetla)


(defcustom xetla-archive-list-mode-hook nil
  "*Hooks run after switching to `xetla-archive-list-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-bookmarks-mode-hook nil
  "*Hooks run after switching to `xetla-bookmarks-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-branch-list-mode-hook nil
  "*Hooks run after switching to `xetla-branch-list-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-cat-log-mode-hook nil
  "*Hooks run after switching to `xetla-cat-log-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-category-list-mode-hook nil
  "*Hooks run after switching to `xetla-category-list-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-inventory-file-mode-hook nil
  "*Hooks run after switching to `xetla-inventory-file-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-inventory-mode-hook nil
  "*Hooks run after switching to `xetla-inventory-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-log-edit-mode-hook nil
  "*Hooks run after switching to `xetla-log-edit-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-logs-mode-hook nil
  "*Hooks run after switching to `xetla-logs-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-revision-list-mode-hook nil
  "*Hooks run after switching to `xetla-revision-list-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-version-list-mode-hook nil
  "*Hooks run after switching to `xetla-version-list-mode'."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-make-branch-hook nil
  "*Hooks run after making a branch."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-make-category-hook nil
  "*Hooks run after making a category."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-make-version-hook nil
  "*Hooks run after making a version."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-make-archive-hook nil
  "*Hooks run after creating a new archive."
  :type 'hook
  :group 'xetla-hooks)


(defcustom xetla-name-read-init-hook nil
  "*Hooks run when the control enters to `xetla-name-read'."
  :type 'hook
  :group 'xetla-hooks)

(defcustom xetla-name-read-final-hook nil
  "*Hooks run when the control leaves `xetla-name-read'.
The name read by `xetla-name-read' is passed to functions connected
to this hook as an argument."
  :type 'hook
  :group 'xetla-hooks)

(defcustom xetla-name-read-error-hook nil
  "*Hooks run when an error is occurred in `xetla-name-read'."
  :type 'hook
  :group 'xetla-hooks)

(defcustom xetla-follow-symlinks 'tree
  "*Follow symlinks of this type."
  :type '(choice (const :tag "None" nil)
                 (const :tag "Symlinks into an arch-managed tree" tree)
                 (const :tag "Symlinks to an arch-managed file" id))
  :group 'xetla-file-actions)

(defcustom xetla-follow-symlinks-mode 'follow
  "*Before following a symlink do this."
  :type '(choice (const :tag "Ask" ask)
                 (const :tag "Follow" follow)
                 (const :tag "Warn" warn))
  :group 'xetla-file-actions)

(defcustom xetla-use-arrow-keys-for-navigation nil
  "*Enable left/right for navigation.
This works best if `xetla-switch-to-buffer-mode' is set to 'single-window.

It enables binding for navigation allowing you to browse by only using the
cursor keys, which is much faster than n/p/return/^.  Use up/down to move to
an item, right to select it and left to go to its \"logical\" parent!

Got the idea?

See the variable `xetla-use-arrow-keys-for-navigation-list' for a list of
bindings that will be installed."
  :type '(choice (const :tag "Disabled" nil)
                 (const :tag "Enabled"  t)
                 (const :tag "Enabled with Shift" shift))
  :group 'xetla-bindings)

(defcustom xetla-revisions-shows-summary t
  "*Whether summary should be displayed for `xetla-revisions'."
  :type 'boolean
  :group 'xetla-revisions)

(defcustom xetla-revisions-shows-creator t
  "*Whether creator should be displayed for `xetla-revisions'."
  :type 'boolean
  :group 'xetla-revisions)

(defcustom xetla-revisions-shows-date t
  "*Whether date should be displayed for `xetla-revisions'."
  :type 'boolean
  :group 'xetla-revisions)

(defcustom xetla-revisions-shows-library t
  "*Display library information in revision lists.

If non-nil the presence of this revision in the library should be
displayed for `xetla-revisions'"
  :type 'boolean
  :group 'xetla-revisions)

(defcustom xetla-revisions-shows-merges nil
  "*Display merge information in revision lists.

If non-nil, the list of merged patches of this revision should be
displayed for `xetla-revisions'"
  :type 'boolean
  :group 'xetla-revisions)

(defcustom xetla-revisions-shows-merged-by t
  "*Display \"merged-by\" field in revision lists.

If non-nil the list of patches merged by this revision should be
displayed for `xetla-revisions'"
  :type 'boolean
  :group 'xetla-revisions)

;;; FIXME: This should be an alist of keyword . description, and
;;; both the keyword and its description should display in the
;;; *xetla-log-keywords* buffer.
(defcustom xetla-log-edit-keywords
  '("admin"				; Administrative changes
    "audit"				; Code clean up/audit
    "bugfix"				; The good ol' bug fix
    "build/compile"			; Compile-time related
    "compat"				; Compatibility changes
    "delete"				; File/dir deletion
    "docfix"				; More that just a typo
    "documentation"			; Writing documentation
    "enhancement"			; Extending existing features
    "internal"				; Changes that don't affect the user
    "linting"				; aka "admin", "audit", "whitespace"
    "merge"				; Merging in changes from other repo
    "newfeature"			; New features
    "newfile"				; New file/dir added to the repo
    "release"				; Changes involved with releases
    "rename"				; Rename file/dir/function/var etc
    "revert"				; Revert some previous changes
    "security"				; Security fixes
    "sync"				; Synching code (eg GNU/Emacs -> XEmacs)
    "trivial"				; Tiny fixes/changes
    "typo"				; Typographic changes
    "update"				; General updates
    "ui"				; User-interface related changes
    "user-visible"			; User-visible changes
    "warnfix"				; Build or run-time warning fixes
    "whitespace"			; Whitespace changes
    )
  "A list of keywords for the Keywords field of a log message."
  :type '(repeat (string))
  :group 'xetla)


(defcustom xetla-apply-patch-mapping nil
  "*Tree in which patches should be applied.

An alist of rules to match fully qualified revision names to target
directories.

That variable is used to offer a directory in `xetla-gnus-apply-patch'.
Example setting: '(((nil \"xetla\" nil nil nil) \"~/work/xetla/xetla\")))"
  :type '(repeat (cons :tag "Rule"
                       (cons :tag "Full revision (regexps)"
                        (choice (const nil) (regexp :tag "Archive"))
                        (cons
                         (choice (const nil) (regexp :tag "Category"))
                         (cons
                          (choice (const nil) (regexp :tag "Branch"))
                          (cons
                           (choice (const nil) (regexp :tag "Version"))
                           (cons (choice (const nil) (string :tag "Revision"))
                                 (const nil))))))
                  (cons (string :tag "tree") (const nil))))
  :group 'xetla)

;;
;; Tips
;;

(defgroup xetla-tips nil
  "\"Tip of the day\" feature for XEtla"
  :prefix "xetla-"
  :group 'xetla)


(defcustom xetla-tips-enabled t
  "*Set this to nil to disable tips."
  :type 'boolean
  :group 'xetla-tips)

;;
;; State
;;

(defgroup xetla-state nil
  "Saving XEtla's state between Emacs sessions."
  :prefix "xetla-"
  :group 'xetla)


(defcustom xetla-state-file-name "state.el"
  "*File in which xetla saves state variables between Emacs sessions.
The file is stored in the `xetla-config-directory'"
  :type 'file
  :group 'xetla-state)

(defcustom xetla-state-variables-list '(xetla-tips-number)
  "*List of variables to store in the state file `xetla-state-file-name'."
  :type '(repeat (symbol))
  :group 'xetla-state)


;; --------------------------------------
;; Face
;; --------------------------------------
(defface xetla-marked
  '((((class color) (background dark)) (:foreground "yellow"))
    (((class color) (background light)) (:foreground "magenta"))
    (t (:bold t)))
  "Face to highlight a marked entry in xetla buffers"
  :group 'xetla-faces)

(defface xetla-archive-name
  '((((class color) (background dark)) (:foreground "lightskyblue1"))
    (((class color) (background light)) (:foreground "blue4"))
    (t (:bold t)))
  "Face to highlight xetla archive names."
  :group 'xetla-faces)

(make-face 'xetla-source-archive-name
	   "Face to highlight xetla source archive names.")
(set-face-parent 'xetla-source-archive-name 'xetla-archive-name)

(make-face 'xetla-mirror-archive-name
	   "Face to highlight xetla mirror archive names.")
(set-face-parent 'xetla-mirror-archive-name 'xetla-archive-name)

(make-face 'xetla-category-name
	   "Face to highlight xetla category names.")
(set-face-parent 'xetla-category-name 'xetla-archive-name)

(make-face 'xetla-branch-name
	   "Face to highlight xetla branch names.")
(set-face-parent 'xetla-branch-name 'xetla-archive-name)

(make-face 'xetla-version-name
	   "Face to highlight xetla version names.")
(set-face-parent 'xetla-version-name 'xetla-archive-name)

(make-face 'xetla-revision-name
	   "Face to highlight xetla revision names.")
(set-face-parent 'xetla-revision-name 'xetla-archive-name)

(make-face 'xetla-local-directory
	   "Face to highlight xetla local directory.")
(set-face-parent 'xetla-local-directory 'xetla-archive-name)

(make-face 'xetla-buffer
	   "Face to highlight buffer names printed in xetla's buffer.")
(set-face-parent 'xetla-buffer 'xetla-archive-name)

(make-face 'xetla-tagging-method
	   "Face to highlight taggine methods.")
(set-face-parent 'xetla-tagging-method 'xetla-archive-name)

(make-face 'xetla-id
	   "Face to highlight an arch id.")
(set-face-parent 'xetla-id 'font-lock-keyword-face)

(defface xetla-separator
  '((((class color) (background dark))  (:underline t :bold t))
    (((class color) (background light)) (:underline t :bold t)))
  "Face to highlight separators."
  :group 'xetla-faces)

(make-face 'xetla-keyword
	   "Face to highlight keywords.")
(set-face-parent 'xetla-keyword 'font-lock-keyword-face)

(make-face 'xetla-comment
	   "Face to highlight comments.")
(set-face-parent 'xetla-comment 'font-lock-comment-face)

(make-face 'xetla-precious
	   "Face to highlight precious entries")
(set-face-parent 'xetla-precious 'font-lock-comment-face)

(make-face 'xetla-unrecognized
	   "Face to highlight unrecognized entries")
(set-face-parent 'xetla-unrecognized 'font-lock-warning-face)

(make-face 'xetla-duplicate
	   "Face to highlight files with duplicate IDs")
(set-face-parent 'xetla-duplicate 'font-lock-warning-face)

(make-face 'xetla-source
	   "Face to highlight source code entries")
(set-face-parent 'xetla-source 'font-lock-string-face)

(make-face 'xetla-junk
	   "Face to highlight junk entries")
(set-face-parent 'xetla-junk 'font-lock-function-name-face)

(make-face 'xetla-nested-tree
	   "Face to highlight nested trees")
(set-face-parent 'xetla-nested-tree 'font-lock-type-face)

(make-face 
 'xetla-to-add
 "Face to highlight a file that should probably be added to the archive.")
(set-face-parent 'xetla-to-add 'font-lock-comment-face)

(make-face 'xetla-broken-link
	   "Face to highlight a broken link")
(set-face-parent 'xetla-broken-link 'font-lock-warning-face)

(make-face 'xetla-unmerged
	   "Face to highlight unmerged patches")
(set-face-parent 'xetla-unmerged 'font-lock-keyword-face)

(make-face 'xetla-header
	   "Face to highlight header in log mode for example")
(set-face-parent 'xetla-header 'font-lock-function-name-face)

(make-face 'xetla-conflict
	   "Face to highlight conflicts")
(set-face-parent 'xetla-conflict 'font-lock-warning-face)

(make-face 'xetla-modified
	   "Face to highlight modified files")
(set-face-parent 'xetla-modified 'font-lock-function-name-face)

(make-face 'xetla-move
	   "Face to highlight moved files/directory")
(set-face-parent 'xetla-move 'font-lock-function-name-face)

(make-face 'xetla-deleted
	   "Face to highlight deleted files")
(set-face-parent 'xetla-deleted 'font-lock-warning-face)

(make-face 'xetla-added
	   "Face to highlight added files")
(set-face-parent 'xetla-added 'font-lock-warning-face)

(make-face 'xetla-meta-info
	   "Face to highlight files with meta-info changes")
(set-face-parent 'xetla-meta-info 'font-lock-comment-face)

(make-face 'xetla-messages
	   "Face to highlight messages in xetla buffers")
(set-face-parent 'xetla-messages 'font-lock-function-name-face)

(defface xetla-highlight
  '((((class color) (background dark)) (:background "darkblue"))
    (((class color) (background light)) (:background "gold")))
  "Face to use as an alternative to `highlight' face.
If there could be more than two highlighted things, the user will confuse.
In such case use this face."
  :group 'xetla-faces)

(defface xetla-mark
  '((((class color) (background dark)) (:foreground "green" :bold t))
    (((class color) (background light)) (:foreground "green3" :bold t))
    (t (:bold t)))
  "Xetla face used to highlight marked file indicator."
  :group 'xetla-faces)


;; --------------------------------------
;; Font lock keywords
;; --------------------------------------

;;
;; Inventory file mode
;;
(defvar xetla-inventory-file-font-lock-keywords
  '(
    ("^#.*$" . xetla-comment)
    ("^[ \t]*\\(backup\\|exclude\\|junk\\|precious\\|unrecognized\\|source\\)\\>[  ]*\\(.*\\)$"
     (1 font-lock-keyword-face)
     (2 font-lock-string-face))
    ("^[ \t]*\\(untagged-source\\)"
     (1 font-lock-builtin-face))
    ("^[ \t]*\\(untagged-source\\) \\(precious\\|source\\|backup\\|junk\\|unrecognized\\)\\>"
     (1 font-lock-builtin-face)
     (2 font-lock-keyword-face))
    ("^[ \t]*\\(explicit\\|tagline\\|names\\|implicit\\)\\>"
     (1 font-lock-builtin-face))
    )
  "Keywords in xetla-inventory-file mode.")

;;
;; Logs mode
;;
(defvar xetla-logs-font-lock-keywords
  '(("^[^ \t]*\\(base\\|patch\\|version\\(fix\\)?\\)-[0-9]+" .
     font-lock-function-name-face))
  "Keywords in xetla-logs-mode.")

;;
;; Changes mode
;;
(defvar xetla-changes-font-lock-keywords
  (append
   '(("^\\* looking for .* to compare with$" . font-lock-function-name-face)
     ("^\\* comparing to .*$" . font-lock-function-name-face)
     ("^\\* dir metadata changed$" . font-lock-function-name-face)
     ("^\\* file metadata changed$" . font-lock-function-name-face)
     ("^\\* modified files" . font-lock-function-name-face)
     ("^\\* added files" . font-lock-function-name-face)
     ("^\\* removed files" . font-lock-function-name-face)
     ("^ +-?-/ .*$" . xetla-meta-info)
     ("^ +- .*$" . xetla-meta-info)
     ("^ *T. .*$" . xetla-nested-tree))
   diff-font-lock-keywords)
  "Keywords in `xetla-changes' mode.")

;;
;; ChangeLog mode
;;
(defvar xetla-changelog-font-lock-keywords
  '(("    \\([^ ].+:\\)\n\\(.*$\\)" 
     (1 'xetla-keyword)
     (2 'change-log-acknowledgement-face))
    ("\t\\(patch-[0-9]+\\)" (1 'xetla-keyword))
    ("^#.*$" . xetla-comment)
    ("^\\sw.........[0-9:+ ]* GMT"
     (0 'change-log-date-face)
     ("\\([^<(]+?\\)[ \t]*[(<]\\([A-Za-z0-9_.-]+@[A-Za-z0-9_.-]+\\)[>)]" nil nil
      (1 'change-log-name-face)
      (2 'change-log-email-face)))
    ("^.*\\* \\([^ ,:([\n]+\\)"
     (1 'change-log-file-face)
     ("\\=, \\([^ ,:([\n]+\\)" nil nil (1 'change-log-file-face))
     ("\\= (\\([^) ,:\n]+\\)" nil nil (1 'change-log-list-face))
     ("\\=, *\\([^) ,:\n]+\\)" nil nil (1 'change-log-list-face)))
    ("^.*(\\([^) ,:\n]+\\)"
     (1 'change-log-list-face)
     ("\\=, *\\([^) ,:\n]+\\)" nil nil (1 'change-log-list-face)))
    ("\\[!?\\([^]\n]+\\)\\]\\(:\\| (\\)" (1 'change-log-conditionals-face))
    ("<\\([^>\n]+\\)>\\(:\\| (\\)" (1 'change-log-function-face))
    ("\\(^.*\\|  \\)\\(From\\|Patch\\(es\\)? by\\|Report\\(ed by\\| from\\)\\|Suggest\\(ed by\\|ion from\\)\\)"
     2 'change-log-acknowledgement-face))
  "Keywords in `xetla-changelog' mode.")

;;
;; Log edit mode
;;
(defvar xetla-log-edit-font-lock-keywords
  (append
   '(("^\\(Summary\\|Keywords\\): \\(.*$\\)"
      (1 'xetla-header)
      (2 'change-log-conditionals-face)))
   xetla-changelog-font-lock-keywords)
      
  "Keywords in xetla-log-edit mode.")

;;
;; Cat-Log mode
;;
(defvar xetla-cat-log-font-lock-keywords
  (append
   '(("^\\(Revision\\|Archive\\|Creator\\|Date\\|Standard-date\\|Modified-files\\|New-patches\\|Summary\\|Keywords\\|New-files\\|New-directories\\|Removed-files\\|Removed-directories\\|Renamed-files\\|Renamed-directories\\|Modified-directories\\|Removed-patches\\): \\(.*$\\)" 
      (1 'xetla-header)
      (2 'change-log-conditionals-face)))
   xetla-changelog-font-lock-keywords)
  "Keywords in `xetla-cat-log-mode'.")

;;
;; Tips mode
;;
(defvar xetla-tips-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map xetla-keyvec-quit 'xetla-buffer-quit)
    (define-key map xetla-keyvec-next 'xetla-tips-next-tip)
    (define-key map xetla-keyvec-previous 'xetla-tips-previous-tip)
    (define-key map [?c] 'xetla-tips-customize)
    map))


;; --------------------------------------
;; Auto-mode-alist entries
;; --------------------------------------
;;;###autoload(add-to-list 'auto-mode-alist '("/\\(=tagging-method\\|\\.arch-inventory\\)$" . xetla-inventory-file-mode))

;; --------------------------------------
;; Hooks into other packages and/or functions
;; --------------------------------------

;;
;; ediff
;;
(defvar xetla-ediff-keymap (copy-keymap xetla-global-keymap)
  "Global keymap used by XEtla in the ediff control buffer.")

(define-key xetla-ediff-keymap xetla-keyvec-log-entry 'xetla-ediff-add-log-entry)

(add-hook 'ediff-keymap-setup-hook
          #'(lambda ()
              (define-key ediff-mode-map xetla-prefix-key xetla-ediff-keymap)))

;;
;; find-file
;;
(add-hook 'find-file-hooks 'xetla-find-file-hook)

;; --------------------------------------
;; Enables arrow key navigation for left/right
;; --------------------------------------
(defvar xetla-use-arrow-keys-for-navigation-list
  '((xetla-inventory-mode-map right 'xetla-inventory-find-file)
    (xetla-inventory-mode-map left 'xetla-inventory-parent-directory)
    (xetla-archive-list-mode-map right 'xetla-archive-list-categories)
    (xetla-archive-list-mode-map left 'xetla-buffer-quit)
    (xetla-category-list-mode-map right 'xetla-category-list-branches)
    (xetla-category-list-mode-map left 'xetla-archives)
    (xetla-branch-list-mode-map right 'xetla-branch-list-versions)
    (xetla-branch-list-mode-map left 'xetla-branch-list-parent-category)
    (xetla-version-list-mode-map right 'xetla-version-list-revisions)
    (xetla-version-list-mode-map left 'xetla-version-list-parent-branch)
    (xetla-revision-list-mode-map left 'xetla-revision-list-parent-version)
    (xetla-revision-list-mode-map right 'xetla-revision-show-changeset)
    (xetla-changes-mode-map left 'xetla-changes-jump-to-change)
    (xetla-changes-mode-map right 'xetla-changes-view-source)
    (xetla-changelog-mode-map left 'xetla-buffer-quit)
    (xetla-process-buffer-mode-map left 'xetla-buffer-quit)
    (xetla-bookmarks-mode-map right 'xetla-bookmarks-inventory)
    ))

(defun xetla-use-arrow-keys-for-navigation (&optional uninstall)
  "Bind the left/right keys for navigation.

This function will be called automatically if variable
`xetla-use-arrow-keys-for-navigation' is non-nil.

If argument UNINSTALL is non-nil, undefine the keys instead of
defining it."
  (interactive "P")
  (let ((bl xetla-use-arrow-keys-for-navigation-list) b
        (m xetla-use-arrow-keys-for-navigation))
    (while bl
      (setq b (car bl)
            bl (cdr bl))
      (eval
       (append (list 'define-key
                     (car b))
               (cond ((eq nil m)
                      (list (vector (cadr b)) nil))
                     ((eq 'shift m)
                      (if uninstall
                          (list (vector (list 'shift (cadr b))) nil)
                        (list (vector (list 'shift (cadr b))) (caddr b))))
                     ((eq t m)
                      (if uninstall
                          (list (vector (cadr b)) nil)
                        (list (vector (cadr b)) (caddr b))))))))
    (if uninstall
        (message "%sleft/right bindings for xetla have been removed."
                 (if (eq 'shift m) "Shifted " ""))
      (message "%sleft/right bindings for xetla have been installed."
               (if (eq 'shift m) "Shifted " "")))))

;; install them if customized
(if xetla-use-arrow-keys-for-navigation
    (xetla-use-arrow-keys-for-navigation))

(provide 'xetla-defs)

;;; xetla-defs.el ends here
