Replacing matching { braces } with do/end in Vim (Ruby)
Asked Answered
K

3

8

Does anyone have a plugin or macro to replace matching { braces } with do and end in Vim? Preferably turning a single-line statement like this:

foo.each { |f| f.whatever }

into:

foo.each do |f|
  f.whatever
end

I could make a macro myself for that one case, but I'd like something that could also handle converting existing multi-line, potentially complicated blocks, like:

foo.each { |f|
  f.bars.each { |b| b.whatever }
  hash = { a: 123, b: 456 }
}

into:

foo.each do |f|
  f.bars.each { |b| b.whatever }
  hash = { a: 123, b: 456 }
end

I've looked at vim-surround and rails.vim, and haven't found a way with either.

Krakow answered 16/3, 2013 at 2:38 Comment(2)
don't know much about ruby. but why your multiline example (output) only the outter {,} was replaced, the inner f.bars.each{... not?Purgatory
It'd be nice to support both, but normally I wouldn't want anything but one level expanded at a time. My scenario is I prefer in-line blocks for single statements, but often find myself wanting to add another statement or two, and I'd like to expand the block for that. Yes, I know I should refactor it all out into a method.Krakow
S
1

splitjoin.vim

It's mentioned in the comments, but should probably be in an answer for visibility:

splitjoin.vim is a plugin that will do this.

It works for many languages and works on many kinds of statements that have single-line and multi-line variants (and in particular it can split blocks with braces into do/end style).

It's actively maintained, as of 2024. (vim-blockle was archived in 2017.)

From the readme:

This plugin is meant to simplify a task I've found too common in my workflow: switching between a single-line statement and a multi-line one. It offers the following default keybindings, which can be customized:

  • gS to split a one-liner into multiple lines
  • gJ (with the cursor on the first line of a block) to join a block into a single-line statement.
Startling answered 29/7, 2024 at 5:3 Comment(0)
R
10

There is a Vim plugin called Vim Blockle that performs this function.

Once you install the plugin you put the cursor on the { } do or end and press <Leader>b to swap the block styles.

Rivera answered 16/3, 2013 at 4:33 Comment(2)
Thanks! A little quirky, but this is pretty much what I was looking for.Krakow
So I looked into installing Blockle and stumbled upon a recommendation by the Blockle author to install splitjoin instead: github.com/jgdavey/vim-blockle/issues/5Dorotea
S
1

splitjoin.vim

It's mentioned in the comments, but should probably be in an answer for visibility:

splitjoin.vim is a plugin that will do this.

It works for many languages and works on many kinds of statements that have single-line and multi-line variants (and in particular it can split blocks with braces into do/end style).

It's actively maintained, as of 2024. (vim-blockle was archived in 2017.)

From the readme:

This plugin is meant to simplify a task I've found too common in my workflow: switching between a single-line statement and a multi-line one. It offers the following default keybindings, which can be customized:

  • gS to split a one-liner into multiple lines
  • gJ (with the cursor on the first line of a block) to join a block into a single-line statement.
Startling answered 29/7, 2024 at 5:3 Comment(0)
P
0

I assume that in your multi-line example, the output would be :

foo.each do |f|
  f.bars.each do |b| b.whatever end
  hash = { a: 123, b: 456 }
end

that is, the f.bars.each{...} should be replaced too.

if it is the goal, try this:

gg/each\s*{<enter>qqf{%send<esc><c-o>sdo<esc>nq200@q

short explanation:

gg               " move cursor to top
/each\s*{<enter> " search pattern we want
qq               " start recording macro to register q
f{               " move to {
%send<esc>       " move to closing {, and change it to "end", back to normal
<c-o>sdo         " back to beginning { and change it into "do"
<esc>nq          " back to normal, and go to next match, stop recording

then you could do for example 200@q and check the result.

Purgatory answered 16/3, 2013 at 3:6 Comment(1)
That's not quite what I'm after. See my comment on the question. I only want to do it for the scope of the current line. I'll check this out and see if I can work with it, though.Krakow

© 2022 - 2025 — McMap. All rights reserved.