]> git.eshelyaron.com Git - emacs.git/commitdiff
New electric forward slash Eshell module
authorSean Whitton <spwhitton@spwhitton.name>
Sat, 16 Apr 2022 15:23:14 +0000 (08:23 -0700)
committerSean Whitton <spwhitton@spwhitton.name>
Thu, 21 Apr 2022 18:57:12 +0000 (11:57 -0700)
* lisp/eshell/em-elecslash.el: New file.
* etc/NEWS:
* doc/misc/eshell.texi (Electric forward slash): Document the module.
(Make / electric): Retitle to "Make / more electric", update, add
"@noindent", and standardize terminology.

doc/misc/eshell.texi
etc/NEWS
lisp/eshell/em-elecslash.el [new file with mode: 0644]

index 411e69606992303a0201a8a6fba02437406c50ad..e539206166508ec9be4eca273afdf05124a094b0 100644 (file)
@@ -1560,6 +1560,7 @@ Eshell module.}  You also need to load the following as shown:
 * Key rebinding::
 * Smart scrolling::
 * Terminal emulation::
+* Electric forward slash::
 @end menu
 
 @node Writing a module
@@ -1592,6 +1593,61 @@ This section is not yet written.
 
 This section is not yet written.
 
+@node Electric forward slash
+@section Electric forward slash
+
+To help with supplying absolute file name arguments to remote
+commands, you can add the @code{eshell-elecslash} module to
+@code{eshell-modules-list}.  Then, typing @kbd{/} as the first
+character of a command line argument will automatically insert the
+Tramp prefix @file{/method:host:}.  If this is not what you want
+(e.g.@: because you want to refer to a local file), you can type
+another @kbd{/} to undo the automatic insertion.  Typing @kbd{~/} also
+inserts the Tramp prefix.  The automatic insertion applies only when
+@code{default-directory} is remote and the command is a Lisp function.
+In particular, typing arguments to external commands doesn't insert
+the prefix.
+
+The result is that in most cases of supplying absolute file name
+arguments to commands you should see the Tramp prefix inserted
+automatically only when that's what you'd reasonably expect.  This
+frees you from having to keep track of whether commands are Lisp
+functions or external when typing command line arguments.  For
+example, suppose you execute
+
+@example
+ cd /ssh:root@@example.com:
+ find /etc -name "*gnu*"
+@end example
+
+@noindent and in reviewing the output of the command, you identify a
+file @file{/etc/gnugnu} that should be moved somewhere else.  So you
+type
+
+@example
+ mv /etc/gnugnu /tmp
+@end example
+
+@noindent But since @command{mv} refers to the local Lisp function
+@code{eshell/mv}, not a remote shell command, to say this is to
+request that the local file @file{/etc/gnugnu} be moved into the local
+@file{/tmp} directory.  After you add @code{eshell-elecslash} to
+@code{eshell-modules-list}, then when you type the above @command{mv}
+invocation you will get the following input, which is what you
+intended:
+
+@example
+ mv /ssh:root@@example.com:/etc/gnugnu /ssh:root@@example.com:/tmp
+@end example
+
+The code that determines whether or not the Tramp prefix should be
+inserted uses simple heuristics.  A limitation of the current
+implementation is that it inspects whether only the command at the
+very beginning of input is a Lisp function or external program.  Thus
+when chaining commands with the operators @code{&&}, @code{||},
+@code{|} and @code{;}, the electric forward slash is active only
+within the first command.
+
 @node Bugs and ideas
 @chapter Bugs and ideas
 @cindex reporting bugs and ideas
@@ -1995,11 +2051,12 @@ only.  That way, it could be listed as a login shell.
 @item The first keypress after @kbd{M-x watson} triggers
 @code{eshell-send-input}
 
-@item Make @kbd{/} electric
+@item Make @kbd{/} more electric
 
-So that it automatically expands and corrects pathnames.  Or make
-pathname completion for Pcomplete auto-expand @samp{/u/i/std@key{TAB}} to
-@samp{/usr/include/std@key{TAB}}.
+@noindent so that it automatically expands and corrects file names,
+beyond what the @code{em-elecslash} module is able to do.  Or make
+file name completion for Pcomplete auto-expand
+@samp{/u/i/std@key{TAB}} to @samp{/usr/include/std@key{TAB}}.
 
 @item Write the @command{pushd} stack to disk along with @code{last-dir-ring}
 
index f8938534f39c03041fad10dc3bbad689d27bfe13..c0b9ce654e1ad18f5b1ad8b9e6de13d13ba37e0c 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1251,6 +1251,16 @@ support for pipelines which will move a lot of data.  See section
 "Running Shell Pipelines Natively" in the Eshell manual, node
 "(eshell) Input/Output".
 
