;;; p4-client-mode.el --- view all clients, and edit them ;; Author: Paul Du Bois ;; Maintainer: dubois@infinite-machine.com ;; $Id: //depot/tools/lisp/p4-client-mode.el#3 $ ;;; Commentary: ;; User entry points: ;; p4-clients ;; p4-edit-client ;;; Code: (require 'p4) (require 'p4-view) ;;; ---------------------------------------------------------------------- ;;; Viewing all clients (vcl = view clients) ;;; ---------------------------------------------------------------------- ;; Entry point (defun p4-clients () (interactive) (message "Finding clients...") (let ((old-buf (current-buffer)) (buf (get-buffer-create "*Clients*")) (inhibit-read-only t)) (p4-exec-p4-fast buf "clients") (set-buffer buf) (p4-vcl-cleanup-buffer) (p4-clients-mode) (p4-display-output buf) (select-window (get-buffer-window buf)) (message "Finding clients... done") (set-buffer old-buf))) ;; Keymaps (defvar p4-clients-column-map nil) (if p4-clients-column-map nil (let ((map (make-sparse-keymap))) ;;(set-keymap-parent map p4-clients-map) ;; [down-mouse-1] is normally mouse-drag-region, which does a track-mouse ;; and eats the click event. So we rebind it. (define-key map [down-mouse-1] 'mouse-set-point) (define-key map [mouse-1] 'p4-vcl-mouse-edit-client) (setq p4-clients-column-map map))) (defvar p4-clients-mode-map nil) (if p4-clients-mode-map nil (let ((map (make-keymap))) (suppress-keymap map) (define-key map "e" 'p4-vcl-edit-client) (define-key map "n" 'next-line) (define-key map "p" 'previous-line) (define-key map "q" 'p4-vcl-quit) (setq p4-clients-mode-map map))) (defun p4-vcl-cleanup-buffer () ;; Find lines like: ;; Client akira.main 1999/04/19 root e:\depot 'shwang's client. //d (goto-char (point-min)) (let* ((ws " \\([^ ]+\\)") (w " [^ ]+") (re (concat "^Client" ws w " root" w " '\\(.*\\)"))) (while (re-search-forward re nil 'move) (let ((client-name (match-string-no-properties 1)) (client-desc (match-string-no-properties 2)) replace-text) (save-match-data (if (string-match "'$" client-desc) (setq client-desc (replace-match "" t t client-desc))) (if (string-match ".*" client-desc) (setq client-desc (replace-match "" t t client-desc)))) (setq replace-text (format " %-15s %s" client-name (substring client-desc 0 (min (length client-desc) (- (window-width) 20))))) (put-text-property 2 17 'client client-name replace-text) (put-text-property 2 17 'mouse-face 'highlight replace-text) (put-text-property 2 17 'local-map p4-clients-column-map replace-text) (replace-match replace-text t t))) (set-buffer-modified-p nil))) (put 'p4-clients-mode 'mode-class 'special) (defun p4-clients-mode () "Major mode for examining a list of clients." (kill-all-local-variables) (use-local-map p4-clients-mode-map) (setq major-mode 'p4-clients-mode mode-name "P4-Clients" buffer-read-only t)) (defun p4-vcl-quit () (interactive) (kill-buffer (current-buffer))) (defun p4-vcl-edit-client () "Edit the client on the line at point" (interactive) (let (client) (beginning-of-line) (skip-chars-forward " \t") (setq client (get-text-property (point) 'client)) (if (null client) (error "No client defined at this point")) (p4-edit-client client))) (defun p4-vcl-mouse-edit-client (e) "Edit the client on the line at point" (interactive "e") (let ((beg (posn-point (event-start e))) (buf (get-buffer "*Shell Command Output*")) client) (setq client (get-text-property beg 'client)) (if (null client) (error "No client defined at this point")) (p4-edit-client client))) ;;; ---------------------------------------------------------------------- ;;; Editing a particular client (ecl = edit clients) ;;; ---------------------------------------------------------------------- (defun p4-edit-client (client) (interactive "sClient: ") (let ((buffer (p4-client-noselect client))) (and buffer (pop-to-buffer buffer)))) (defun p4-client-noselect (client) (let* ((buffer-name (format "*Perforce client %s*" client)) (client-buf (get-buffer-create buffer-name))) (p4-exec-p4-fast client-buf "client" "-o" client) (save-excursion (set-buffer client-buf) (goto-char (point-min)) (p4-client-mode client)) client-buf)) ;; XXX extract from buffer instead (defvar p4-client-mode-client nil) (make-variable-buffer-local 'p4-client-mode-client) (defvar p4-client-mode-map nil) (if p4-client-mode-map nil (let ((map (make-sparse-keymap))) (set-keymap-parent map p4-view-mode-map) (define-key map "\C-x\C-s" 'p4-ecl-save) ;; overrides the view toggle ;;(define-key map "\C-c\C-c" 'p4-ecl-save-and-exit) (setq p4-client-mode-map map))) (defun p4-client-mode (client) "A variant of `p4-view-mode' (which see)." (p4-view-mode) (setq p4-client-mode-client client major-mode 'p4-client-mode mode-name "P4-Client") (use-local-map p4-client-mode-map)) (defun p4-ecl-save () "Give the current buffer contents to Perforce via `| p4 client -i'" (interactive) (p4-ecl-save-low nil)) (defun p4-ecl-save-and-exit () "Give the current buffer contents to Perforce via `| p4 client -i'" (interactive) (p4-ecl-save-low 'exit)) (defun p4-ecl-save-low (&optional exit) "Give the current buffer contents to Perforce via `| p4 client -i'" (interactive) (if (not (buffer-modified-p)) (message "(No changes need to be saved)") (message "Saving client %s..." p4-client-mode-client) (condition-case nil (p4-view-uncompress) (error nil)) (p4-erase-buffer p4-output-buffer) (apply 'call-process-region (point-min) (point-max) p4-executable nil p4-output-buffer t '("client" "-i")) ;; Check result status ;; Client FOO saved|not changed. (let (new-client success success-msg) (save-excursion (set-buffer p4-output-buffer) (goto-char (point-min)) (if (looking-at "Client \\([^ ]+\\).*") (setq success t success-msg (match-string 0) new-client (match-string 1)))) ;; Refresh the buffer if successful (if success (progn (if exit (kill-buffer (current-buffer)) (let ((oline (1+ (count-lines 1 (save-excursion (beginning-of-line) (point))))) (ocol (current-column)) (wstart (window-start))) (p4-client-noselect new-client) (set-window-start (selected-window) wstart) (goto-line oline) (move-to-column ocol))) (message "%s" success-msg)) (p4-display-output p4-output-buffer))))) (provide 'p4-client-mode)