Move Cursor Immediately Before a Character on a Line in Vim - vim

Say I have the following:
text function(contents) text
and I wanted it to be
text function() text
Placing the cursor right after the opening parenthesis, I thought the following command would work df); however, what I ended up with was the following
text function( text
So I would need someway to specify that I want the character just before the closing parenthesis, but I'm not sure how to do that. There may also be a better way to do this.
What would be the best way to go about this?

You were close! You need dt) as in delete till )
The f motion places the cursor on the ) (remember it like find)
As for the 'best' way to do it, there is at least a more general way: if the
cursor were somewhere in the middle of the ( and ) (or on one of them), you
can do di) (or equivalently di() to delete inside )
If you do da) (or equivalently da() to delete around ), you would
delete the stuff in between and including the brackets.
The same goes for di[, di{, di<, di', di" etc. Using these so-called
text objects, as opposed to the d{motion} way, has the advantage that you can
repeat the edit on other pairs of brackets/quotes without the cursor needing to
be in precisely the same place - it just needs to be on or in between them.
In the following you could position the cursor on e.g. the 'i' of 'initial' in
the first line, do di) to delete the words 'some initial text', then move the
cursor to the 'e' in 'more' in the second line and just do . to also delete
the words 'some more text'):
(some initial text)
(some more text)
This way also works when the brackets (or quotes) are on different lines. For
example, with the cursor somewhere between the {}, doing di} will change
this:
function( args ) {
body of function
}
to this:
function( args ) {
}

Related

Vim delete parent parenthesis and reindent child