++++
+*** New module to help supplying absolute file names to remote commands.
+After enabling the new 'eshell-elecslash' module, typing a forward
+slash as the first character of a command line argument will
+automatically insert the Tramp prefix.  The automatic insertion
+applies only when 'default-directory' is remote and the command is a
+Lisp function.  This frees you from having to keep track of whether
+commands are Lisp function or external when supplying absolute file
+name arguments.  See "Electric forward slash" in the Eshell manual.
+
 ** Miscellaneous
 
 +++
diff --git a/lisp/eshell/em-elecslash.el b/lisp/eshell/em-elecslash.el
new file mode 100644 (file)
index 0000000..091acb9
--- /dev/null
@@ -0,0 +1,120 @@
+;;; em-elecslash.el --- electric forward slashes  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author: Sean Whitton <spwhitton@spwhitton.name>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; 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
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Electric forward slash in remote Eshells.
+
+;;; Code:
+
+(require 'tramp)
+(require 'thingatpt)
+(require 'esh-cmd)
+(require 'esh-ext)
+(require 'esh-mode)
+
+;; This makes us an option when customizing `eshell-modules-list'.
+;;;###autoload
+(progn
+(defgroup eshell-elecslash nil
+  "Electric forward slash in remote Eshells.
+
+This module helps with supplying absolute file name arguments to
+remote commands.  After enabling it, typing a forward slash as
+the first character of a command line argument will automatically
+insert the Tramp prefix, /method:host:.  The automatic insertion
+applies only when `default-directory' is remote and the command
+is a Lisp function.
+
+The result is that in most cases of supplying absolute file name
+arguments to commands you should see the Tramp prefix inserted
+automatically only when that's what you'd reasonably expect.
+This frees you from having to keep track of whether commands are
+Lisp functions or external when typing command line arguments."
+  :tag "Electric forward slash"
+  :group 'eshell-module))
+
+;;; Functions:
+
+(defun eshell-elecslash-initialize () ;Called from `eshell-mode' via intern-soft!
+  "Initialize remote Eshell electric forward slash support."
+  (add-hook 'post-self-insert-hook
+            #'eshell-electric-forward-slash nil t))
+
+(defun eshell-electric-forward-slash ()
+  "Implementation of electric forward slash in remote Eshells.
+
+Initializing the `eshell-elecslash' module adds this function to
+`post-self-insert-hook'.  Typing / or ~/ as the first character
+of a command line argument automatically inserts the Tramp prefix
+in the case that `default-directory' is remote and the command is
+a Lisp function.  Typing a second forward slash undoes the
+insertion."
+  (when (eq ?/ (char-before))
+    (delete-char -1)
+    (let ((tilde-before (eq ?~ (char-before)))
+          (command (save-excursion
+                     (eshell-bol)
+                     (skip-syntax-forward " ")
+                     (thing-at-point 'sexp))))
+      (if (and (file-remote-p default-directory)
+               ;; We can't formally parse the input.  But if there is
+               ;; one of these operators behind us, then looking at
+               ;; the first command would not be sensible.  So be
+               ;; conservative: don't insert the Tramp prefix if there
+               ;; are any of these operators behind us.
+               (not (looking-back (regexp-opt '("&&" "|" ";"))
+                                  eshell-last-output-end))
+              (or (= (point) eshell-last-output-end)
+                  (and tilde-before
+                        (= (1- (point)) eshell-last-output-end))
+                  (and (or tilde-before
+                            (eq ?\s (char-syntax (char-before))))
+                       (or (eshell-find-alias-function command)
+                           (and (fboundp (intern-soft command))
+                                (or eshell-prefer-lisp-functions
+                                    (not (eshell-search-path command))))))))
+         (let ((map (make-sparse-keymap))
+               (start (if tilde-before (1- (point)) (point)))
+                (localname
+                 (tramp-file-name-localname
+                  (tramp-dissect-file-name default-directory))))
+           (when tilde-before (delete-char -1))
+           (insert
+             (substring default-directory 0
+                        (string-search localname default-directory)))
+           (unless tilde-before (insert "/"))
+           ;; Typing a second slash undoes the insertion, for when
+           ;; you really do want to type a local absolute file name.
+           (define-key map "/" (lambda ()
+                                 (interactive)
+                                 (delete-region start (point))
+                                 (insert (if tilde-before "~/" "/"))))
+           (set-transient-map map))
+        (insert "/")))))
+
+(provide 'em-elecslash)
+
+;; Local Variables:
+;; generated-autoload-file: "esh-groups.el"
+;; End:
+
+;;; esh-elecslash.el ends here