Subject: bug#70792: 30.0.50; [PATCH] Add Eshell support for expanding absolute file names within the current remote connection

From: Jim Porter <[email-masked]>
Date: Tue, 7 May 2024 11:54:26 -0700

(Replying a bit out of order to make the structure of my responses clearer.)

On 5/7/2024 4:55 AM, Eli Zaretskii wrote:
>> Eshell users already have a command for explicitly moving between local
>> and remote hosts: it's just "cd".
> 
> Then why do we need to change anything at all?
> 
> My suggestion is to introduce a notion of "state", either local or
> remote, and make it so that the "state" defines the semantics of file
> names without the Tramp "/METHOD:..." prefix: such names _always_ mean
> files on the host specified by the "state".  In particular, quoted
> file names also specify files according to the "state"; they do not
> "escape" to the other host.
> 
> This matches what you get from a normal shell: if you login to a
> remote host, _all_ the file names are from the remote host.
> 
> It is okay to use the value of default-directory as the "state", but
> we should use it consistently.  the only way of "escaping" from the
> current host is by using fully-qualified file names that specify the
> host explicitly.

I think we must be close to seeing things the same way, since your 
explanation is almost exactly how I proposed to fix this initially. In 
retrospect, I should probably have spent a bit more space introducing 
the issue and explaining why I did what I did; most of my initial 
explanation was simply on *how* the patch works.

So I'll try to provide a summary of this problem from a user POV to make 
sure we're on the same page:

----- SUMMARY -----

Currently, Eshell has a problem: when connected to a remote host (i.e. 
cd'ed into a remote dir), sometimes an absolute file name like 
"/foo/bar" means "a file on the current host", and sometimes it means "a 
file on the *local* host". This new option lets you change that so an 
absolute file name *always* means "a file on the current host"; this 
matches the behavior of normal shells. If you want to refer to a file on 
a different host, you instead type the fully-qualified remote file name 
("/ssh:remote:/foo/bar"); this always means "/foo/bar on remote".

----- END SUMMARY -----

There's just one open question with this: if I'm on a remote system, how 
do I type the fully-qualified *local* file name? I propose using "/:" as 
the prefix to mean "always look on the local host", so "/:/etc/foo.log" 
is a local file name no matter what. For this case, I'm open to other 
spellings, so long as we have *some* way to fully-qualify a local file name.

>> Currently, for Lisp-based commands, you have to type the the full remote 
>> part of the file name again, like "/ssh:user@remote:/some/file". For 
>> external commands, you have to type just the local part, like 
>> "/some/file". For commands that could be *either* Lisp-based or external 
>> (this includes most Eshell built-ins), there's no way to do this. 
>> (Unless you know exactly how Eshell implements things.)
> 
> I think asking the user to specify the full "/ssh:..." file name for
> remote files makes this easier, because Eshell could then
> transparently handle also the commands which can be external or
> internal.  That's one confusing problem down.

Based on your longer explanation above, I think we agree entirely here.

>>> So you are saying that to chdir to the _local_ /etc I must quote it as
>>> in "/:/etc", or somesuch?  If not, how do I chdir to a local directory
>>> by its absolute file name?
>>
>> If your current working directory is local, "cd /etc" is enough (since 
>> the current host is the local one). If your current working directory is 
>> remote, any of the following would change back to the local /etc:
>>
>>    cd /:/etc
>>    cd \/etc
>>    cd "/etc"
>>    cd '/etc'
> 
> The first form I could maybe agree to.  But the others are standard
> shell quoting, so I think repurposing them for "escape to local file
> names" is not a good idea, since quoting is used in shell commands for
> other reasons, notably for quoting special characters.  We need to
> allow user to quote file names without implying the name is local.

That's fine by me; I could remove options 2-4 from this list (so that 
they mean "/etc on the current host"). I had chosen this set of options 
to match the escaping logic for "~" in Eshell. However, I think I agree 
that that's too invasive: a user might want to write a file name with 
spaces "/something/like this.txt", and would be surprised if that 
escaped to a local filename.

>>>>     ##### 5. Change to the *local* home directory, stop being root
>>>> /sudo:root@host:~ # cd /:~; pwd; *pwd
>>>> /home/jim
>>>> /home/jim
>>>
>>> That's awful!  Completely un-natural, let alone a lot of typing!
>>
>> It's only two extra characters
> 
> Two extra characters _per_file_name_!

Note that these extra characters *only* come up if you're connected to a 
remote host and need to explicitly refer to a file on your local system. 
With this new option enabled, the "normal" spelling of "~/blah" would be 
on the current host, just like normal shells. The "/:" is there to 
explicitly override that behavior by fully-qualifying the name. (This 
makes the common case - everything on the same host - easier to type. 
You just type the normal, unqualified name.)

>> Currently, the string "/foo/bar" is just that, a string. It
>> carries no information about the host Emacs should look on.
> 
> The "state" should supply the missing information, and the
> "/METHOD:..." notation should allow the user to override what the
> "state" says implicitly.

Agreed. With this option, an unqualified file name will refer to the 
"state" (current remote host) to resolve the name.

>> Existing commands (whether Lisp-based or external) will just look on
>> the host where the process is running.
> 
> Some kind of dispatch should look at the "state" before it runs the
> command, and decide which variety of the command to run.

Eshell already has a lot of logic for determining whether to run a Lisp 
implementation of a command or an external program, so I don't think we 
can change that without breaking many things. However, once Eshell has 
determined the variety of the command, it can provide file names in the 
correct syntax for that variety. (In other words, Lisp code will see the 
fully-qualified file name[1], and external commands will see the 
unqualified file name.)

[1] It might be wise to let Lisp-based commands request unqualified file 
names too; Eshell already does similar things for determining when to 
turn a string like "123" into a Lisp number.