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 ) {
}
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
I have a file like this:
foo
bar
And I'm trying to get something like:
foo: foo,
bar: bar,
I've tried :%s/^\w/\0: \0,/g where ^\w matches the first word in line but I'm getting
f: f,foo
b: b,bar
Someone can explain to me what I'm doing wrong?
You are missing two characters (\+) which extend the match to the entire word, because \w only matches one character of a word and not the whole word.
The following should do what you want.
%s/^\w\+/\0: \0,/g
Instead of replacing you could (globally) copy, paste and append:
:g/\v^.+$/normal! yEPa: ^[A,
(where ^[ is escape, entered as <c-v><esc>)
or use (lower-case) e if that is the kind of "word" you want
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 :)
I have a lot of lines like this:
{ id: 22, name: 'Alice', score: 123, city: 'Atlanta', birthday: '1981/12/03'},
I want to use a VI (gvim to be exact) search and replace and empty the last two sets of single quotes.
you can use :normal cmd, sometimes it comes easier than the :s. for your example:
:norm! $F'di'3;.
will change your line into:
{ id: 22, name: 'Alice', score: 123, city: '', birthday: ''},
If you want to do this on all lines, you just :%norm! ..... You can combine the norm cmd with :g too, e.g. you want to do this transform on all lines with name:
:g/name:/norm! ...
Write a macro to achieve that. To start recording a macro, hit q followed by a register where you want to save it (for example under a register). Do it in command mode.
$F'di';;di'j
$ - go to the end of line
F' - search backwards for '
di' - delete what is between single quotes
;; - go to the previous single quotes
di' - delete again
j - go to line below
Finish a macro by hitting again q. Then, to apply a macro on a single line hit #a. To apply a macro on all lines type :%norm! #a
If you want to use search and replace, you can do this:
:%s/city: '.\{-}'/city: ''
and the same for the birthday field
:%s/birthday: '.\{-}'/birthday: ''
the "\{-}" is the same as "*" but uses de shortest match first algorithm. (see :help non-greedy)
if you really like do this in a single command:
%s/\(city:\|birthday:\) '.\{-}'/\1 ''/g
"city:" and "birthday:" are matched as a sub-expression with the \( and \), then you can use the \1 (means the first sub-expression) in the substitute string, the end g option is needed to make more than one substitution in a single line.