1;;; pcmpl-cvs.el --- functions for dealing with cvs completions
2
3;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
4;;   2005, 2006, 2007 Free Software Foundation, Inc.
5
6;; Author: John Wiegley <johnw@gnu.org>
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs; see the file COPYING.  If not, write to the
22;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23;; Boston, MA 02110-1301, USA.
24
25;;; Commentary:
26
27;; These functions provide completion rules for the `cvs' tool.
28
29;;; Code:
30
31(provide 'pcmpl-cvs)
32
33(require 'pcomplete)
34(require 'executable)
35
36(defgroup pcmpl-cvs nil
37  "Functions for dealing with CVS completions."
38  :group 'pcomplete)
39
40;; User Variables:
41
42(defcustom pcmpl-cvs-binary (or (executable-find "cvs") "cvs")
43  "*The full path of the 'cvs' binary."
44  :type 'file
45  :group 'pcmpl-cvs)
46
47;; Functions:
48
49;;;###autoload
50(defun pcomplete/cvs ()
51  "Completion rules for the `cvs' command."
52  (let ((pcomplete-help "(cvs)Invoking CVS"))
53    (pcomplete-opt "HQqrwlntvfab/T/e*d/z?s")
54    (pcomplete-here* (pcmpl-cvs-commands))
55    (cond ((pcomplete-test "add")
56	   (setq pcomplete-help "(cvs)Adding files")
57	   (pcomplete-opt "k?m?")
58	   (while (pcomplete-here (pcmpl-cvs-entries '(??)))))
59	  ((pcomplete-test "remove")
60	   (setq pcomplete-help "(cvs)Removing files")
61	   (pcomplete-opt "flR")
62	   (while (pcomplete-here (pcmpl-cvs-entries '(?U)))))
63	  ((pcomplete-test "init")
64	   (setq pcomplete-help "(cvs)Creating a repository"))
65	  ((pcomplete-test '("login" "logout"))
66	   (setq pcomplete-help "(cvs)Password authentication client"))
67	  ((pcomplete-test "import")
68	   (setq pcomplete-help "(cvs)import")
69	   (pcomplete-opt "dk?I(pcmpl-cvs-entries '(??))b?m?W?"))
70	  ((pcomplete-test "checkout")
71	   (setq pcomplete-help "(cvs)checkout")
72	   (pcomplete-opt "ANPRcflnpsr?D?d/k?j?")
73	   (pcomplete-here (pcmpl-cvs-modules)))
74	  ((pcomplete-test "rtag")
75	   (setq pcomplete-help "(cvs)Creating a branch")
76	   (pcomplete-opt "aflRndbr?DF")
77	   (pcomplete-here (pcmpl-cvs-modules)))
78	  ((pcomplete-test "release")
79	   (setq pcomplete-help "(cvs)release")
80	   (pcomplete-opt "d")
81	   (while (pcomplete-here (pcomplete-dirs))))
82	  ((pcomplete-test "export")
83	   (setq pcomplete-help "(cvs)export")
84	   (pcomplete-opt "NflRnr?D?d/k?")
85	   (pcomplete-here (pcmpl-cvs-modules)))
86	  ((pcomplete-test "commit")
87	   (setq pcomplete-help "(cvs)commit files")
88	   (pcomplete-opt "nRlfF.m?r(pcmpl-cvs-tags '(?M ?R ?A))")
89	   (while (pcomplete-here (pcmpl-cvs-entries '(?M ?R ?A)))))
90	  ((pcomplete-test "diff")
91	   (setq pcomplete-help "(cvs)Viewing differences")
92	   (let ((opt-index pcomplete-index)
93		 saw-backdate)
94	     (pcomplete-opt "lRD?Nr(pcmpl-cvs-tags)")
95	     (while (< opt-index pcomplete-index)
96	       (if (pcomplete-match "^-[Dr]" (- pcomplete-index opt-index))
97		   (setq saw-backdate t opt-index pcomplete-index)
98		 (setq opt-index (1+ opt-index))))
99	     (while (pcomplete-here
100		     (pcmpl-cvs-entries (unless saw-backdate '(?M)))))))
101	  ((pcomplete-test "unedit")
102	   (setq pcomplete-help "(cvs)Editing files")
103	   (pcomplete-opt "lR")
104	   (while (pcomplete-here (pcmpl-cvs-entries '(?M ?R ?A)))))
105	  ((pcomplete-test "update")
106	   (setq pcomplete-help "(cvs)update")
107	   (pcomplete-opt
108	    (concat "APdflRpk?r(pcmpl-cvs-tags '(?U ?P))D?"
109		    "j(pcmpl-cvs-tags '(?U ?P))"
110		    "I(pcmpl-cvs-entries '(??))W?"))
111	   (while (pcomplete-here (pcmpl-cvs-entries '(?U ?P)))))
112	  (t
113	   (while (pcomplete-here (pcmpl-cvs-entries)))))))
114
115(defun pcmpl-cvs-commands ()
116  "Return a list of available CVS commands."
117  (with-temp-buffer
118    (call-process pcmpl-cvs-binary nil t nil "--help-commands")
119    (goto-char (point-min))
120    (let (cmds)
121      (while (re-search-forward "^\\s-+\\([a-z]+\\)" nil t)
122	(setq cmds (cons (match-string 1) cmds)))
123      (pcomplete-uniqify-list cmds))))
124
125(defun pcmpl-cvs-modules ()
126  "Return a list of available modules under CVS."
127  (with-temp-buffer
128    (call-process pcmpl-cvs-binary nil t nil "checkout" "-c")
129    (goto-char (point-min))
130    (let (entries)
131      (while (re-search-forward "\\(\\S-+\\)$" nil t)
132	(setq entries (cons (match-string 1) entries)))
133      (pcomplete-uniqify-list entries))))
134
135(defun pcmpl-cvs-tags (&optional opers)
136  "Return all the tags which could apply to the files related to OPERS."
137  (let ((entries (pcmpl-cvs-entries opers))
138	tags)
139    (with-temp-buffer
140      (apply 'call-process pcmpl-cvs-binary nil t nil
141	     "status" "-v" entries)
142      (goto-char (point-min))
143      (while (re-search-forward "Existing Tags:" nil t)
144	(forward-line)
145	(while (not (looking-at "^$"))
146	  (unless (looking-at "^\\s-+\\(\\S-+\\)\\s-+")
147	    (error "Error in output from `cvs status -v'"))
148	  (setq tags (cons (match-string 1) tags))
149	  (forward-line))))
150    (pcomplete-uniqify-list tags)))
151
152(defun pcmpl-cvs-entries (&optional opers)
153  "Return the Entries for the current directory.
154If OPERS is a list of characters, return entries for which that
155operation character applies, as displayed by 'cvs -n update'."
156  (let* ((arg (pcomplete-arg))
157	 (dir (file-name-as-directory
158	       (or (file-name-directory arg) "")))
159	 (nondir (or (file-name-nondirectory arg) ""))
160	 entries)
161    (if opers
162	(with-temp-buffer
163	  (and dir (cd dir))
164	  (call-process pcmpl-cvs-binary nil t nil
165			"-q" "-n" "-f" "update"); "-l")
166	  (goto-char (point-min))
167	  (while (re-search-forward "^\\(.\\) \\(.+\\)$" nil t)
168	    (if (memq (string-to-char (match-string 1)) opers)
169		(setq entries (cons (match-string 2) entries)))))
170      (with-temp-buffer
171	(insert-file-contents (concat dir "CVS/Entries"))
172	(goto-char (point-min))
173	(while (not (eobp))
174	  (let* ((line (buffer-substring (line-beginning-position)
175					 (line-end-position)))
176		 (fields (split-string line "/"))
177		 text)
178	    (if (eq (aref line 0) ?/)
179		(setq fields (cons "" fields)))
180	    (setq text (nth 1 fields))
181	    (when text
182	      (if (string= (nth 0 fields) "D")
183		  (setq text (file-name-as-directory text)))
184	      (setq entries (cons text entries))))
185	  (forward-line))))
186    (setq pcomplete-stub nondir)
187    (pcomplete-uniqify-list entries)))
188
189;;; arch-tag: d2aeac43-4bf5-4509-a496-74b863c6642b
190;;; pcmpl-cvs.el ends here
191