Skip to content
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

Line operations on lines with read-only segments (Eshell, wdired...) #852

Closed
Ambrevar opened this issue Jun 15, 2017 · 7 comments
Closed

Comments

@Ambrevar
Copy link

Issue type

  • Enhancement request

Environment

Emacs version: 25.2
Operating System: Arch Linux
Evil version: 1.2.12
Evil installation type: MELPA
Graphical/Terminal: Graphical
Terminal multiplexer: n/a

Line operations (cc, dd...) will fail if parts of the line are read-only. This is most noticeable with Eshell's prompt and wdired.

The issue was mentioned in #603.

My proposal would be as follow: for every line operation, narrow the operation area to the segment under point. If the segment is not writable, then return an error.
Processing segments allows to handle lines like

======______======______====

where = is a read-only charater and _ is a writable character.

Further notes

Going to insert mode on read-only areas does not make much sense, and comands such as evil-insert-line would greatly benefit from moving the point after the beginning of the read-only part. See Eshell for a good example: pressing I on the command prompt should move to the point right after the prompt, not to the beginning of line.

I am using the following fix at the moment:

(defun evil/eshell-next-prompt ()
  (when (get-text-property (point) 'read-only)
    ;; If we are at end of prompt, `eshell-next-prompt' will not move, so go backward.
    (backward-char)
    (eshell-next-prompt 1)))

(add-hook
 'eshell-mode-hook
 (lambda () (add-hook 'evil-insert-state-entry-hook 'evil/eshell-next-prompt nil t)))

What do you think?

@wasamasa
Copy link
Member

It's a huge can of worms. I've started doing something along these lines for comint and it broke history in a non-obvious way, so I went back to using REPLs outside Emacs.

A general solution seems impossible, the saner alternative is imitating what Emacs modes do in this case and allow to easily remap line changes to a mode-specific command. For example, lui provides a line killing command on C-u, so I use that one instead for IRC.

@Ambrevar
Copy link
Author

What about implementing some mode specific commands then? I'd be happy to send a PR for wdired and Eshell.

@wasamasa
Copy link
Member

Eshell caters to that usecase by remapping C-a to a command ensuring you do not end up before the prompt. Therefore, C-a C-k can be used to kill the whole line, a common pattern for Emacs users.

@Ambrevar
Copy link
Author

I'm already mapping 0 to eshell-bol (C-a with standard bindings). That would be nice to make it the default in Evil.

That does not cover everything though. cc and friends still do not work.

It would be easy to define new operators from the old ones and just modify beg and end, but I'm not sure how to do the mapping.

@wasamasa
Copy link
Member

I don't see why Evil should specifically cater to this, so I'm closing this one.

@mentalisttraceur
Copy link

mentalisttraceur commented Apr 12, 2023

Relevant question:

Why does this work out-of-the-box in IELM and not in eshell?

In IELM, Evil commands like 0, dd, cc, and so on, all "Just Work" and do the "right" thing: if the point is to the right of the ELISP> prompt, they move/delete/replace only up to the prompt.

Is Evil doing something special for IELM?

@mentalisttraceur
Copy link

mentalisttraceur commented Apr 13, 2023

I figured out why 0, dd, cc, and so on work out-of-the-box in IELM but not Eshell and so many others: fields.

IELM has the decency to put the field property on its prompt, which is the native Emacs way to say "these are separate things of text, don't traverse/edit them as if they're one thing".

Evil (by design rather than accident, I hope) respects Emacs fields.

Eshell fails to mark its prompt as a field, but luckily we can fix that ourselves! For example, this is my setup (very minimal/plain prompt):

(setq eshell-highlight-prompt nil)
(setq eshell-prompt-function (lambda ()
    (propertize
        (if (= (user-uid) 0) "# " "$ ")
	'read-only t 'field 'prompt 'rear-nonsticky '(read-only field))))
(setq eshell-prompt-regexp "^[$#] ")

(Note that the (setq eshell-highlight-prompt nil) is necessary. If it's non-nil, eshell-emit-prompt will apply its own default properties after our eshell-prompt-function returns, which clobbers our rear-nonsticky value, and we need rear-nonsticky to apply to the field property for this to work.)

If you want to start from the default eshell prompt, just fixed to mark the prompt as a field, you can use this code instead of the above:

(setq eshell-highlight-prompt nil)
(setq eshell-prompt-function (lambda ()
    (propertize
        (concat (abbreviate-file-name (eshell/pwd))
                (if (= (user-uid) 0) " # " " $ "))
        'read-only t
        'font-lock-face 'eshell-prompt
        'field 'prompt
        'front-sticky '(font-lock-face read-only)
        'rear-nonsticky '(font-lock-face read-only field))))

And with that, 0, dd, cc, and so on "Just Work" on the eshell command-line.

I suspect that every other buffer would become automatically similarly compatible with Evil out-of-the-box if its mode was patched/wrapped to properly annotate different fields as such.

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

No branches or pull requests

3 participants