17

I have a list of words, like this:

these are
some
words that I want
to convert to
camel case

I need a way to turn, for example, camel case into camelCase within a macro (or a way to turn every line of a visual line selection into camel case).

I could use something like wgUlhx as many times as necessary, but the problem is that this doesn't work for words of varying lengths (so, for example, wgUlhxwgUlhx would work for convert this please but not for convert these pretty please).

The desired output for the above lines would be

theseAre
some
wordsThatIWant
toConvertTo
camelCase

Is there any way to automate this?

4 Answers 4

19

A One Liner

I found a simple regular expression replacement (assuming 'magic' is set):

:s/ \([a-zA-Z]\)/\u\1/g

This match any single letter after a space, saving the letter. Then, it replaces it with the saved letter made upper case (\u = upper case, \1 = first saved match), for every match in the line.

Apply over the entire file by putting a % between : and s.

The downside to this solution is that it is linewise (which works for your examples), but would fall short if you only wanted to camel case a few words out of many within a line.

A fuller solution

map <leader>g~ :set opfunc=MyCamelCase<CR>g@
function! MyCamelCase(type, ...)
  let searchsave=@/
    silent s/\%>'\[ \([a-zA-Z]\)\%<']/\u\1/g
  let @/=searchsave
 endfunction

This creates a new operator that can operate on a motion. If you have <leader> as \, then given the following text (with | as the cursor):

This is some |example text to work with.

Typing \g~3w gives

This is some exampleTextTo work with.

That is, we camel cased over 3 words.

Description of that substitution:

s/ starts the substitution.
\%>'\[ is a bit painful. The \%>'m says to match to the right of a mark. We want mark [, but that also has to be escaped in this pattern. So, this starts the match after the motion given to the operator.
\([a-zA-Z\) is the same as from the one-liner above.
\%<'] this is the other end, matching before the end of the motion.
/\u\1/g is the replacement from the one-liner above.

4
  • Actually, that's not a macro so much as it is a one liner, but you could map it to a key combination.
    – John O'M.
    Commented Feb 18, 2015 at 2:48
  • Added an operator version to do it. Operates a bit better.
    – John O'M.
    Commented Feb 18, 2015 at 5:52
  • I think it's okay if your answer doesn't specifically use a macro; the asker presented an XY problem, in my opinion.
    – tommcdo
    Commented Feb 18, 2015 at 12:18
  • @tommcdo Yes, you're right; it doesn't have to be an actual macro. It just needs to be some kind of automated method.
    – Doorknob
    Commented Feb 19, 2015 at 2:18
12

For an alternative I use the vim-abolish plugin that offers a coercion feature:

Want to turn fooBar into foo_bar? Press crs (coerce to snake_case). MixedCase (crm), camelCase (crc), snake_case (crs), and UPPER_CASE (cru) are all just 3 keystrokes away. These commands support repeat.vim.

2
  • 2
    +1 because there's always a Tim Pope's plugin I didn't know about.
    – mrzool
    Commented Sep 8, 2015 at 11:59
  • I maybe being stupid but what is the "crs" key to press? Commented Jun 11 at 8:42
5

You can create a recursive macro that does this for a single line with the following keystrokes:

qqqqqf xgUl@qq

(Note that the space between the f and the x is a tap of the spacebar, not a pause)

In detail:

  1. Clear out the q register. This is necessary because we are creating a recursive macro. (See step 5.): qqq

  2. Start recording a macro in register q: qq

  3. You can't use the w motion here, because you want the macro to abort when it gets to the end of the line, rather than leaping to the next line. Instead, jump to the next space character on the line by pressing the f key followed by the spacebar: f<space>

  4. Delete the space and upper-case the following letter: xgUl

  5. Recurse. Because we cleared the q register in step 1, there's nothing in it yet, so this will do nothing: @q

  6. Save the macro: q

You can then apply this macro to multiple lines by using a range:

Apply the macro to every line in the file:

:%normal @q

Apply the macro to lines 2–5 inclusive:

:2,5normal @q

Make a visual selection, and then type :normal @q. This will pre-populate the command line when you press the : key, resulting in a command which applies the macro to every line in the selection:

:'<,'>normal @a
6
  • It's unnecessary to clear out the q register, as qq does just that before it starts recording keystrokes. In fact, that's precisely why qqq works to clear the q register :)
    – tommcdo
    Commented Feb 18, 2015 at 12:13
  • Of course, if you were doing something that required appending to the q register (i.e. using qQ) then clearing it first would probably be necessary.
    – tommcdo
    Commented Feb 18, 2015 at 12:15
  • 2
    @tommcdo That's definitely not true in my copy of Vim. (Vim 7.3.87, invoked with vim -u NONE). The existing contents are only cleared out when you save the register, in step 6. Clearing out the register before you start is therefore necessary if you want to recurse.
    – Rich
    Commented Feb 18, 2015 at 12:19
  • @tommcdo I've updated the answer to make it more clear why this step is necessary.
    – Rich
    Commented Feb 18, 2015 at 12:22
  • My mistake, I sort of jumped the gun there. Excellent clarification!
    – tommcdo
    Commented Feb 19, 2015 at 1:41
1

See http://vim.wikia.com/wiki/Changing_case_with_regular_expressions It explains the \U, \L, \u, \l modifiers quite clearly and succinctly!

Its essence is the following:

There are times that you might like to go through a file and change the case of characters that match some arbitrary criteria. If you understand regular expressions well, you can actually do this fairly easily.

It's as simple as placing \U or \L in front of backreferences which you want to change the case of, and \E at the end. Vim will make the text in the backreference uppercase or lowercase (respectively). Use \u and \l (without the \E at the end) to just change the case of the very first character in the backreference.

(A "backreference" is a part of a regular expression that refers to a previous part of a regular expression. The most common backreferences are &, \1, \2, \3, ... , \9).

Some examples that demonstrate the power of this technique:

Lowercase the entire file

:%s/.*/\L&/g

(& is a handy backreference that refers to the complete text of the match.)

Uppercase all words that are preceded by a < (i.e. opening HTML tag names):

:%s/<\(\w*\)/<\U\1/g

Note also the gu and gU commands.

For example, ggguG will lowercase the entire file. (gg = go to top, gu = lowercase, G = go to EOF).

By using the \0 general backref instead of the name ones (\1, \2 etc) you can save some typing for on replace stanza of the regex.

This regex upper cases an explicit set of words to uppercase in a file:

:%s/\(select\)\|\(order)\|\(by\)\|\(from\)\|\(where\)/\U\0/g

Not rocket science, but otherwise you'd have to do this:

:%s/\(select\)\|\(order)\|\(by\)\|\(from\)\|\(where\)/\U\1\U\2\U\3\U\4\U\5/g
2
  • 1
    Can you please summarize the article you mentioned in your answer? Commented Sep 8, 2015 at 16:08
  • See you? It is very important, if single-link answers would be okay, some years later this site would be full with deleted links. But if you only copy an important part of the link you refer, and give also the link where the OP can get further infos, it is okay.
    – peterh
    Commented Sep 8, 2015 at 21:00

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.