home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / comp / emacs / 3849 < prev    next >
Encoding:
Text File  |  1992-12-22  |  8.5 KB  |  281 lines

  1. Newsgroups: comp.emacs
  2. Path: sparky!uunet!haven.umd.edu!darwin.sura.net!spool.mu.edu!agate!ames!network.ucsd.edu!news.service.uci.edu!ucivax!megatek!hollen
  3. From: hollen@megatek.UUCP (Dion Hollenbeck)
  4. Subject: Re: Environment variable expansion bug in file name completion
  5. In-Reply-To: tlp00@ras.amdahl.com's message of 22 Dec 92 01: 12:43 GMT
  6. Message-ID: <HOLLEN.92Dec22075123@peg.megatek.UUCP>
  7. Sender: hollen@megatek.com (Dion Hollenbeck)
  8. Organization: Megatek Corporation, San Diego, California
  9. References: <cdCB02Hq2fmj01@JUTS.ccc.amdahl.com>
  10. Date: Tue, 22 Dec 1992 15:51:23 GMT
  11. Lines: 268
  12.  
  13. >>>>> On 22 Dec 92 01:12:43 GMT, tlp00@ras.amdahl.com (Tibor Polgar) said:
  14.  
  15. Tibor> if i do a C-x C-f (M-x find-file) and type: 
  16.  
  17. Tibor>   Find file: $SRC<space>
  18.  
  19. Tibor> i would expect to see (assuming "setenv SRC /usr/project/src"):
  20.  
  21. Tibor>   Find file: /usr/project/src/
  22.  
  23. Tibor> but instead i get:
  24.  
  25. Tibor>   Find file: /
  26.  
  27. Tibor> BUT if i do:
  28. Tibor>   
  29. Tibor>    Find file: $SRC/foo.c
  30.  
  31. Tibor> All works fine, i edit file /usr/project/src/foo.c
  32.  
  33. Here is some source code which binds TAB to completion in both shell
  34. and mini-buffers and does what you want correctly.  Add the following
  35. line to your .emacs and have the included code availaible.
  36.  
  37. (load "file-complete" nil t nil)
  38.  
  39. ;;
  40. ;;  file-complete.el
  41. ;;
  42. ;; Code to do completion of $envvar and ~username, within shell buffers
  43. ;; or the minibuffer.
  44. ;; 
  45. ;; Copyright (C) 1991 Free Software Foundation, Inc.
  46. ;; 
  47. ;; This program is free software; you can redistribute it and/or modify
  48. ;; it under the terms of the GNU General Public License as published by
  49. ;; the Free Software Foundation; either version 1, or (at your option)
  50. ;; any later version.
  51. ;; 
  52. ;; This program is distributed in the hope that it will be useful,
  53. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  54. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  55. ;; GNU General Public License for more details.
  56. ;; 
  57. ;; You should have received a copy of the GNU General Public License
  58. ;; along with this program; if not, write to the Free Software
  59. ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  60. ;;
  61. ;; Written by eirik@theory.tn.cornell.edu.
  62. ;;(wmessage "In file-complete.el...") 
  63. (defvar passwd-use-yp nil
  64.   "*If t, do not read the passwd file directly")
  65.  
  66. (defvar shell-mode-hook
  67.   (function (lambda ()
  68.           (local-set-key "\^I" 'shell-expand-file-name))))
  69.  
  70. (or (fboundp 'read-file-name-internal-primitive)
  71.     (fset 'read-file-name-internal-primitive
  72.       (symbol-function 'read-file-name-internal)))
  73.   
  74. ;;  This is unnecessary with #define MAINTAIN_ENVIRONMENT
  75.  
  76. (if (boundp 'process-environment)
  77.     (or (fboundp 'getenv-primitive)
  78.     (progn
  79.       (fset 'getenv-primitive (symbol-function 'getenv))
  80.       (defun getenv (var)
  81.         "Return the value of environment variable VAR, or the entire environment if VAR is t"
  82.         (if (eq t var)
  83.         (if envvars envvars
  84.           (setq envvars
  85.             (mapcar
  86.              (function
  87.               (lambda (string)
  88.                 (let ((d (string-match "=" string)))
  89.                   (cons (substring string 0 d)
  90.                     (and d (substring string (1+ d)))))))
  91.              process-environment)))
  92.           (getenv-primitive var))))))
  93.  
  94. (defvar envvars nil
  95.   "A list of the environment variable names and values.")
  96.  
  97. ;; Might as well compute this at load time
  98. (getenv t)
  99.  
  100. (defun read-file-name-internal (name dir action)
  101.   "A replacement for the primitive read-file-name-internal that expands
  102. partial usernames and environment variable names.
  103.  
  104. NAME is the filename to complete; DIR is the directory to complete in.
  105. ACTION is nil to complete, t to return list of completions, lambda to
  106. verify final value."
  107.  
  108.     (let* ((buf (current-buffer))
  109.        (char (progn
  110.            (set-buffer (get-buffer-create " *read*"))
  111.            (erase-buffer)
  112.            (insert name)
  113.            (and (re-search-backward "[$~]" nil t)
  114.             (char-after (point)))))
  115.        (can (and char
  116.              (or (eq (point) (point-min))
  117.              (save-excursion (backward-char 1)
  118.                      (looking-at "/")))
  119.              (not (progn
  120.                 (forward-char 1)
  121.                 (save-excursion
  122.                   (re-search-forward "[^A-Za-z -]"
  123.                          (point-max) t))))
  124.              (buffer-substring (point) (point-max))))
  125.        (ignore (set-buffer buf)))
  126.       (if (null can) (read-file-name-internal-primitive name dir action)
  127.     (let ((prefix (substring name 0 (- (length name) (length can) 1))))
  128.       (cond
  129.        ((eq char ?~)
  130.         (let ((s (complete-username can nil action)))
  131.           (cond ((stringp s)
  132.              (concat "~" s
  133.                  (and
  134.                   (eq t (complete-username s nil action))
  135.                   (file-directory-p
  136.                    (expand-file-name (concat "~" s)))
  137.                   "/")))
  138.             ((eq t s) (concat name 
  139.                       (if (file-directory-p
  140.                        (expand-file-name name))
  141.                       "/")))
  142.             (t s))))
  143.        ((eq char ?$)
  144.         (let ((completion-list (all-completions can (getenv t))))
  145.           (cond
  146.            ((null action)
  147.         (let* ((un (and (eq (length completion-list) 1)
  148.                 (car completion-list)))
  149.                (unv (and un (getenv un)))
  150.                (dirp (and unv (> (length unv) 0)
  151.                   (file-directory-p unv))))
  152.           (if (and un (string-equal un can))
  153.               (concat prefix unv (if dirp "/"))
  154.             (let ((s (try-completion can (getenv t))))
  155.               (cond ((stringp s) (concat prefix "$" s
  156.                          (if dirp "/")))
  157.                 (t s))))))
  158.            ((eq t action) completion-list)
  159.            (t (eq 1 (length completion-list)))))))))
  160.       ))
  161.  
  162. (defun complete-username (string predicate flag)
  163.   "Use /etc/passwd to expand a ~."
  164.   (if (string-match ":" string) nil
  165.     (let ((pwbuf (get-file-buffer "/etc/passwd"))
  166.       (regexp (concat "^" string "."))
  167.       (buffer (current-buffer))
  168.       ret)
  169.       (cond (pwbuf
  170.          (set-buffer pwbuf)
  171.          (or passwd-use-yp
  172.          (verify-visited-file-modtime pwbuf)
  173.          (revert-buffer t t)))
  174.         (passwd-use-yp
  175.          (progn
  176.            (setq pwbuf (create-file-buffer "/etc/passwd"))
  177.            (set-buffer pwbuf)
  178.            (call-process "ypcat" nil pwbuf nil "passwd")
  179.            (set-visited-file-name "/etc/passwd")
  180.            (set-buffer-modified-p nil)))
  181.         (t
  182.          (setq pwbuf (create-file-buffer "/etc/passwd"))
  183.          (set-buffer pwbuf)
  184.          (insert-file-contents "/etc/passwd" t)))
  185.       (save-excursion
  186.     (goto-char (point-min))
  187.     (cond ((eq flag t)
  188.            (while (and flag (re-search-forward regexp nil t))
  189.          (let* ((start (progn
  190.                  (beginning-of-line 1)
  191.                  (point)))
  192.             (end (if (search-forward ":" nil t)
  193.                  (1- (point))
  194.                    (setq flag nil)))
  195.             (name (and start end
  196.                    (buffer-substring start end))))
  197.            (setq ret
  198.              (nconc ret
  199.                 (if predicate
  200.                     (if (funcall predicate name)
  201.                     (list name))
  202.                   (list name)))))))
  203.           ((not flag)
  204.            (setq ret
  205.              (let ((list
  206.                  (mapcar 'list
  207.                      (complete-username string nil t))))
  208.                 (let ((match
  209.                    (try-completion
  210.                     string
  211.                     (if list list (list nil)))))
  212.                   (or (and (eq (length list) 1)
  213.                        (complete-username string
  214.                               predicate
  215.                               'lambda))
  216.                   match)))))
  217.           (t
  218.            (and (re-search-forward (concat "^" string ":") nil t)
  219.             (setq ret t)))
  220.           ))
  221.       (set-buffer buffer)
  222.       ret)))
  223.  
  224. ;; Same, within shell buffers.  It is useful to bind this to a key,
  225. ;; e.g., TAB.
  226. ;; 
  227. (defun shell-expand-file-name ()
  228.   "Expand the file name before point"
  229.   (interactive)
  230.   (let* (
  231.      (line (save-excursion (beginning-of-line) (point)))
  232.      (base (or (save-excursion
  233.              (and (re-search-backward "[ /]" line t)
  234.               (point)))
  235.            (1- line)))
  236.      (dir (or (save-excursion
  237.             (and (search-backward " " line t)
  238.              (1+ (point))))
  239.           line))
  240.      (char (and dir (char-after dir)))
  241.      (dirname (and dir (or
  242.                 (and (eq char ?$)
  243.                  (let* ((s (save-excursion
  244.                          (goto-char dir)
  245.                          (search-forward "/" nil t)
  246.                          (point)))
  247.                     (d (and s (getenv
  248.                            (buffer-substring
  249.                             (1+ dir) (1- s))))))
  250.                    (and d (eq (aref d 0) ?/) 
  251.                     (concat d
  252.                         (buffer-substring (1- s) base)
  253.                         ))))
  254.                 (and (eq char ?/)
  255.                  (buffer-substring dir (1+ base)))
  256.                 (and (> base dir)
  257.                  (concat default-directory
  258.                      (buffer-substring dir base)))
  259.                 default-directory)))
  260.      (basename (and base (buffer-substring (1+ base) (point))))
  261.      (name (and basename dirname
  262.             (read-file-name-internal basename dirname nil)))
  263.      )
  264.     (cond
  265.      ((eq t name) (message "[Sole completion]"))
  266.      ((null name) (message "[No match]"))
  267.      ((string-equal name basename)
  268.       (with-output-to-temp-buffer "*Completions*"
  269.     (display-completion-list
  270.      (read-file-name-internal basename dirname t))))
  271.      (t (delete-region (1+ base) (point))
  272.     (insert name))
  273.      )))
  274.  
  275. ;; eof
  276.  
  277. -- 
  278. Dion Hollenbeck                        Email: hollen@megatek.com
  279. Senior Software Engineer                      megatek!hollen@uunet.uu.net
  280. Megatek Corporation, San Diego, California    ucsd!megatek.uucp!hollen
  281.