New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot edit TRAMP protocol after "accepting" #1227

Closed
darkfeline opened this Issue Oct 7, 2017 · 17 comments

Comments

Projects
None yet
3 participants
@darkfeline

darkfeline commented Oct 7, 2017

After "accepting" a TRAMP protocol, there does not appear to be a way to go back and edit it. DEL does nothing.

This is a huge pain if you tunnel through a few machines and discover a typo. With default completing read, you can move point back and edit the TRAMP portion, but with ivy you have to start over from scratch it seems.

1 Find file: /ssh:user@some-server|ssh:user@another-server|ssh:typo@last-server:/
@abo-abo

This comment has been minimized.

Owner

abo-abo commented Oct 7, 2017

I don't use TRAMP hopping in my workflows (I think it can be avoided by creating entries in ~/.ssh/config?). If you can propose a PR that solves this in a good way, I'd gladly accept.

@edkolev

This comment has been minimized.

Contributor

edkolev commented Oct 7, 2017

The issue is reproducible when a single host is used, without hops.

Here are the steps:

  1. C-x C-f /ssh:fake: (assuming there's a fake host in ssh config)
  2. now if you pressC-x C-f you can visit files on the fake host, but you can't edit files on your machine (where emacs runs)
@abo-abo

This comment has been minimized.

Owner

abo-abo commented Oct 7, 2017

now if you pressC-x C-f you can visit files on the fake host, but you can't edit files on your machine (where emacs runs)

Press // or ~ to go back to local machine?

@darkfeline

This comment has been minimized.

darkfeline commented Oct 8, 2017

You would still have to retype your TRAMP part from scratch. It would be nice if you could go back and edit it.

@abo-abo

This comment has been minimized.

Owner

abo-abo commented Oct 8, 2017

Once you've opened a file or direcotry, it's in the history. Use C-x C-f M-p then.

@darkfeline

This comment has been minimized.

darkfeline commented Oct 8, 2017

You can't edit the TRAMP portion though.

1 Find file: /ssh:user@some-server|ssh:user@another-server|ssh:typo@last-server:/

Once you get here, you can no longer edit the ssh:user@some-server|ssh:user@another-server|ssh:typo@last-server: part at all. Not even if you go back through the history. The only way I have found is to type // to go back to / then type all of ssh:user@some-server|ssh:user@another-server|ssh:typo@last-server: from memory, changing any necessary parts.

@edkolev

This comment has been minimized.

Contributor

edkolev commented Oct 8, 2017

If I understand correctly, the find-file code determines what the prompt is, then ivy doesn't allow editing the prompt, which seems reasonable decision to me.

Here's a snippet which uses plain emacs completion when the visited file is remote:

(defun evgeni-counsel-find-file ()
  (interactive)
  (let ((completing-read-function
         (if (and (buffer-file-name)
                  (file-remote-p (buffer-file-name)))
             'completing-read-default
           'ivy-completing-read)))
    (call-interactively 'find-file)))

The above function can be bound to C-x C-f.
Note this doesn't work if you're visiting a remote directory, though.

@darkfeline

This comment has been minimized.

darkfeline commented Oct 8, 2017

If I understand correctly, the find-file code determines what the prompt is, then ivy doesn't allow editing the prompt, which seems reasonable decision to me.

It doesn't seem reasonable to me, since ido can do it.

/sudo:|sudo::/$

$ denotes the readonly portion of the minibuffer. At this point, pressing DEL repeatedly yields:

/sudo:|sudo::$
/sudo:|sudo:$:
/sudo:|sudo:$
/sudo:|sudo$:
/sudo:|sudo$
/sudo:|$sudo
/sudo:|$sud
/sudo:|$su

Whereas for ivy, pressing DEL does nothing (depending on ivy-on-del-error-function), and pressing // just goes back to a plain /$ prompt.

Thanks for the workaround, although I have simply disabled ivy-mode, binding specific commands like counsel-find-file, and calling M-x find-file whenever I encounter a corner case. ivy is great, but there are so many corner cases. As an analogy, Emacs's default dumb minibuffer read is like a command line, and ivy is like a GUI. It's awesome for a lot of cases, but sometimes you need a dumb command line that makes no assumptions on what you're trying to input.

@abo-abo

This comment has been minimized.

Owner

abo-abo commented Oct 9, 2017

As an analogy, Emacs's default dumb minibuffer read is like a command line, and ivy is like a GUI. It's awesome for a lot of cases, but sometimes you need a dumb command line that makes no assumptions on what you're trying to input.

Rather than shell-vs-GUI, I'd like to think of it as assembler-vs-C. Just imagine we're designing C right now: we should make it easy to do everything in C and not have the user resort to asm when things are lacking.

What IDO did is to make it easy to fall back to asm from C (via C-c C-f) which is a huge anti-pattern: I've spent years un-learning that key binding. I don't want counsel-find-file to have C-c C-f.

As a user, I'm already very happy the subset of functionality that counsel-find-file offers. I'd like other users to be happy with their workflows as well. But then improvements to counsel-find-file should be done by the person that wants them.
So I invite @darkfeline or @edkolev or anyone else to contribute.

@darkfeline

This comment has been minimized.

darkfeline commented Oct 10, 2017

Well, I have already bound find-file to C-u C-x C-f.

What you say may be good, but making a change to a large library like ivy is no small endeavor, and in the meantime, I need Emacs to actually work. Of course, once I have a workaround, I am less motivated to improve ivy.

I do not have an answer, sorry. Software development is hard.

@abo-abo

This comment has been minimized.

Owner

abo-abo commented Oct 10, 2017

Software development is hard.

True that.

@edkolev

This comment has been minimized.

Contributor

edkolev commented Oct 12, 2017

I don't mind implementing a change in counsel-find-file's behaviour.

I'm trying to implement the following behaviour:

  • with prompt Find file: /ssh:fake:/ pressing C-<backspace> should set the prompt to /, clear ivy candidates, and set the minibuffer contents to ssh:fake:/ so the user can edit as necessary.

I'm modifying counsel-up-directory to get the above behaviour. Note that I'm planning to preserve the current behaviour of C-<backspace> on input such as Find file: /ssh:fake:/path/to/file.

@abo-abo could you help me out with pointers (no C pun intended) how to:

  • set the prompt to / without triggering ivy completion; i.e. do what ivy--cd does but without making ivy list files in /
  • set minibuffer contents programatically, I see minibuffer.el has minibuffer-completion-contents and delete-minibuffer-contents but no function to set the contents

Thank you

@abo-abo

This comment has been minimized.

Owner

abo-abo commented Oct 12, 2017

set the prompt to / without triggering ivy completion; i.e. do what ivy--cd does but without making ivy list files in /

See ivy-set-prompt. You can attach a custom prompt function and display whatever is needed.

set minibuffer contents programatically, I see minibuffer.el has minibuffer-completion-contents and delete-minibuffer-contents but no function to set the contents

With Ivy, the minibuffer contents are always:

  1. prompt (customizable)
  2. user input
  3. candidates that match user input (customizable)

Use :re-builder and :matcher arguments to ivy-read to customize item 3.

  • :re-builder is str -> str and transforms ivy-text to a regex
  • :matcher is str * str list -> str list and transforms a regex and a list of candidates to a list of candidates that "match" the regex. Use can just ignore all input arguments and return whatever you want - that will be inserted into the minibuffer.
@edkolev

This comment has been minimized.

Contributor

edkolev commented Oct 16, 2017

Thanks, abo-abo!

Here's what I've come up with, not sure if this is the best implementation.

In the following gif I press C-x C-f then C-backspace twice, then edit the ssh host:

10

This is the only changed function:

(defun counsel-up-directory ()
  "Go to the parent directory preselecting the current one."
  (interactive)
  (let* ((dir-file-name
          (directory-file-name (expand-file-name ivy--directory)))
         (up-dir (file-name-directory dir-file-name)))

    (if (string-equal dir-file-name up-dir)
        (progn
          (setq ivy--old-cands nil)
          (setq ivy--old-re nil)
          (ivy-set-index 0)

          (setq ivy--directory "")
          (setq ivy--all-candidates nil)
          (setq ivy-text "")
          (delete-minibuffer-contents)
          (insert up-dir))
      (ivy--cd (file-name-directory dir-file-name))
      (setf (ivy-state-preselect ivy-last)
            (file-name-as-directory (file-name-nondirectory dir-file-name)))))) 

@darkfeline is this behaviour something you consider better over the current one?

@darkfeline

This comment has been minimized.

darkfeline commented Oct 17, 2017

@edkolev Thanks, that looks great.

@abo-abo

This comment has been minimized.

Owner

abo-abo commented Oct 17, 2017

@edkolev Could you open a PR with this?

@edkolev

This comment has been minimized.

Contributor

edkolev commented Oct 17, 2017

Sure, I just opened one.

@abo-abo abo-abo closed this in 4a66bb6 Oct 17, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment