249 lines
11 KiB
EmacsLisp
249 lines
11 KiB
EmacsLisp
;;; dvc-status.el --- A generic status mode for DVC
|
|
|
|
;; Copyright (C) 2007 - 2009, 2011 by all contributors
|
|
|
|
;; Author: Stephen Leake, <stephen_leake@stephe-leake.org>
|
|
|
|
;; This file is free software; you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation; either version 3, or (at your option)
|
|
;; any later version.
|
|
|
|
;; This file is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with GNU Emacs; see the file COPYING. If not, write to
|
|
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
;; Boston, MA 02110-1301, USA.
|
|
|
|
;;; Commentary:
|
|
|
|
;;
|
|
|
|
;;; Code:
|
|
|
|
(require 'dvc-ui)
|
|
(require 'dvc-defs)
|
|
(require 'dvc-core)
|
|
(require 'dvc-fileinfo)
|
|
(require 'uniquify)
|
|
|
|
(defcustom dvc-status-display-known nil
|
|
"If non-nil, display files with 'known' status in dvc-status buffer."
|
|
:type 'boolean
|
|
:group 'dvc)
|
|
|
|
(defcustom dvc-status-display-ignored nil
|
|
"If non-nil, display files with 'ignored' status in dvc-status buffer."
|
|
:type 'boolean
|
|
:group 'dvc)
|
|
|
|
(defvar dvc-status-mode-map
|
|
(let ((map (make-sparse-keymap)))
|
|
;; grouped by major function, then alphabetical by dvc-keyvec name
|
|
;; workspace operations
|
|
(define-key map dvc-keyvec-add 'dvc-fileinfo-add-files)
|
|
(define-key map dvc-keyvec-commit 'dvc-log-edit)
|
|
(define-key map [?=] 'dvc-diff-diff)
|
|
(define-key map "E" 'dvc-fileinfo-toggle-exclude)
|
|
(define-key map "\M-e" 'dvc-edit-exclude)
|
|
(define-key map dvc-keyvec-ediff 'dvc-status-ediff)
|
|
(define-key map dvc-keyvec-help 'describe-mode)
|
|
(define-key map dvc-keyvec-logs 'dvc-log)
|
|
(define-key map "l" 'dvc-diff-log-single)
|
|
(define-key map "R" 'dvc-fileinfo-rename)
|
|
(define-key map "t" 'dvc-fileinfo-add-log-entry)
|
|
(define-key map dvc-keyvec-mark 'dvc-fileinfo-mark-file)
|
|
(define-key map dvc-keyvec-mark-all 'dvc-fileinfo-mark-all)
|
|
(define-key map dvc-keyvec-next 'dvc-fileinfo-next)
|
|
(define-key map dvc-keyvec-previous 'dvc-fileinfo-prev)
|
|
(define-key map dvc-keyvec-quit 'dvc-buffer-quit)
|
|
(define-key map dvc-keyvec-refresh 'dvc-generic-refresh)
|
|
(define-key map dvc-keyvec-revert 'dvc-fileinfo-revert-files)
|
|
(define-key map dvc-keyvec-unmark 'dvc-fileinfo-unmark-file)
|
|
(define-key map dvc-keyvec-unmark-all 'dvc-fileinfo-unmark-all)
|
|
(define-key map [?i] 'dvc-fileinfo-ignore-files)
|
|
(define-key map [?I] 'dvc-ignore-file-extensions-in-dir)
|
|
(define-key map "\M-I" 'dvc-ignore-file-extensions)
|
|
(define-key map (dvc-prefix-tagging-method ?e) 'dvc-edit-ignore-files)
|
|
(define-key map [?k] 'dvc-fileinfo-kill)
|
|
(define-key map dvc-keyvec-remove 'dvc-fileinfo-remove-files)
|
|
(define-key map "\r" 'dvc-find-file-other-window)
|
|
(define-key map "\M-d" 'dvc-status-dtrt)
|
|
|
|
;; database operations
|
|
(define-key map (dvc-prefix-merge ?u) 'dvc-update)
|
|
(define-key map (dvc-prefix-merge ?m) 'dvc-missing)
|
|
(define-key map (dvc-prefix-merge ?M) 'dvc-merge)
|
|
|
|
map)
|
|
"Keymap used in `dvc-status-mode'.")
|
|
|
|
(easy-menu-define dvc-status-mode-menu dvc-status-mode-map
|
|
"`dvc-status' menu"
|
|
`("DVC"
|
|
["Refresh Buffer" dvc-generic-refresh t]
|
|
["Edit log before commit" dvc-log-edit t]
|
|
["Quit" dvc-buffer-quit t]
|
|
("Merge/Update"
|
|
["Update" dvc-update t]
|
|
["Show missing" dvc-missing t]
|
|
["Merge" dvc-merge t]
|
|
)
|
|
("Mark"
|
|
["Mark File" dvc-fileinfo-mark-file t]
|
|
["Mark all" dvc-fileinfo-mark-all t]
|
|
["Unmark File" dvc-fileinfo-unmark-file t]
|
|
["Unmark all" dvc-fileinfo-unmark-all t]
|
|
)
|
|
("Ignore"
|
|
["Ignore Files" dvc-fileinfo-ignore-files t]
|
|
["Ignore Extensions in dir" dvc-ignore-file-extensions-in-dir t]
|
|
["Ignore Extensions globally" dvc-ignore-file-extensions t]
|
|
["Edit Ignore File" dvc-edit-ignore-files t]
|
|
)
|
|
("Exclude"
|
|
["Exclude File" dvc-fileinfo-toggle-exclude t]
|
|
["Edit Exclude File" dvc-edit-exclude t]
|
|
)
|
|
["Do the Right Thing" dvc-status-dtrt t]
|
|
["Add File" dvc-fileinfo-add-files t]
|
|
["Ediff File" dvc-status-ediff t]
|
|
["diff File" dvc-diff-diff t]
|
|
["Delete File" dvc-fileinfo-remove-files t]
|
|
["Kill File" dvc-fileinfo-kill t]
|
|
["Rename File" dvc-fileinfo-rename t]
|
|
["Revert File" dvc-fileinfo-revert-files t]
|
|
["Edit File" dvc-find-file-other-window t]
|
|
["Add log entry" dvc-fileinfo-add-log-entry t]
|
|
["Log (single file)" dvc-diff-log-single t]
|
|
["Log (full tree)" dvc-log t]
|
|
))
|
|
|
|
;; "<back-end>-status-mode", if defined, will be used instead of this
|
|
;; one. If so, it should be derived from dvc-status-mode (via
|
|
;; `define-derived-mode'), and rely on it for as many features as
|
|
;; possible (one can, for example, extend the menu and keymap).
|
|
;; Remember to add the new mode to uniquify-list-buffers-directory-modes
|
|
(define-derived-mode dvc-status-mode fundamental-mode "dvc-status"
|
|
"Major mode to display workspace status."
|
|
(setq dvc-buffer-current-active-dvc (dvc-current-active-dvc))
|
|
(setq dvc-fileinfo-ewoc (ewoc-create 'dvc-fileinfo-printer))
|
|
(set (make-local-variable 'dvc-get-file-info-at-point-function) 'dvc-fileinfo-current-file)
|
|
(use-local-map dvc-status-mode-map)
|
|
(easy-menu-add dvc-status-mode-menu)
|
|
(dvc-install-buffer-menu)
|
|
(setq buffer-read-only t)
|
|
(buffer-disable-undo)
|
|
(set-buffer-modified-p nil))
|
|
|
|
(add-to-list 'uniquify-list-buffers-directory-modes 'dvc-status-mode)
|
|
|
|
(defun dvc-status-prepare-buffer (dvc root base-revision branch header-more refresh)
|
|
"Prepare and return a status buffer. Should be called by <back-end>-dvc-status.
|
|
Calls <back-end>-status-mode.
|
|
DVC is back-end.
|
|
ROOT is absolute path to workspace.
|
|
BASE-REVISION is a string identifying the workspace's base revision.
|
|
BRANCH is a string identifying the workspace's branch.
|
|
HEADER-MORE is a function called to add other text to the ewoc header;
|
|
it should return a string.
|
|
REFRESH is a function that refreshes the status; see `dvc-buffer-refresh-function'."
|
|
|
|
(let ((status-buffer (dvc-get-buffer-create dvc 'status root)))
|
|
(dvc-kill-process-maybe status-buffer)
|
|
(with-current-buffer status-buffer
|
|
(let ((inhibit-read-only t)) (erase-buffer))
|
|
(let ((dvc-temp-current-active-dvc dvc))
|
|
(funcall (dvc-function dvc "status-mode")))
|
|
(let ((header (concat
|
|
(format "Status for %s:\n" root)
|
|
(format " base revision : %s\n" base-revision)
|
|
(format " branch : %s\n" branch)
|
|
(if (functionp header-more) (funcall header-more))))
|
|
(footer ""))
|
|
(set (make-local-variable 'dvc-buffer-refresh-function) refresh)
|
|
(ewoc-filter dvc-fileinfo-ewoc (lambda (elem) nil))
|
|
(ewoc-set-hf dvc-fileinfo-ewoc header footer)
|
|
(ewoc-enter-last dvc-fileinfo-ewoc (make-dvc-fileinfo-message :text (format "Running %s..." dvc)))
|
|
(ewoc-refresh dvc-fileinfo-ewoc)))
|
|
(dvc-switch-to-buffer-maybe status-buffer)))
|
|
|
|
(defun dvc-status-dtrt (prefix)
|
|
"Do The Right Thing in a status buffer; update, commit, resolve
|
|
conflicts, and/or ediff current files."
|
|
(interactive "P")
|
|
|
|
(let (status)
|
|
;; Note that message elements cannot be marked. Make sure all
|
|
;; selected files need the same action.
|
|
(if (< 1 (length (dvc-fileinfo-marked-files)))
|
|
(ewoc-map (lambda (fileinfo)
|
|
(etypecase fileinfo
|
|
(dvc-fileinfo-message
|
|
nil)
|
|
|
|
(dvc-fileinfo-file ; also matches dvc-fileinfo-dir
|
|
(if (dvc-fileinfo-file-mark fileinfo)
|
|
(if status
|
|
(if (not (equal status (dvc-fileinfo-file-status fileinfo)))
|
|
(error "cannot Do The Right Thing on files with different status"))
|
|
(setq status (dvc-fileinfo-file-status fileinfo))))
|
|
;; don't redisplay the element
|
|
nil)))
|
|
dvc-fileinfo-ewoc)
|
|
(setq status (dvc-fileinfo-file-status (dvc-fileinfo-current-fileinfo))))
|
|
|
|
(ecase status
|
|
(added
|
|
(dvc-fileinfo-add-log-entry prefix))
|
|
|
|
((deleted rename-source rename-target)
|
|
(dvc-status-ediff))
|
|
|
|
(missing
|
|
;; File is in database, but not in workspace
|
|
(ding)
|
|
(dvc-offer-choices (concat (dvc-fileinfo-current-file) " does not exist in working directory")
|
|
'((dvc-fileinfo-revert-files "revert")
|
|
(dvc-fileinfo-remove-files "remove")
|
|
(dvc-fileinfo-rename "rename"))))
|
|
|
|
(modified
|
|
;; Don't offer undo here; not a common action
|
|
;; Assume user has started the commit log frame
|
|
(if (< 1 (length (dvc-fileinfo-marked-files)))
|
|
(error "cannot diff more than one file"))
|
|
(dvc-status-ediff))
|
|
|
|
(unknown
|
|
(dvc-offer-choices nil
|
|
'((dvc-fileinfo-add-files "add")
|
|
(dvc-fileinfo-ignore-files "ignore")
|
|
(dvc-fileinfo-remove-files "remove")
|
|
(dvc-fileinfo-rename "rename"))))
|
|
)))
|
|
|
|
(defun dvc-status-inventory-done (status-buffer)
|
|
(with-current-buffer status-buffer
|
|
(ewoc-enter-last dvc-fileinfo-ewoc (make-dvc-fileinfo-message :text "Parsing inventory..."))
|
|
(ewoc-refresh dvc-fileinfo-ewoc)
|
|
(dvc-redisplay)
|
|
;; delete "running", "parsing" from the ewoc now, but don't
|
|
;; refresh until the status is displayed
|
|
(dvc-fileinfo-delete-messages)))
|
|
|
|
(defun dvc-status-ediff ()
|
|
"Run ediff on the current workspace file, against the database version."
|
|
(interactive)
|
|
;; FIXME: need user interface to specify other revision to diff
|
|
;; against. At least BASE and HEAD.
|
|
(let ((dvc-temp-current-active-dvc dvc-buffer-current-active-dvc))
|
|
(dvc-file-ediff (dvc-fileinfo-current-file))))
|
|
|
|
(provide 'dvc-status)
|
|
;;; end of file
|