guns / vim-sexp

Precision Editing for S-expressions
MIT License
612 stars 33 forks source link

Capturing elements like emacs slurp #10

Open snoe opened 9 years ago

snoe commented 9 years ago

Hi, great plugin!

There are two features of slurping in emacs paredit mode that I really miss in vim-sexp. The cheat sheet here shows how it behaves and below is why it feels more natural for me to use than the vim equivalents. http://emacswiki.org/emacs/PareditCheatsheet (See Barfage & Slurpage)

Take the example of introducing a let for the map result, after typing (something xs)

(let [xs])
(map to-x ys)
(something xs)

The first thing I miss, is that slurping an element does not move the cursor (or if at the end of a line it moves to the prev char). It makes it far easier to quickly drop out of insert, put forms in the right place and then back to insert without losing focus of where you were working. In the example, I can finish the vector and easily slurp in the map I was working on with ...[xs])<ESC><slurp><slurp>. With vim-sexp captures, it's painful to do this as I need to navigate to the previous form after each slurp.

The second thing is that slurping will recursively slurp up the tree if there's nothing to slurp in the current form. In the example, my cursor can be on the s (the last non-closing char I need to type) and I can just slurp three times to get the map into the binding and the final form into the body.

Would it be possible to change capture to behave in this way or introduce slurp and barf calls with this behavior?

I would have loved to do a PR but I've never written a vim plugin and I felt like I was way over my head when I dove into this.

justinmk commented 9 years ago

slurping an element does not move the cursor

I'd also like this. It allows . repeat without any hassle.

Another thing I noticed (separate issue I guess) is that some vim-sexp operations tend to modify the '> and '< markers so gv does not restore my previous selection.

guns commented 9 years ago

Hello, thanks for reporting!

The first thing I miss, is that slurping an element does not move the cursor (or if at the end of a line it moves to the prev char)

This makes plenty of sense. It's easy to just use ( and ) to move the end of the list anyway.

It makes it far easier to quickly drop out of insert, put forms in the right place and then back to insert without losing focus of where you were working. … With vim-sexp captures, it's painful to do this as I need to navigate to the previous form after each slurp

This doesn't invalidate your point, but you can use gi to return to your last insertion point, and since capture/emit appends the jumplist, you can also use <C-o> to jump back to a previous position.

The second thing is that slurping will recursively slurp up the tree if there's nothing to slurp in the current form. In the example, my cursor can be on the s (the last non-closing char I need to type) and I can just slurp three times to get the map into the binding and the final form into the body.

Does this mean that given the following (with cursor at ):

(let [x█]) foo bar

A first slurp-right produces the following:

(let [x█] foo) bar

A second slurp-right produces this:

(let [x█ foo]) bar

And a third slurp-right produces:

(let [x█ foo] bar)

This is also useful behavior if I've understood correctly.

One more thing, what happens to the cursor position when slurping left and an opening bracket moves from current line to a line above? Does the cursor position stay at the same column, or does it shift left one to stay on the same character?

I don't have much experience with Emacs, so I appreciate your input.

@justinmk writes:

I'd also like this. It allows . repeat without any hassle.

. should work with the current capture/emit. Or do you mean that it will still work, but be better since the cursor is stable?

Another thing I noticed (separate issue I guess) is that some vim-sexp operations tend to modify the '> and '< markers so gv does not restore my previous selection.

Ah, that's an oversight. Visual marks are intentionally overwritten for visual mode bindings, but they should not be mangled when called from normal mode. I'll fix this up as well. Thanks!

justinmk commented 9 years ago

Or do you mean that it will still work, but be better since the cursor is stable?

Yes, that. If the cursor moves then I have to <C-o> before ..

Thank you!

snoe commented 9 years ago

Does this mean that given the following... This is also useful behavior if I've understood correctly.

That's exactly right.

One more thing, what happens to the cursor position when slurping left and an opening bracket moves from current line to a line above? Does the cursor position stay at the same column, or does it shift left one to stay on the same character?

emacs will actually automatically indent if you slurp something from the line above or below. I, personally, don't miss this as much and the rules are a bit harder to nail down, here's some examples:

let
(█[x])

will become

(let
█   [x])

If the cursor had been on the x it would become

(let
    [█x])

If you are inside an empty list, it will join the lines

let
()

Becomes

(let█)

Slurping below:

(let [█x])
foo
bar

becomes

(let [█x]
  foo)
bar
(let [█x
      foo])
bar
(let [█x
      foo]
  bar)
snoe commented 8 years ago

@guns if you want to take a different path forward on this, please feel free to reject my PRs.