Subject: Re: bug#30724: eshell: escaped tilde is not treated as such

From: Jonathan Kyle Mitchell <[email-masked]>
Date: Tue, 17 Jul 2018 22:54:27 -0500

On Mon, 2018-07-16 at 20:14 -0400, Noam Postavsky wrote:
> The "Add eshell-escape-special-filenames to symbol plist" should be
> coalesced, as in:

Done in the new attached patch.

> I'm not sure 'escaped' or 'eshell-escape-special-filenames' are
> really
> the right names here, as they're not actually indicating any
> escaping.
> Maybe the property should be something like 'eshell-filename-
> arguments'?

I changed the property name to eshell-filename-arguments.

> Comments should be capitalized and end with a period (I know the
> original didn't, but since we're updating the code, now is a good
> time
> to fix it).

Fixed both the original and new comment.

> It looks like this kind of escaping isn't actually needed for "*"
> which
> your previous patch mentioned.  Perhaps just check for "~"
> explicitly,
> rather than any single character filenames.  Or are there other
> examples
> besides "~" which need "./" to prevent interpretation?

I can't think of any other cases that would need to be check either, so
I changed to to just string-match "~" only.

--
Jonathan Kyle Mitchell

From 2b86bff2c3d62936fb53a5cb3540f86fcd920a84 Mon Sep 17 00:00:00 2001
From: Jonathan Kyle Mitchell <[email-masked]>
Date: Mon, 16 Jul 2018 21:46:20 -0500
Subject: [PATCH] Check for special filenames in eshell (Bug#30724)

	* lisp/eshell/esh-cmd.el (eshell-lisp-command): Check for "~"
	in lisp commands with the eshell-filename-arguments property
	(Bug#30724).

	* lisp/eshell/em-dirs.el (eshell/cd, eshell/pushd, eshell/popd):
	* lisp/eshell/em-ls.el (eshell/ls):
	* lisp/eshell/em-unix.el (eshell/rm, eshell/mkdir, eshell/rmdir):
	(eshell/mv, eshell/cp, eshell/ln, eshell/cat, eshell/du, eshell/diff):
	* lisp/eshell/esh-ext.el (eshell/addpath): Add
	eshell-filename-arguments to symbol plist.
---
 lisp/eshell/em-dirs.el |  3 +++
 lisp/eshell/em-ls.el   |  1 +
 lisp/eshell/em-unix.el | 10 +++++++
 lisp/eshell/esh-cmd.el | 59 ++++++++++++++++++++++++------------------
 lisp/eshell/esh-ext.el |  1 +
 5 files changed, 49 insertions(+), 25 deletions(-)

diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el
index ec380e6701..5180a0700d 100644
--- a/lisp/eshell/em-dirs.el
+++ b/lisp/eshell/em-dirs.el
@@ -407,6 +407,7 @@ eshell/cd
 	nil))))
 
 (put 'eshell/cd 'eshell-no-numeric-conversions t)
+(put 'eshell/cd 'eshell-filename-arguments t)
 
 (defun eshell-add-to-dir-ring (path)
   "Add PATH to the last-dir-ring, if applicable."
@@ -470,6 +471,7 @@ eshell/pushd
   nil)
 
 (put 'eshell/pushd 'eshell-no-numeric-conversions t)
+(put 'eshell/pushd 'eshell-filename-arguments t)
 
 ;;; popd [+n]
 (defun eshell/popd (&rest args)
@@ -500,6 +502,7 @@ eshell/popd
   nil)
 
 (put 'eshell/popd 'eshell-no-numeric-conversions t)
+(put 'eshell/pop 'eshell-filename-arguments t)
 
 (defun eshell/dirs (&optional if-verbose)
   "Implementation of dirs in Lisp."
diff --git a/lisp/eshell/em-ls.el b/lisp/eshell/em-ls.el
index 900b28905b..2b568a991a 100644
--- a/lisp/eshell/em-ls.el
+++ b/lisp/eshell/em-ls.el
@@ -334,6 +334,7 @@ eshell/ls
     (apply 'eshell-do-ls args)))
 
 (put 'eshell/ls 'eshell-no-numeric-conversions t)
+(put 'eshell/ls 'eshell-filename-arguments t)
 
 (declare-function eshell-glob-regexp "em-glob" (pattern))
 
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index a18fb85507..c912c15ac7 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -307,6 +307,7 @@ eshell/rm
    nil))
 
 (put 'eshell/rm 'eshell-no-numeric-conversions t)
+(put 'eshell/rm 'eshell-filename-arguments t)
 
 (defun eshell/mkdir (&rest args)
   "Implementation of mkdir in Lisp."
@@ -324,6 +325,7 @@ eshell/mkdir
    nil))
 
 (put 'eshell/mkdir 'eshell-no-numeric-conversions t)
+(put 'eshell/mkdir 'eshell-filename-arguments t)
 
 (defun eshell/rmdir (&rest args)
   "Implementation of rmdir in Lisp."
@@ -340,6 +342,7 @@ eshell/rmdir
    nil))
 
 (put 'eshell/rmdir 'eshell-no-numeric-conversions t)
+(put 'eshell/rmdir 'eshell-filename-arguments t)
 
 (defvar no-dereference)
 
@@ -524,6 +527,7 @@ eshell/mv
 			     eshell-mv-overwrite-files))))
 
 (put 'eshell/mv 'eshell-no-numeric-conversions t)
