From 3b11e6ac60fa5c99b97fca3e588947e0b137a250 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Thu, 8 Nov 2012 10:10:08 -0500 Subject: [PATCH] * lisp/env.el (env--substitute-vars-regexp): New const. (substitute-env-vars): Use it. Add `only-defined' arg. * lisp/net/tramp.el (tramp-replace-environment-variables): Use it. --- lisp/ChangeLog | 4 ++++ lisp/env.el | 26 +++++++++++++------------- lisp/minibuffer.el | 8 ++++++++ lisp/net/tramp.el | 32 +++++++++++++++++++------------- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e44f1a7cdff..c040c71cbd4 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,5 +1,9 @@ 2012-11-08 Stefan Monnier + * env.el (env--substitute-vars-regexp): New const. + (substitute-env-vars): Use it. Add `only-defined' arg. + * net/tramp.el (tramp-replace-environment-variables): Use it. + * emacs-lisp/bytecomp.el (byte-compile-initial-macro-environment): Byte-compile *before* eval in eval-and-compile. (byte-compile-log-warning): Remove redundant inhibit-read-only. diff --git a/lisp/env.el b/lisp/env.el index d0d8ed0b998..f770dd27d75 100644 --- a/lisp/env.el +++ b/lisp/env.el @@ -57,31 +57,31 @@ If it is also not t, RET does not exit if it does non-null completion." ;; History list for VALUE argument to setenv. (defvar setenv-history nil) +(defconst env--substitute-vars-regexp + (rx "$" + (or (submatch-n 1 (1+ (regexp "[[:alnum:]_]"))) + (and "{" (submatch-n 1 (minimal-match (0+ anything))) "}") + "$"))) -(defun substitute-env-vars (string) +(defun substitute-env-vars (string &optional only-defined) "Substitute environment variables referred to in STRING. `$FOO' where FOO is an environment variable name means to substitute the value of that variable. The variable name should be terminated with a character not a letter, digit or underscore; otherwise, enclose the entire variable name in braces. For instance, in `ab$cd-x', `$cd' is treated as an environment variable. +If ONLY-DEFINED is nil, references to undefined environment variables +are replaced by the empty string; if it is non-nil, they are left unchanged. Use `$$' to insert a single dollar sign." (let ((start 0)) - (while (string-match - (eval-when-compile - (rx (or (and "$" (submatch (1+ (regexp "[[:alnum:]_]")))) - (and "${" (submatch (minimal-match (0+ anything))) "}") - "$$"))) - string start) + (while (string-match env--substitute-vars-regexp string start) (cond ((match-beginning 1) (let ((value (getenv (match-string 1 string)))) + (if (and (null value) only-defined) + (setq start (match-end 0)) (setq string (replace-match (or value "") t t string) - start (+ (match-beginning 0) (length value))))) - ((match-beginning 2) - (let ((value (getenv (match-string 2 string)))) - (setq string (replace-match (or value "") t t string) - start (+ (match-beginning 0) (length value))))) + start (+ (match-beginning 0) (length value)))))) (t (setq string (replace-match "$" t t string) start (+ (match-beginning 0) 1))))) @@ -185,7 +185,7 @@ VARIABLE should be a string. Value is nil if VARIABLE is undefined in the environment. Otherwise, value is a string. If optional parameter FRAME is non-nil, then it should be a -frame. This function will look up VARIABLE in its 'environment +frame. This function will look up VARIABLE in its `environment' parameter. Otherwise, this function searches `process-environment' for diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 38347f23f7d..6e704fad807 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -51,6 +51,9 @@ ;;; Todo: +;; - Make *Completions* readable even if some of the completion +;; entries have LF chars or spaces in them (including at +;; beginning/end) or are very long. ;; - for M-x, cycle-sort commands that have no key binding first. ;; - Make things like icomplete-mode or lightning-completion work with ;; completion-in-region-mode. @@ -74,6 +77,9 @@ ;; - whether the user wants completion to pay attention to case. ;; e.g. we may want to make it possible for the user to say "first try ;; completion case-sensitively, and if that fails, try to ignore case". +;; Maybe the trick is that we should distinguish completion-ignore-case in +;; try/all-completions (obey user's preference) from its use in +;; test-completion (obey the underlying object's semantics). ;; - add support for ** to pcm. ;; - Add vc-file-name-completion-table to read-file-name-internal. @@ -2048,6 +2054,8 @@ This is only used when the minibuffer area has no active minibuffer.") process-environment)) (defconst completion--embedded-envvar-re + ;; We can't reuse env--substitute-vars-regexp because we need to match only + ;; potentially-unfinished envvars at end of string. (concat "\\(?:^\\|[^$]\\(?:\\$\\$\\)*\\)" "$\\([[:alnum:]_]*\\|{\\([^}]*\\)\\)\\'")) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 874c0aa7fef..caaae5d553e 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -1748,20 +1748,26 @@ value of `default-file-modes', without execute permissions." (or (file-modes filename) (logand (default-file-modes) (tramp-compat-octal-to-decimal "0666")))) -(defun tramp-replace-environment-variables (filename) - "Replace environment variables in FILENAME. +(defalias 'tramp-replace-environment-variables + (if (ignore-errors + (equal "${ tramp?}" (substitute-env-vars "${ tramp?}" 'only-defined))) + (lambda (filename) + "Like `substitute-env-vars' with `only-defined' non-nil." + (substitute-env-vars filename 'only-defined)) + (lambda (filename) + "Replace environment variables in FILENAME. Return the string with the replaced variables." - (save-match-data - (let ((idx (string-match "$\\(\\w+\\)" filename))) - ;; `$' is coded as `$$'. - (when (and idx - (or (zerop idx) (not (eq ?$ (aref filename (1- idx))))) - (getenv (match-string 1 filename))) - (setq filename - (replace-match - (substitute-in-file-name (match-string 0 filename)) - t nil filename))) - filename))) + (save-match-data + (let ((idx (string-match "$\\(\\w+\\)" filename))) + ;; `$' is coded as `$$'. + (when (and idx + (or (zerop idx) (not (eq ?$ (aref filename (1- idx))))) + (getenv (match-string 1 filename))) + (setq filename + (replace-match + (substitute-in-file-name (match-string 0 filename)) + t nil filename))) + filename))))) ;; In XEmacs, electricity is implemented via a key map for ?/ and ?~, ;; which calls corresponding functions (see minibuf.el). -- 2.39.2