I'm trying to go from here:
const f = function() {
if (exists) { // delete this
const a = 'apple'
}
}
to:
const f = function() {
const a = 'apple'
}
What's the fastest way to delete and reindent everything in between?
Assuming that cursor is inside the braces; any number of lines and nested operators; "else"-branch is not supported:
[{"_dd<]}']"_dd
Explanation:
[{ go to previous unmatched brace
"_dd delete the "{"-line (now the cursor is in the first line of the block)
<]} decrease identation until the next unmatched "}"
'] go to the last changed line (i.e. "}"-line)
"_dd and delete it
If the cursor is initially set on the "{"-line and you don't care for 1-9 registers, the command can be simplified to dd<]}']dd
Assuming your cursor is somewhere on the line containing const a
?{^M%dd^Odd== (where ^M is you hitting the Enter key and ^O is you hitting Ctrl+O).
Broken down this is:
?{^M - search backwards/upwards for the opening brace
% - jump to the corresponding brace (closing brace)
dd - delete the current line
^O - jump to previous location (the opening brace)
dd - delete the line
== - indent current line
You don't need a special macro or function or anything to do this since vim gives you all the powerful text manipulation tools to do the task. If you find yourself doing this an awful lot then you could always map it to a key combination if you want.
The above only works for single lines inside curly braces, but the one below will work for multiple lines (again assuming you are on some line inside the curly braces)
<i{0f{%dd^Odd I'll leave you to figure out how this one works. Type the command slowly and see what happens.
Great answers all around, and, as pointed out, you can always map these keys to a shortcut. If you'd like to try a slightly more generic solution, you could check my "deleft" plugin: https://github.com/AndrewRadev/deleft.vim

Select first word from each line in multiple lines with Vim

I would like to copy the first words of multiple lines.
Example of code :
apiKey := fmt.Sprintf("&apiKey=%s", args.ApiKey)
maxCount := fmt.Sprintf("&maxCount=%d", args.MaxCount)
id := fmt.Sprintf("&id=%s", args.Id)
userid := fmt.Sprintf("&userid=%s", args.Userid)
requestFields := fmt.Sprintf("&requestFields=%s", args.RequestFields)
I would like to have this in my clipboard :
apiKey
maxCount
id
userid
requestFields
I tried with ctrl-v and after e, but it copies like on the image :
You could append every first word to an empty register (let's say q) using
:'<,'>norm! "Qyiw
That is, in every line of the visual selection, execute the "Qyiw sequence of normal commands to append (the first) "inner word" to the q register.
You need to have > in cpoptions for the newline to be added in between yanks (:set cpoptions+=>), otherwise the words will be concatenated on a single line.
If you want to quickly empty a register you can use qqq in normal mode (or qaq to empty register a).
Note: the unnamed register ("") will also contain what you want at the end of the operation, so you don't need to "qp to paste it, p will do.
I think the chosen answer is a really good one, the idea of appending matches to registers can be pretty useful in other scenarios as well.
That said, an alternative way to get this done might be to align the right-hand side first, do the copying and then undo the alignment. You can use a tool like tabular, Align or easy-align.
With tabular, marking the area and executing :Tab/: would result in this:
apiKey : = fmt.Sprintf("&apiKey=%s", args.ApiKey)
maxCount : = fmt.Sprintf("&maxCount=%d", args.MaxCount)
id : = fmt.Sprintf("&id=%s", args.Id)
userid : = fmt.Sprintf("&userid=%s", args.Userid)
requestFields : = fmt.Sprintf("&requestFields=%s", args.RequestFields)
You can now use visual block mode to select the first part, and then use u to undo the alignment.
Relying on the external cut program:
:'<,'>!cut -d' ' -f1

vim macro until pattern is matched

I have an array of states that no one is going to have to modify often, so I want to remove the white space.
I tried the following keystrokes as there are some whitespace characters between the commas in the array and the endlines:
q a /, ENTER FORWARD v /\n ENTER d
Unfortunately, whomever formatted this neglected to place any whitespace after 'Montana', so when I run the macro 51#a, it breaks after 27 iterations.
How can I have a macro only run a pattern if \s is matched, or better yet, how can I run a macro until it recognizes ); (end of array).
EDIT: Here is an example. Note the two white space characters after all entries except keys MT,NE,NV and NH.
$state_list = array('AL'=>"Alabama",
'AK'=>"Alaska",
'AZ'=>"Arizona",
'AR'=>"Arkansas",
'CA'=>"California",
'CO'=>"Colorado",
'CT'=>"Connecticut",
'DE'=>"Delaware",
'DC'=>"District Of Columbia",
'FL'=>"Florida",
'GA'=>"Georgia",
'HI'=>"Hawaii",
'ID'=>"Idaho",
'IL'=>"Illinois",
'IN'=>"Indiana",
'IA'=>"Iowa",
'KS'=>"Kansas",
'KY'=>"Kentucky",
'LA'=>"Louisiana",
'ME'=>"Maine",
'MD'=>"Maryland",
'MA'=>"Massachusetts",
'MI'=>"Michigan",
'MN'=>"Minnesota",
'MS'=>"Mississippi",
'MO'=>"Missouri",
'MT'=>"Montana",
'NE'=>"Nebraska",
'NV'=>"Nevada",
'NH'=>"New Hampshire",
'NJ'=>"New Jersey",
'NM'=>"New Mexico",
'NY'=>"New York",
'NC'=>"North Carolina",
'ND'=>"North Dakota",
'OH'=>"Ohio",
'OK'=>"Oklahoma",
'OR'=>"Oregon",
'PA'=>"Pennsylvania",
'RI'=>"Rhode Island",
'SC'=>"South Carolina",
'SD'=>"South Dakota",
'TN'=>"Tennessee",
'TX'=>"Texas",
'UT'=>"Utah",
'VT'=>"Vermont",
'VA'=>"Virginia",
'WA'=>"Washington",
'WV'=>"West Virginia",
'WI'=>"Wisconsin",
'WY'=>"Wyoming"
);
To:
$state_list=array('AL'=>"Alabama",'AK'=>"Alaska",'AZ'=>"Arizona",'AR'=>"Arkansas",'CA'=>"California",'CO'=>"Colorado",'CT'=>"Connecticut",'DE'=>"Delaware",'DC'=>"District Of Columbia",'FL'=>"Florida",'GA'=>"Georgia",'HI'=>"Hawaii",'ID'=>"Idaho",'IL'=>"Illinois",'IN'=>"Indiana",'IA'=>"Iowa",'KS'=>"Kansas",'KY'=>"Kentucky",'LA'=>"Louisiana",'ME'=>"Maine",'MD'=>"Maryland",'MA'=>"Massachusetts",'MI'=>"Michigan",'MN'=>"Minnesota",'MS'=>"Mississippi",'MO'=>"Missouri",'MT'=>"Montana",'NE'=>"Nebraska",'NV'=>"Nevada",'NH'=>"New Hampshire",'NJ'=>"New Jersey",'NM'=>"New Mexico",'NY'=>"New York",'NC'=>"North Carolina",'ND'=>"North Dakota",'OH'=>"Ohio",'OK'=>"Oklahoma",'OR'=>"Oregon",'PA'=>"Pennsylvania",'RI'=>"Rhode Island",'SC'=>"South Carolina",'SD'=>"South Dakota",'TN'=>"Tennessee",'TX'=>"Texas",'UT'=>"Utah",'VT'=>"Vermont",'VA'=>"Virginia",'WA'=>"Washington",'WV'=>"West Virginia",'WI'=>"Wisconsin",'WY'=>"Wyoming");
EDIT:
Just googled vim macro until pattern matched, and came across my own question. I have a better example now:
namespace A{
class a{}
class a{}
}
namespace B{
class b{}
class b{}
class b{}
}
Needs to become:
namespace A{
class Aa{}
class Aa{}
}
namespace B{
class Bb{}
class Bb{}
class Bb{}
}
This cannot be solved with the previously accepted answer.
Honestly the easiest answer would be to join the lines.
If you visual select the entire region and just press J (or feed the range to :join) all of the lines will end up on one line. (There may be excess whitespace in-between elements but thats easier to fix then trying to write the macro).
If you then want to remove the excess whitespace you could run
:s/,\s\+/,/g
on the joined line.
Take a look at :h J and :h :join
First of all, you can easily remove all trailing whitespace with one command:
:%s/\s\+$//e
That will work on every line of the file. If you want to do it only on this fragment of code, you can specify different range (instead of %, which is whole file). For example, you can pass line numbers (1 to 51):
:1,51s/\s\+$//e
or first visually select, and then run command removing whitespace (you have to be on the first line starting this sequence):
V/)<CR>:s/\s\+$//e
If you really want to use macro, you can slightly tweak (and simplify) your macro:
qa0f,lDq
and then run it on every line at once by first of all visually selecting all of them (again, start on line you want, I won't put gg here because it might be just part of the file):
V/)<CR>:normal #q
This will play the macro over every selected line, up to the line with ).
I hope it helps :)

Vim: How to write a function that searches the current buffer?

I am trying to write a function in Vim that searches the current buffer for a certain pattern and returns it. But, I'm failing horribly. Basically, what I want is a function that returns the (PHP) namespace of the file I am working in. The namespace is defined in the file itself:
namespace Foo\Bar;
What I would like is a function that returns the Foo\Bar part as a string. I.e. something that searches like /namespace\s\([^;]\+\) and returns the first submatch.
Edit: Here's the function I build thanks to the help I got:
func! PhpNamespace()
let l:lnr = 0
while l:lnr < line('$')
let l:str = matchstr(getline(l:lnr), '^\s*namespace\s\+[^;]\+')
if len(l:str)
return substitute(l:str, '^\s*namespace\s\+', '', '')
endif
let l:lnr = l:lnr + 1
endwhile
return ''
endfunc
One option is to use searchpos(), which gets you the start position; you then need to extract the text yourself. This is fast and easy, especially if you need to search forward / backward from the cursor position. With the 'n' flag, the cursor position will not change. Otherwise, you have to save and restore the cursor position (getpos('.'), setpos('.', saved_cursor)).
For your problem, it looks like the namespace declaration is likely at the beginning of the file, and is limited to a single line. Then, you could also get individual lines with getline(lnum) in a loop and extract the text with matchstr(), and break out of the loop once you have it.

Add a number of '=' in a rest (reStructuredText) document that equals to characters from last line?

I want to use a shortcut to add needed = (from Section/Title reStructuredText syntax) according to the last line.
So, suppose (being | the cursor position)
Title
|
and pressing an specific mapping mapped to a function, add a number of = that equals to the last line (where Title is), becoming:
Title
=====|
This sequence will get you close:
kyyp:.s/./=/g
Duplicate the previous line, then in that line, change every character to an equals sign. Map that to a key sequence you like, and try it out.
Another way:
:execute "normal " . strlen(getline(line(".") - 1)) . "i="
strlen(getline(line(".") - 1)) returns the lenght of the line above the current position. The result is that the command Ni= is executed, inserting = N times.
For a mapping I would have used:
put=repeat('=', col('$')-1)
For something more interactive, I would have use the same solution as Ned's.
(I don't like my mappings to change the various registers like #" or #/)
My vim-rst-sections vim plugin will convert lines to section headings:
http://www.vim.org/scripts/script.php?script_id=4486
In your case, you'd put the cursor on the line, and type <leader><leader>d to get a top-level heading like this:
#####
Title
#####
A few repeats of <leader><leader>d will take you down to the standard hierarchy of Python ReST sections to the =.

Resources