unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Sean Whitton <spwhitton@spwhitton.name>
To: emacs-devel@gnu.org, Philip Kaludercic <philipk@posteo.net>
Subject: New optional Eshell module: em-elecslash
Date: Sat, 16 Apr 2022 11:57:55 -0700	[thread overview]
Message-ID: <87k0bokg98.fsf@melete.silentflame.com> (raw)
In-Reply-To: <87r18qu5e1.fsf@posteo.net>

[-- Attachment #1: Type: text/plain, Size: 519 bytes --]

Hello,

On Sat 29 Jan 2022 at 11:51AM GMT, Philip Kaludercic wrote:

> Sean Whitton <spwhitton@spwhitton.name> writes:
>
>> Hello,
>>
>> I have a useful Eshell thing that I would like to make more broadly
>> available but which should definitely not be turned on by default.  The
>> final implementation will be as an Eshell module which makes an addition
>> to post-self-insert-hook.
>
> Could you give any details on what the feature is?

Here is my new module, which I'd like to install on master.

-- 
Sean Whitton

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-New-electric-forward-slash-Eshell-module.patch --]
[-- Type: text/x-patch, Size: 9006 bytes --]

From c915c51cd32b6354b951f10fb4d2d3666b3480d2 Mon Sep 17 00:00:00 2001
From: Sean Whitton <spwhitton@spwhitton.name>
Date: Sat, 16 Apr 2022 08:23:14 -0700
Subject: [PATCH] New electric forward slash Eshell module

* lisp/eshell/em-elecslash.el: New module.
* etc/NEWS:
* doc/misc/eshell.texi (Electric forward slash): Document the module.
---
 doc/misc/eshell.texi        |  59 +++++++++++++++++++
 etc/NEWS                    |   8 +++
 lisp/eshell/em-elecslash.el | 113 ++++++++++++++++++++++++++++++++++++
 3 files changed, 180 insertions(+)
 create mode 100644 lisp/eshell/em-elecslash.el

diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index 372e4c3ffb..61db05c4e3 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -1241,6 +1241,7 @@ Extension modules
 * Key rebinding::
 * Smart scrolling::
 * Terminal emulation::
+* Electric forward slash::
 @end menu
 
 @node Writing a module
@@ -1273,6 +1274,64 @@ Terminal emulation
 
 This section is not yet written.
 
+@node Electric forward slash
+@section Electric forward slash
+
+This optional module tries to help with passing absolute paths to
+commands when @code{default-directory} is remote.  When using Eshell's
+Tramp support, it is easy to accidentally refer to a local path when
+you meant a remote path.  The problem arises because absolute paths
+passed to Lisp functions must have Tramp's @code{/method:host:}
+prefix, but absolute paths passed to external commands must not have
+this prefix.  Typically, one does not think about whether a command is
+a Lisp function or an external command while inputting 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 @code{/etc/gnugnu} that should be moved somewhere else.  So you
+type
+
+@example
+ mv /etc/gnugnu /tmp
+@end example
+
+@noindent But since @code{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 @code{/etc/gnugnu} be moved into the local
+@code{/tmp} directory.  What you should have typed is
+
+@example
+ mv /ssh:root@@example.com:/etc/gnugnu /ssh:root@@example.com:/tmp
+@end example
+
+@noindent but it is easy to forget to do that, and it takes much
+longer to type.
+
+If the @code{eshell-elecslash} module has been added to
+@code{eshell-modules-list}, and @code{default-directory} is remote,
+then when you type the first forward slash of an argument to a Lisp
+function, the Tramp prefix will be filled in for you.  A second
+forward slash can be used to undo the insertion, for when you really
+do want to pass a local absolute path, such as when you want to copy a
+remote file to the local machine.  And when typing arguments to
+external commands, the Tramp prefix is not filled in.  The result is
+that you don't have to think about inserting the Tramp prefix and can
+just type absolute paths in the same way for both types of command.
+The Tramp prefix is additionally filled in when you type @code{~/}.
+
+The code that determines whether or not the Tramp prefix should be
+inserted uses simple heuristics.  A limitation of the current
+implementation is that only the status as Lisp function or external
+program of the command at the very beginning of input can be
+considered.  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
diff --git a/etc/NEWS b/etc/NEWS
index 79c27da549..696c3ff844 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1165,6 +1165,14 @@ 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 optional Eshell module to help avoid mistakes when supplying
+absolute paths to commands in remote Eshells.  When
+'default-directory' is remote thanks to Eshell's TRAMP integration,
+and you are supplying absolute paths to commands, it is easy to
+accidentally refer to a local path instead of a remote path.  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
index 0000000000..e2585fe2a5
--- /dev/null
+++ b/lisp/eshell/em-elecslash.el
@@ -0,0 +1,113 @@
+;;; 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
+  "When `default-directory' is remote thanks to Eshell's TRAMP
+integration, and you are supplying absolute paths to commands, it
+is easy to accidentally refer to a local path when you meant a
+remote path.  This happens because absolute paths passed to Lisp
+functions must be prefixed with /method:host: but absolute paths
+passed to external commands must not have this prefix; it is easy
+to invoke a built-in command without the prefix by mistake.  This
+module tries to resolve this difficulty by filling in the
+/method:host: electrically just when it's needed."
+  :tag "Electric forward slash"
+  :group 'eshell-module))
+
+;;; Functions:
+
+(defun eshell-elecslash-initialize () ;Called from `eshell-mode' via intern-soft!
+  "Initialize electric forward slash support."
+  (add-hook 'post-self-insert-hook
+            #'eshell-electric-forward-slash nil t))
+
+(defun eshell-electric-forward-slash ()
+  "Electric insertion of TRAMP part of `default-directory' in
+remote Eshells.  Added to `post-self-insert-hook' when the
+Eshell elecslash module is initialized.
+
+Typing a forward slash in a remote Eshell performs the
+completion.  Typing a second forward slash undoes it."
+  (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 path.
+	    (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
-- 
2.30.2


  reply	other threads:[~2022-04-16 18:57 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-27  2:48 Optional Eshell modules -- to emacs.git or ELPA? Sean Whitton
2022-01-29 11:51 ` Philip Kaludercic
2022-04-16 18:57   ` Sean Whitton [this message]
2022-04-16 19:18     ` New optional Eshell module: em-elecslash Eli Zaretskii
2022-04-16 20:04       ` Sean Whitton
2022-04-16 21:42         ` [External] : " Drew Adams
2022-04-17  6:20         ` Eli Zaretskii
2022-04-17 16:48           ` [External] : " Drew Adams
2022-04-19 16:52           ` Sean Whitton
2022-04-20  0:36             ` Sean Whitton
2022-04-20  6:19               ` Eli Zaretskii
2022-04-20 20:14                 ` Sean Whitton
2022-04-21  6:15                   ` Eli Zaretskii
2022-04-16 21:12       ` Sean Whitton
2022-04-16 22:58     ` Stefan Monnier
2022-04-17  5:02       ` Sean Whitton
2022-04-17  6:24     ` Jim Porter
2022-04-19 15:28       ` Sean Whitton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87k0bokg98.fsf@melete.silentflame.com \
    --to=spwhitton@spwhitton.name \
    --cc=emacs-devel@gnu.org \
    --cc=philipk@posteo.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).