When I press dd in haskell-interactive-mode at the prompt, it doesn't delete anything, because part of the line is read-only. I would like to map dd to 'haskell-interactive-mode-kill-whole-line.


(evil-define-key 'normal haskell-interactive-mode-map
  (kbd "dd") 'haskell-interactive-mode-kill-whole-line)

doesn't solve the problem. Although it binds dd, it clobbers evil-mode's d binding, making commands like dw no longer work. Just adding things to the evil-operator-shortcut-map (like what evil-surround does) doesn't quite cut it either, because that would bind nonsensical sequences like yd which should remain unbound.

These two links are relevant, but not quite answers.

  • yd? What does that do?
    – PythonNut
    Commented May 22, 2015 at 4:29
  • Nothing, as it should.
    – Alex R
    Commented May 22, 2015 at 14:49
  • If you are still interested, I can immediately post a high-quality solution. Would you open bounty for that? Commented Aug 21, 2015 at 20:10
  • Sure. It's not like I'm using that reputation for anything anyway.
    – Alex R
    Commented Aug 22, 2015 at 2:02

2 Answers 2


Your initial idea to merely remap dd has another subtle issue. As you surely know Vd is basically the same as dd (in a sense that it operates on a whole line), so it should also exhibit the same desired behavior somehow (i.e. use haskell-interactive-mode-kill-whole-line as a back end). I hope it's clear that this also applies to an infinite set of other possibilities: 10dd, Vjjjd, and etc. Hence, we are going to define our own haskell-delete operator (thanks to the Evil framework facilities):

(evil-define-operator haskell-delete
    (beg end type register yank-handler)
  "Delete text from BEG to END with TYPE.
Save in REGISTER or in the kill-ring with YANK-HANDLER."
  (interactive "<R><x><y>")
  (if (eq type 'line)
        (unless register
          (let ((text (filter-buffer-substring beg end)))
            (unless (string-match-p "\n" text)
              (evil-set-register ?- text))))
        (let ((evil-was-yanked-without-register nil))
          (evil-yank beg end type register yank-handler))
        (dotimes (var (count-lines beg end))
    (evil-delete beg end type register yank-handler))
  (when (and (evil-called-interactively-p)
             (eq type 'line))

And now simply remap d in haskell-interactive-mode-map specific to the Normal state:

(evil-define-key 'normal haskell-interactive-mode-map
  (kbd "d") #'haskell-delete)

Please, let me know if you encounter any issues, so that we could jointly fix them.

  • That looks like it will work. I'll try it and get back to you.
    – Alex R
    Commented Aug 22, 2015 at 20:38
  • This seems to work; the only problem is that it puts the point at the beginning of the line rather than at the end. Replacing (evil-first-non-blank) with (evil-end-of-line) solves that. Would you consider explaining your operator definition so that I could write my own for yy and cc?
    – Alex R
    Commented Aug 25, 2015 at 17:54
  • Simply take a look at what evil-delete does. The part with register dancing is there to handle yanking of what you delete (same way the default evil-delete does, thus this code is copy/paste from it). The loop simply solves the problem when several lines are involved. The very last part with evil-first-non-black is again copy/paste from evil-delete (i.e. that's how default delete operator is expected to function, hence your choice of evil-end-of-line looks weird to me). The condition on whether type is 'line distinguishes the case where we want to apply operator to line(s). Commented Aug 25, 2015 at 19:03
  • evil-first-non-blank puts the point before the prompt.
    – Alex R
    Commented Aug 26, 2015 at 3:51

I found that the right way to map operators is using evil-operator-state-map. So this

(defun my-haskell-maps() 
  (define-key evil-operator-state-local-map
  "D" 'haskell-interactive-mode-kill-whole-line))

(add-hook 'haskell-interactive-mode-hook 'my-haskell-maps)

will map dD to the correct function without interfere with the other d operators. However, for some reason, mapping dd does not work. Maybe because it doesn't override evil defaults. I'll let you know if I manage to fix the dd binding

  • It's probably because evil hardcodes repetition of the operator as a line-wise operation, hacking around that will be more involved than your snippet I'm afraid.
    – wasamasa
    Commented May 22, 2015 at 18:59
  • The relevant portion of the code that defines "dd" (albeit indirectly) is: gitorious.org/evil/evil/source/…
    – Alex R
    Commented May 22, 2015 at 20:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.