3

In vim, I frequently used the "." shortcut for repeating the last command. I found this extremely useful especially when working with clojure tools to do things like slurp-ing and barf-ing to refactor code.

In Spacemacs, the clojure layer provides a special state called lisp-state that allows for things like slurp and barf. See here.

What I'm trying to do is find a key, like ., that I can bind to some command that would allow me to repeat an action like a slurp.

By default, in evil-mode the . is bound to evil-repeat. However, doing that creates odd behavior. For example, a common scenario in which I use the repeat is when editing lisp files. Let's say I slurp a text like so using Ctrl + k, s:

() + a b => (+) a b

In vim, I would hit the "." key to continue moving the paren to the right. With the setting above in Emacs (Spacemacs), I got a behavior I did not understand. If I hit ., the slurp is not repeated. Instead, I see the following at the bottom of the screen:

state: lisp -> normal

I also tried to remap the . key to the repeat command instead of evil-repeat, but I get the same behavior.

It appears that the repeat key somehow first interacts with the lisp-state, perhaps returning the browser to normal state. So my question is what is the right way to repeat an action like slurp in lisp-state, and can this method be bound to a key?

fraxture
  • 338
  • 1
  • 13
  • 1
    If I install evil and enable `evil-mode` then I can see that `.` is already bound to `evil-repeat`. – phils Jan 09 '19 at 03:50
  • It's unclear what you're asking about because you're speaking of a repeat command built into Emacs (aka `repeat`), then show how you're binding Evil's (aka `evil-repeat`) which is already bound in `evil-normal-state-map`, so whatever you're doing is a no-op. – wasamasa Jan 09 '19 at 06:06
  • @phils you are right, by default `.` is bound to `evil-repeat`, but `evil-repeat` is the command that I have to hit twice, and which the first time causes this message `state: lisp->normal` to appear. I'll try to make the question clearer. – fraxture Jan 10 '19 at 15:38
  • Question updated. – fraxture Jan 10 '19 at 16:28
  • FWIW, the question title is confusing. You state you are 'binding'. Most people would assume this is regarding something like `global-key-set`. It doesn't seem like the question is about key-binding at all. Instead, it looks like it's a question about how to repeatedly slurp. You might have better luck asking about how to repeat commands or how the slurping package works. BTW, what package provides the slurping functionality? I've seen it before, but it's not a default GNU Emacs function (although it seems to be packaged with Spacemacs). – Lorem Ipsum Jan 10 '19 at 17:57
  • @LoremIpsum the slurp package comes from the clojure layer for spacemacs (I'm using spacemacs). The documentation for that layer is [here](https://github.com/syl20bnr/spacemacs/tree/master/layers/%2Blang/clojure#layer). The document describes a special `lisp-state` that provides for things like barfing and slurping. The odd behavior I'm getting must have to do partly with that. – fraxture Jan 14 '19 at 14:07

1 Answers1

2

In Vim, the . key repeats the last change made in normal mode.

The slurping scenario you describe is some random function that is beyond evil. Your guess is as good as mine in regards to how that function works in relation to normal mode. Since it's not likely a bonafide normal mode operation, there's no guarantee that it will be repeatable with evil-repeat. In fact, that seems to be the case.

Rebind

It's not clear from your question whether repeat, or the related repeat-complex-command, achieve your goal. If they are what you want and it's only the default bindings of C-x z or C-x <ESC> <ESC> which you dislike, you can rebind them using global-set-key. For example, you could rebind repeat using something like,

(global-set-key (kbd "C-r") 'repeat)  ;; bind to C-r
(global-set-key [f5] 'repeat)         ;; bind to F5

Unfortunately, binding can get a little tricky because of mode maps. You may have to do some fiddling/poking around to find the right combination. The evil package, for example, which I believe is used for Spacemacs, has a different state map for normal, visual, etc. It can be set with something like,

  (define-key evil-normal-state-map "\C-r" 'repeat) ;; bind to C-r in Normal mode

To see which keys are currently (un)bound for a given buffer, you can use C-h b.

Alternative 1

You might be able to achieve the same goal of repeating a sequence some other way. One thought is with macros. Here's how Vim macros work:

In Vim, and subsequently evil, macros are recorded with q. You press q, give the macro a name, do the stuff you want to do, then press q again to end the recording. To call the macro, do @<name>. The macro can be called repeatedly with a prefix number.

For example, qaiHello, world!<RET><ESC>q will record a macro to a. It inserts "Hello, world!" at the current cursor position and moves to the next line. To call the macro, press @a.

I have less experience with Emacs macros. It looks like there's an Emacs Rocks about it, Episode 05: Macros in style, though.

Alternative 2

Instead of repeating the command, you might use the C-u prefix to anticipate the number of times you need to do something. For instance, if you know you need to slurp the next 5 characters, you ought to be able to do C-u 5 <command-that-slurps>.

Lorem Ipsum
  • 4,327
  • 2
  • 14
  • 35