0

I'm trying to reverse some words, and I have it set up where I can visually select them and hit ,rw to reverse them.

How do I set it up so ,rw also works with a motion. E.g. ,rw3w to reverse 3 words?

(defun reverse-words (beg end)
  "Reverse the order of words in region."
  (interactive "*r")
  (apply
    'insert
    (reverse
      (split-string
        (delete-and-extract-region beg end) "\\b"))))
(define-key evil-visual-state-map (kbd ",rw") 'reverse-words)

I've also tried (define-key evil-normal-state-map ...) and (define-key evil-operator-state-map ...) but to no avail.

It should also respond to the . command to repeat the last command.

Any tips on a built-in way to do this or a better keybinding would be appreciated.

1 Answer 1

1

You can use the evil-define-operator macro for that. However, your command would not work well with the w operator, use the e operator instead. Also, the command must be modified a little to work well with 'repeat'.

(evil-define-operator reverse-words (beg end)
  "Reverse the order of words in region."
  :repeat t
  (interactive "*<r>")
  (apply
    'insert
    (reverse
      (split-string
       (delete-and-extract-region beg end) "\\b")))
  (when (looking-at-p "[[:blank:]]")
    (forward-to-word 1)))

(evil-global-set-key 'normal ",rw" 'reverse-words)

As far as I know, the only place to find info about the evil interactive codes is in evil-types.el (use M-x find-library).

Although the forward-to-word docstring implies that the 1 should be optional, it is not optional on Emacs 30 (would be great if you have time to report this 'bug').

You can comment out the when to try and see why I've added it (try to repeat using .).

5
  • Thank you! How do I find out what < > means? I couldn't find it in C-h f. Any downside to just using (forward-to-word)? What is the purpose of (when ...)? Is the correct way to make it work in visual mode to add (evil-global-set-key 'visual ...), or is there one line that will cover all modes? And how do I stop it including a newline at the end?
    – Zaz
    Commented May 19, 2023 at 22:37
  • I have updated the answer. I think what you suggest for setting this in 'visual state' is correct, but it seems unnecessary, as setting it only in normal mode seems to take care of it (I am no evil developer, and I don't know why it works like this, I guess the answer can be found in the evil docs). I am not sure what you mean with 'including a newline at the end'. Commented May 20, 2023 at 7:27
  • Without adding a visual state, it doesn't work for me. When I select text and then press ,rw, nothing happens. What I mean with the newline is if I use visual-line mode, the entire line is selected, including the newline at the end. So this code moves the newline to the beginning, which is generally not what I want.
    – Zaz
    Commented May 20, 2023 at 8:50
  • I created a patch. Before I submit it, am I missing something? As it is now, M-x forward-to-word RET works without argument, but (forward-to-word) throws a missing argument error. Is the function designed this way on purpose?
    – Zaz
    Commented May 20, 2023 at 10:30
  • Great! That patch looks good to me. A small stylistic comment is that I would just 'pass' (or arg 1) in that backward-to-word function, but maybe your current code is more explicit. To exclude that newline, I guess you could replace the \\b with a [[:blank:]]... Commented May 30, 2023 at 6:04

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.