+(put 'eshell/mv 'eshell-filename-arguments t)
 
 (defun eshell/cp (&rest args)
   "Implementation of cp in Lisp."
@@ -561,6 +565,7 @@ eshell/cp
 			   eshell-cp-overwrite-files preserve)))
 
 (put 'eshell/cp 'eshell-no-numeric-conversions t)
+(put 'eshell/cp 'eshell-filename-arguments t)
 
 (defun eshell/ln (&rest args)
   "Implementation of ln in Lisp."
@@ -593,6 +598,7 @@ eshell/ln
 			     eshell-ln-overwrite-files))))
 
 (put 'eshell/ln 'eshell-no-numeric-conversions t)
+(put 'eshell/ln 'eshell-filename-arguments t)
 
 (defun eshell/cat (&rest args)
   "Implementation of cat in Lisp.
@@ -645,6 +651,7 @@ eshell/cat
      (setq eshell-ensure-newline-p nil))))
 
 (put 'eshell/cat 'eshell-no-numeric-conversions t)
+(put 'eshell/cat 'eshell-filename-arguments t)
 
 ;; special front-end functions for compilation-mode buffers
 
@@ -927,6 +934,8 @@ eshell/du
 	     (eshell-print (concat (eshell-du-size-string size)
 				   "total\n"))))))))
 
+(put 'eshell/du 'eshell-filename-arguments t)
+
 (defvar eshell-time-start nil)
 
 (defun eshell-show-elapsed-time ()
@@ -1029,6 +1038,7 @@ eshell/diff
   nil)
 
 (put 'eshell/diff 'eshell-no-numeric-conversions t)
+(put 'eshell/diff 'eshell-filename-arguments t)
 
 (defvar locate-history-list)
 
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index 61c0ebc71d..358f0f957e 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -1304,32 +1304,41 @@ eshell-lisp-command
   "Insert Lisp OBJECT, using ARGS if a function."
   (catch 'eshell-external               ; deferred to an external command
     (let* ((eshell-ensure-newline-p (eshell-interactive-output-p))
-	   (result
-	    (if (functionp object)
-		(progn
-		  (setq eshell-last-arguments args
-			eshell-last-command-name
-			(concat "#<function " (symbol-name object) ">"))
-		  ;; if any of the arguments are flagged as numbers
-		  ;; waiting for conversion, convert them now
-		  (unless (get object 'eshell-no-numeric-conversions)
-		    (while args
-		      (let ((arg (car args)))
-			(if (and (stringp arg)
-				 (> (length arg) 0)
-				 (not (text-property-not-all
-				       0 (length arg) 'number t arg)))
-			    (setcar args (string-to-number arg))))
-		      (setq args (cdr args))))
-		  (eshell-apply object eshell-last-arguments))
-	      (setq eshell-last-arguments args
-		    eshell-last-command-name "#<Lisp object>")
-	      (eshell-eval object))))
+           (result
+            (if (functionp object)
+                (progn
+                  (setq eshell-last-arguments args
+                        eshell-last-command-name
+                        (concat "#<function " (symbol-name object) ">"))
+                  (let ((numeric (not (get object
+                                           'eshell-no-numeric-conversions)))
+                        (fname-args (get object 'eshell-filename-arguments)))
+                    (when (or numeric fname-args)
+                      (while args
+                        (let ((arg (car args)))
+                          (cond ((and numeric (stringp arg) (> (length arg) 0)
+                                      (text-property-any 0 (length arg)
+                                                         'number t arg))
+                                 ;; If any of the arguments are
+                                 ;; flagged as numbers waiting for
+                                 ;; conversion, convert them now.
+                                 (setcar args (string-to-number arg)))
+                                ((and fname-args (stringp arg)
+                                      (string-equal arg "~"))
+                                 ;; If any of the arguments match "~",
+                                 ;; prepend "./" to treat it as a
+                                 ;; regular file name.
+                                 (setcar args (concat "./" arg)))))
+                        (setq args (cdr args)))))
+                  (eshell-apply object eshell-last-arguments))
+              (setq eshell-last-arguments args
+                    eshell-last-command-name "#<Lisp object>")
+              (eshell-eval object))))
       (if (and eshell-ensure-newline-p
-	       (save-excursion
-		 (goto-char eshell-last-output-end)
-		 (not (bolp))))
-	  (eshell-print "\n"))
+               (save-excursion
+                 (goto-char eshell-last-output-end)
+                 (not (bolp))))
+          (eshell-print "\n"))
       (eshell-close-handles 0 (list 'quote result)))))
 
 (defalias 'eshell-lisp-command* 'eshell-lisp-command)
diff --git a/lisp/eshell/esh-ext.el b/lisp/eshell/esh-ext.el
index ba5182deb4..244cc7ff1f 100644
--- a/lisp/eshell/esh-ext.el
+++ b/lisp/eshell/esh-ext.el
@@ -259,6 +259,7 @@ eshell/addpath
        (eshell-printn dir)))))
 
 (put 'eshell/addpath 'eshell-no-numeric-conversions t)
+(put 'eshell/addpath 'eshell-filename-arguments t)
 
 (defun eshell-script-interpreter (file)
   "Extract the script to run from FILE, if it has #!<interp> in it.
-- 
2.17.1