How to move through words in camel-cased identifiers in Vim? - vim

How to move the cursor before or after the first uppercase letter of a word in Vim?
My motivation is removing or selecting the first word of a camel-case identifier in code. For example, if the cursor is on the m character in the word camelCase, I can use the FcdtC sequence of Normal-mode commands to delete the camel prefix.
Is there a general way to jump to the next occurrence of an uppercase letter in an identifier?

In situations where approaches using only built-in Vim instruments are
preferred, the following search commands can be used.
For jumping to the next uppercase character:
/\u
For moving the cursor one character to the right of the next uppercase
character:
/\u/s+
or
/\u\zs
If one expects to use a movement like that often, one can always
define a key mapping for it as a shorthand, e.g.:
:nnoremap <leader>u /\u/s+<cr>

I don't think there is anything built-in.
As #ib. indicates, you can use a regular expression motion, but it’s not particularly easy to type. However, there is camelcasemotion plugin that adds the necessary motions, for this, as well as underscore seperated identifiers.

Updated Answer (using #ib.'s contribution)
"select from first char up to First uppercase letter ( after first char )
map ,b bv/[A-Z]<cr>h
Original Answer
Regarding jumping before and after the first uppercase letter—
You can map it if you want to.
"Before next uppercase letter
map ,A /[A-Z]<cr>l
"After next uppercase letter
map ,B /[A-Z]<cr>h
:D. Hope this helps. I'm reading your second question now.
Ok, read it. Now you can do this
bv,A
:D

I think I thought maybe "the vim way" to do it :
Vim allow us to define our own operator !
" movement mapping {
" Delete yank or change until next UpperCase
" o waits for you to enter a movement command : http://learnvimscriptthehardway.stevelosh.com/chapters/15.html
" M is for Maj (as in french)
" :<c-u>execute -> special way to run multiple normal commande in a map : learnvimscriptthehardway.stevelosh.com/chapters/16.html
onoremap M :<c-u>execute "normal! /[A-Z]\r:nohlsearch\r"<cr>
That way giving
DailyAverage.new(FooBarBaz)
If my cursor is on a (from DailyMesure) and I press dM It delete to A and give
Average.new(FooBarBaz)
It works with all command waiting for a movement (c y ........)
This snippet need to be improved because of bad highlight.

Related

How to find ("super-star") the word under the cursor without the word boundary modifiers?

Vim's "super-star" operation (search and highlight for the word under the cursor) is super-handy. But it has the limitation of searching for the exact match of the whole word.
Is it possible to have similar functionality, but w/o the enclosing word-boundary brackets?
Update: Apparently I was too quick to post the question. Looking here, there's the answer.
using g * is probably the best solution, but for new vim users it might be interesting to know how this could be done pretty much from scratch:
:nnoremap <expr> * "/".expand("<cword>")."/\<CR>"
map <expr> means that instead of mapping to a literal key sequence, the right-hand side is an expression that is evaluated every time the mapping occurs and the resulting string is treated like the RHS of a normal mapping.
expand("<cword>") returns a string containing the word under the cursor, and "\<CR>" basically just means the enter key.
So in the end we get a mapping to /<word under cursor>/enter, where the word under cursor isn't inserted until the mapping is used.
Answer is in this page: Instead of pressing *, use g*.

c, i and s commands combined in VIM

I've been using VIM for a while and it surprises me each time. Under "Building Sentences" section in this tutorial, I saw the combination of commands cis and yip. I have used Vim quite a while and I am familiar with most commands in Normal Mode. I also know combining the commands in a meaningful way to produce combined actions.
However, the examples I showed above (cis and yip) totally broke my understanding of VIM command system in normal mode. "c" stands for change, "i" stands for insert and "s" stands for substitute but combined action is different than I would expect. I also went through VIM help files but never saw an example illustrating given usage.
Could someone clarify what's going on ?
cis
In vim help it is described as follows
:help c
"Delete {motion} text [into register x] and start insert …"
The next part of the command cis refer to the "motion" part. These commands are for text object selection. An explanation on the different types of text object selections can you get here:
:help text-objects
e.g. for
is – "inner sentence", select [count] sentences …
Analog to the explanation above its the same with yip
:help y
"Yank {motion} text [into register x] … "
And the text selection part yip
ip – "inner paragraph", select [count] paragraphs (see paragraph) …
In this case i does not stand for Insert and s not for substitute.
cis = change inner sentence.
This is completly logic once you understand the basic principle. Each command is like a sentence, it needs an Verb(Action) and an Noun(Object) and there are modifiers.
So the first button is your action C (Change). Now the following keystrokes will not be actions, until the c action ended (Until an Object is provided, or an invalid sequence is inserted). I (inner) is a modifier here and S the Object (Sentence).
I find this especially usefull for Changing words. if you only press cw on a word, you have to have the cursor on the beginning of the word.
With ciw you can change the whole word regardless of the cursor position (Note if you have / or some other seperators in the word, you maybe need ciW)
same letter can have different meanings. E.g. (/{ move to sentences/paragraph back, but ci( or ci{ means change in (...)/{...}.
Same as your s case, s in normal mode alone, does delete & start insert, however in cis, das means sentence.
p case: in normal mode alone, means paste, however in cip, yap ... means paragraph.
:h text-objects
will show you the concept of text-objects. It is a must skill for vim user. ;-)

vim: command like f{char} but for series of chars instead of single char

In vim I can navigate to char in current line using f{char} -- To [count]'th occurrence of {char} to the right. The cursor is placed on {char} (inclusive).
Lets look on next line:
from fmodule import futility
-- there are three words starting from f letter and assume that I want to jump to futils. To do it (with cursor at the beginning of line) I will execute 2ff, but instead I would really like to do something like f{fut} (providing first chars of word not single one).
What are the ways to accomplish this task?
You can use the / search as a motion, also in visual mode and in combination with a command like d. You need to conclude the search with <Enter>, as usual. In contrast to f, this will also find matches in following lines. Some consider this a feature (and change f accordingly via plugins), others don't like this. If you're in the latter camp, the following mapping will restrict the pattern to the current line automatically:
noremap <expr> <Leader>/ '/\%' . line('.') . 'l'
You might also want to define <Leader>? for the opposite direction.

Is it possible to interactively delete matching search pattern in Vim?

There is a phrase that I want to look for in Vim. When found, I want to delete that occurrence of the phrase. What is the easiest way to cycle through all the occurrences (via n), and delete a match one by one (I do not want to delete all of them at once).
Note: I know I can delete a certain number of characters or a number of words, but I want to specifically remove the match of my search. Is this possible?
http://vim.wikia.com/wiki/Search_and_replace
Try this search and replace:
:%s/foo/bar/gc
Change each 'foo' to 'bar', but ask for confirmation first.
Press y or n to change or keep your text.
There are 3 ways I can think of:
The way that is easiest to explain is
:%s/phrase to delete//gc
but you can also (personally I use this second one more often) do a regular search for the phrase to delete
/phrase to delete
Vim will take you to the beginning of the next occurrence of the phrase.
Go into insert mode (hit i) and use the Delete key to remove the phrase.
Hit escape when you have deleted all of the phrase.
Now that you have done this one time, you can hit n to go to the next occurrence of the phrase and then hit the dot/period "." key to perform the delete action you just performed
Continue hitting n and dot until you are done.
Lastly you can do a search for the phrase to delete (like in second method) but this time, instead of going into insert mode, you
Count the number of characters you want to delete
Type that number in (with number keys)
Hit the x key - characters should get deleted
Continue through with n and dot like in the second method.
PS - And if you didn't know already you can do a capital n to move backwards through the search matches.
1. In my opinion, the most convenient way is to search for one
occurrence first, and then invoke the following :substitute command:
:%s///gc
Since the pattern is empty, this :substitute command will look for
the occurrences of the last-used search pattern, and will then replace
them with the empty string, each time asking for user confirmation,
realizing exactly the desired behavior.
2. If it is a common pattern in one’s editing habits, one can
further define a couple of text-object selection mappings to operate
specifically on the match of the last search pattern under the cursor.
The following two mappings can be used in both Visual and
Operator-pending modes to select the text of the preceding match
of the last search pattern.
vnoremap <silent> i/ :<c-u>call SelectMatch()<cr>
onoremap <silent> i/ :call SelectMatch()<cr>
function! SelectMatch()
if search(#/, 'bcW')
norm! v
call search(#/, 'ceW')
else
norm! gv
endif
endfunction
Using these mappings one can delete the match under the cursor with
di/, or apply any other operator or visually select it with vi/.
The best way is probably to use:
:%s/phrase//gc
c asks for confirmation before each deletion. g allows multiple replacements to occur on the same line.
You can also just search using /phrase, select the next match with gn, and delete it with d.

Command to surround a character with spaces in vim

I am trying to use vim properly - to aid me I've mapped my arrow keys to "" so that I am forced to use {hjlk} to move around.
This is causing me a problem when I want to just surround a character with spaces, eg:
"2+3" is better formatted "2 + 3"
Previously I would have put my cursor over the + and typed:
i[space][arrow-right][space][Esc]
That's 5 presses.
To do this without the arrow I seem to need to put the cursor over the + and go:
i[space][Esc]lli[space][Esc]
That's 8 presses.
I can convert the "li" into an "a" which reduces it to 7 presses:
i[space][Esc]la[space][Esc]
Short of writing this into a macro is there a better way of doing it? Is there some magic vim command which will allow me to do it in less than even 5 presses - and some way to generalise it so that I can do it to entire words or symbols, eg if I want to convert 3==4 to 3 == 4?
Personally, I think it makes most sense to destroy what you want to surround, and then repaste it.
c w "" ESC P
Obviously, you can replace both the object and the quotes with whatever you like. To change just one character + to be [space]+[space], you would do
s [space] [space] ESC P
on the +
The first thing that jumps to mind after reading just the title is surround.vim which is an excellent script to do all kinds of useful things along the lines of what you've described.
To solve your specific problem, I would probably position the cursor on the + and:
s[space]+[space][esc]
To change 3==4 into 3 == 4, I might position the cursor on the first =, and:
i[space][esc]ww.
i have been wondering about this as well. i tried with surround.vim, but the naive approach
S<space>
(after making a visual selection) does not work since the space is already taken up as a modifier for adding space to other surrounding character pairs. S<space><cr> adds a ^M in the output. Ss almost works but inserts a space only before.
after asking at tpope/surround.vim on github:
S<space><space>
in visual mode works. alternatively, from normal mode, ysl<space><space> works for a single character
Hah! I've been trying to figure out how to surround a block in spaces for quite a while and I finally found the right combination.
Using surround.vim you say surround selector space space.
So for this specific case I would use visual mode (a good trick for operating on single characters under the cursor BTW) thus: "vs " <- four key presses!
I also have a habit of typing things like argument lists without spaces. With this technique you can just navigate to the second argument using w and say "vws " to visually select a word and surround with spaces.
I prefer visual select mode generally. Also the alternate surround syntax "ysw " excludes the word final comma that is caught by "vw".
You could create a macro with one of the described actions and call it everytime you need it (Like amphetamachine proposed while I was writing) or you could simply search & replace:
:%s/\(\d\)\(+\|-\)\(\d\)/\1 \2 \3/g
You probably have to execute this command two times because it will only find every second occurence of +/-.
EDIT:
This will replace everything without the need to be called twice:
:%s/\d\#<=+\|-\d\#=/ \0 /g
Try positioning your cursor over the '+' and typing this:
q1i[space][right arrow][space][left arrow][esc]q
This will record a quick macro in slot 1 that you can re-use whenever you feel like it, that will surround the character under the cursor with spaces. You can re-call it with #1.
There is also the more versatile one:
q1ea[space][esc]bi[space][right arrow][esc]q
Which will surround the word under the cursor ("==" counts as a word) with spaces when you hit #1.
You could set up a mapping like this (press enter in visual mode to wrap spaces):
:vnoremap <CR> <ESC>`<i<SPACE><ESC>`>la<SPACE><ESC>h
This method allows you to use . to repeat the command at the next +.
Put your cursor over the + and type:
s[SPACE][CTRL-R]"[SPACE][ESC]
I know this is and old thread, but this might be useful to someone. I've found that the map (map it to anything else you want!)
noremap <leader>ss diwi<SPACE><C-R>"<SPACE><ESC>B
works ok both for turning 'a+b' into 'a + b' (when used over the '+' char) and for turning 'a==b' into 'a == b' (when used over either the first or the second '=' sign).
I hope it's useful to someone.

Resources