pcmpl-unix.el 7.48 KB
Newer Older
1
;;; pcmpl-unix.el --- standard UNIX completions
Gerd Moellmann's avatar
Gerd Moellmann committed
2

Paul Eggert's avatar
Paul Eggert committed
3
;; Copyright (C) 1999-2018 Free Software Foundation, Inc.
Gerd Moellmann's avatar
Gerd Moellmann committed
4

5 6
;; Package: pcomplete

Gerd Moellmann's avatar
Gerd Moellmann committed
7 8
;; This file is part of GNU Emacs.

9
;; GNU Emacs is free software: you can redistribute it and/or modify
Gerd Moellmann's avatar
Gerd Moellmann committed
10
;; it under the terms of the GNU General Public License as published by
11 12
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
Gerd Moellmann's avatar
Gerd Moellmann committed
13 14 15 16 17 18 19

;; GNU Emacs 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
20
;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
Gerd Moellmann's avatar
Gerd Moellmann committed
21

22 23
;;; Commentary:

Gerd Moellmann's avatar
Gerd Moellmann committed
24 25 26 27 28 29 30
;;; Code:

(require 'pcomplete)

;; User Variables:

(defcustom pcmpl-unix-group-file "/etc/group"
31 32
  "If non-nil, a string naming the group file on your system."
  :type '(choice file (const nil))
Gerd Moellmann's avatar
Gerd Moellmann committed
33 34 35
  :group 'pcmpl-unix)

(defcustom pcmpl-unix-passwd-file "/etc/passwd"
36 37
  "If non-nil, a string naming the passwd file on your system."
  :type '(choice file (const nil))
Gerd Moellmann's avatar
Gerd Moellmann committed
38 39
  :group 'pcmpl-unix)

40
(defcustom pcmpl-ssh-known-hosts-file "~/.ssh/known_hosts"
41
  "If non-nil, a string naming your SSH \"known_hosts\" file.
42 43 44 45 46
This allows one method of completion of SSH host names, the other
being via `pcmpl-ssh-config-file'.  Note that newer versions of
ssh hash the hosts by default, to prevent Island-hopping SSH
attacks.  This can be disabled, at some risk, with the SSH option
\"HashKnownHosts no\"."
47 48 49
  :type '(choice file (const nil))
  :group 'pcmpl-unix
  :version "23.1")
50

51 52 53 54 55 56 57 58
(defcustom pcmpl-ssh-config-file "~/.ssh/config"
  "If non-nil, a string naming your SSH \"config\" file.
This allows one method of completion of SSH host names, the other
being via `pcmpl-ssh-known-hosts-file'."
  :type '(choice file (const nil))
  :group 'pcmpl-unix
  :version "24.1")

Gerd Moellmann's avatar
Gerd Moellmann committed
59 60 61 62 63
;; Functions:

;;;###autoload
(defun pcomplete/cd ()
  "Completion for `cd'."
64
  (while (pcomplete-here (pcomplete-dirs))))
Gerd Moellmann's avatar
Gerd Moellmann committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

;;;###autoload
(defalias 'pcomplete/pushd 'pcomplete/cd)

;;;###autoload
(defun pcomplete/rmdir ()
  "Completion for `rmdir'."
  (while (pcomplete-here (pcomplete-dirs))))

;;;###autoload
(defun pcomplete/rm ()
  "Completion for `rm'."
  (let ((pcomplete-help "(fileutils)rm invocation"))
    (pcomplete-opt "dfirRv")
    (while (pcomplete-here (pcomplete-all-entries) nil
			   'expand-file-name))))

;;;###autoload
(defun pcomplete/xargs ()
  "Completion for `xargs'."
  (pcomplete-here (funcall pcomplete-command-completion-function))
  (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1))
	       pcomplete-default-completion-function)))

;;;###autoload
(defalias 'pcomplete/time 'pcomplete/xargs)

;;;###autoload
(defun pcomplete/which ()
  "Completion for `which'."
  (while (pcomplete-here (funcall pcomplete-command-completion-function))))

(defun pcmpl-unix-read-passwd-file (file)
98 99 100 101
  "Return an alist correlating gids to group names in FILE.

If FILE is in hashed format (as described in the OpenSSH
documentation), this function returns nil."
Gerd Moellmann's avatar
Gerd Moellmann committed
102 103 104 105 106 107 108 109 110 111 112 113
  (let (names)
    (when (file-readable-p file)
      (with-temp-buffer
	(insert-file-contents file)
	(goto-char (point-min))
	(while (not (eobp))
	  (let* ((fields
		  (split-string (buffer-substring
				 (point) (progn (end-of-line)
						(point))) ":")))
	    (setq names (cons (nth 0 fields) names)))
	  (forward-line))))
Paul Eggert's avatar
Paul Eggert committed
114
    (pcomplete-uniquify-list names)))
Gerd Moellmann's avatar
Gerd Moellmann committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

(defsubst pcmpl-unix-group-names ()
  "Read the contents of /etc/group for group names."
  (if pcmpl-unix-group-file
      (pcmpl-unix-read-passwd-file pcmpl-unix-group-file)))

(defsubst pcmpl-unix-user-names ()
  "Read the contents of /etc/passwd for user names."
  (if pcmpl-unix-passwd-file
      (pcmpl-unix-read-passwd-file pcmpl-unix-passwd-file)))

;;;###autoload
(defun pcomplete/chown ()
  "Completion for the `chown' command."
  (unless (pcomplete-match "\\`-")
    (if (pcomplete-match "\\`[^.]*\\'" 0)
	(pcomplete-here* (pcmpl-unix-user-names))
      (if (pcomplete-match "\\.\\([^.]*\\)\\'" 0)
	  (pcomplete-here* (pcmpl-unix-group-names)
			   (pcomplete-match-string 1 0))
	(pcomplete-here*))))
  (while (pcomplete-here (pcomplete-entries))))

;;;###autoload
(defun pcomplete/chgrp ()
  "Completion for the `chgrp' command."
  (unless (pcomplete-match "\\`-")
    (pcomplete-here* (pcmpl-unix-group-names)))
  (while (pcomplete-here (pcomplete-entries))))

145

146 147 148
;; ssh support by Phil Hagelberg.
;; http://www.emacswiki.org/cgi-bin/wiki/pcmpl-ssh.el

149
(defun pcmpl-ssh-known-hosts ()
150 151 152 153 154
  "Return a list of hosts found in `pcmpl-ssh-known-hosts-file'."
  (when (and pcmpl-ssh-known-hosts-file
             (file-readable-p pcmpl-ssh-known-hosts-file))
    (with-temp-buffer
      (insert-file-contents-literally pcmpl-ssh-known-hosts-file)
Mike Lamb's avatar
Mike Lamb committed
155 156 157 158 159
      (let ((host-re "\\(?:\\([-.[:alnum:]]+\\)\\|\\[\\([-.[:alnum:]]+\\)\\]:[0-9]+\\)[, ]")
            ssh-hosts-list)
        (while (re-search-forward (concat "^ *" host-re) nil t)
          (add-to-list 'ssh-hosts-list (concat (match-string 1)
                                               (match-string 2)))
160
          (while (and (eq (char-before) ?,)
Mike Lamb's avatar
Mike Lamb committed
161 162 163
                      (re-search-forward host-re (line-end-position) t))
            (add-to-list 'ssh-hosts-list (concat (match-string 1)
                                                 (match-string 2)))))
164
        ssh-hosts-list))))
165

166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
(defun pcmpl-ssh-config-hosts ()
  "Return a list of hosts found in `pcmpl-ssh-config-file'."
  (when (and pcmpl-ssh-config-file
             (file-readable-p pcmpl-ssh-config-file))
    (with-temp-buffer
      (insert-file-contents-literally pcmpl-ssh-config-file)
      (let (ssh-hosts-list
            (case-fold-search t))
        (while (re-search-forward "^ *host\\(name\\)? +\\([-.[:alnum:]]+\\)"
                                  nil t)
          (add-to-list 'ssh-hosts-list (match-string 2)))
        ssh-hosts-list))))

(defun pcmpl-ssh-hosts ()
  "Return a list of known SSH hosts.
Uses both `pcmpl-ssh-config-file' and `pcmpl-ssh-known-hosts-file'."
  (let ((hosts (pcmpl-ssh-known-hosts)))
    (dolist (h (pcmpl-ssh-config-hosts))
      (add-to-list 'hosts h))
    hosts))

187 188 189
;;;###autoload
(defun pcomplete/ssh ()
  "Completion rules for the `ssh' command."
190
  (pcomplete-opt "1246AaCfgKkMNnqsTtVvXxYbcDeFiLlmOopRSw")
191 192 193 194 195 196 197
  (pcomplete-here (pcmpl-ssh-hosts)))

;;;###autoload
(defun pcomplete/scp ()
  "Completion rules for the `scp' command.
Includes files as well as host names followed by a colon."
  (pcomplete-opt "1246BCpqrvcFiloPS")
198 199 200 201 202 203 204 205 206 207
  (while t (pcomplete-here
            (lambda (string pred action)
              (let ((table
                     (cond
                      ((string-match "\\`[^:/]+:" string) ; Remote file name.
		       (if (and (eq action 'lambda)
				(eq (match-end 0) (length string)))
			   ;; Avoid connecting to the remote host when we're
			   ;; only completing the host name.
			   (list string)
208 209
			 (completion-table-subvert (pcomplete-all-entries)
                                                   "" "/ssh:")))
210 211 212 213 214 215 216
                      ((string-match "/" string) ; Local file name.
                       (pcomplete-all-entries))
                      (t                ;Host name or local file name.
                       (append (all-completions string (pcomplete-all-entries))
                               (mapcar (lambda (host) (concat host ":"))
                                       (pcmpl-ssh-hosts)))))))
                (complete-with-action action table string pred))))))
217

218 219
(provide 'pcmpl-unix)

Gerd Moellmann's avatar
Gerd Moellmann committed
220
;;; pcmpl-unix.el ends here