Vim - how to replace with match without last char? - vim

I would like to fix every line in code which has following pattern:
int main() {
with
int main()
{
Same applies for if statements and loops. Simply said - fixing brackets. I have matched them with:
:%s/.*\(.*\).*{/&^?^M{/gc
But I get the following output:
int main() {
{
How do I replace my pattern with it's match (&), but without the last character or specifically without the "{" ?

%s/.*(.\{-})[^{]*\zs{/\r&/
this command works for your example, add flag g or gc if you need them. however you may want to check if the indentation also correct if you apply it on you real source file.
I think there should be special tool for the code style fixing.. you should check it. IMO, Vim/shell script would be the last option for those source codes batch editing.

Related

How to format the std::process::Command as a string for debugging

Working on my first rust app, and it issues a number of commands via std::process::Command. If one of these is incorrect I'd like to see what it is, and to have it look pretty on the command line.
Currently I have code that looks like this (simplified):
let mut command = std::process::Command::new("ls");
command.arg("-la");
println!("{:?}", command)
This is alright, but it encloses everything in quotes when it prints the string. The output looks like: "ls" "-la".
How can I format this so that it doesn't enclose each arg in double quotes, but instead produces a command that is easy to read? Something like: ls -la.
I saw a related issue, but it comes to the same mediocre solution.
Command adds the quotes because, while they're "ugly," they never break a command. On the other hand, not having them can! Parsing whether you need them or not, including all edge cases, can get surprisingly complicated.
If you have a tightly controlled set of use cases, and you are certain that you don't need them, then just remove them:
let mut command = std::process::Command::new("ls");
command.arg("-la");
println!("{}", format!("{:?}", command).replace("\"", ""));

Multi-line edit starting at the same character (= sign) [no macros?]

I'm working on an ansible playbook, where VIm seems to prove to be an extremely useful tool for (lots of similar patterns in style/formatting and such), and I'm hoping to take my current situation (since been written) to turn it into a Vim lesson.
I've made extensive use of code blocks to make multi-line edits, but I think I've reached their limit and wanted to reach out to figure out how I might approach making line edits more dynamically. In this scenario, I have a block of code that I'm trying to transform
from:
rcon.port=25575
rcon.password=strong-password
enable-rcon=true
into:
- { regexp: '^rcon.port', line: 'rcon.port=25575' }
- { regexp: '^rcon.password', line: 'rcon.password=strong-password' }
- { regexp: '^enable-rcon', line: 'enable-rcon=true' }
To do that, the first part is fairly simple. Shift-I, then ctrl-V for block, traverse lines to edit, type - { regexp: '^" to get to the following:
- { regexp: '^rcon.port=25575
- { regexp: '^rcon.password=strong-password
- { regexp: '^enable-rcon=true
Unfortunately, from there I'm a bit lost as the macros (and whether or not that's overkill or not) are still a bit unclear to me. Are there any possible approaches to solve this problem other than macros?
I'm not looking for a full solution, but simply a hint for the best (or only approach) here, and if there are any tricks to thinking about this in the Vim way.
Any links to good documentation/learning resources for macros would be AWESOME as well! I'm still new to Vim, so bear with me... thanks!
Building off #Stephen Warren's answer the following works as required:
:%s/^\(\(.\+\)=.\+\)/- regex: '\2', line: '\1' }/
The match section is:
From the beginning of the line ^
It has two groups rather than one \(\)
The first group is the outer one that matches the entire line
The second group is the inner group that matches up to the =
Match one or more characters \+ is used rather than the greedy * for matching either side of the =
The replace section:
Basically your expected output calling on the previously matched groups \1 and \2
Perhaps something like the following regular expression substitutions:
:%s/^\(.*\)$/- { regexp: '^\1' }/
Or with all relevant lines visually selected:
CTRL-o
:s/^\(.*\)$/- { regexp: '^\1' }/
I guess I should explain that a bit more:
: Enter command mode.
% Apply to all lines.
s Substitute.
/xxx/yyy/ Replace xxx with yyy.
^ Anchor at start of input string
(xxx) (in match string) capture whatever matches xxx.
\1 (in replacement string) replace with whatever matched (xxx).
.* Match any amount of any characters.
$ Anchor at end of input string.
Replacement string is emitted into the result literally without any interpretation, except for stuff like \1.

VIM - Reformatting indentation and braces

When working with blocks of code in VIM, I'm able to easily re-indent blocks of code via selecting a region in visual mode (SHIFT+v), then just hit =. This re-tabs lines of code, uses the correct indentation depths, hard-tabs vs spaces, etc.
I have a large set of functions I need to re-factor, and I have several blocks of code with braces on the same line as if/else keywords, ie:
if(something) {
doFunction(something);
} else if(somethingElse) {
doFunction(somethingElse);
} else {
// default stuff to do
}
And I would like to change the brace and spacing style to:
if ( something ) {
doFunction( something);
}
else if ( somethingElse )
{
doFunction( somethingElse );
}
else
{
// default stuff to do
}
The differences include:
Having the opening/closing braces on their own dedicated line
The argument to if, else if, and functions has a space separating the beginning and end of the argument list from the surrounding round brackets.
There is a space between if/else if and the argument brackets, but not for function names and the argument brackets.
Is there a way to set this style as the default in VIM, and to also have re-indentation commands change the style to match the latter of the two I've provided? I've found tools to enforce things like line endings, tabs-vs-spaces, etc, but not style details like those shown above.
Thank you.
The indentation scripts in vim are not constructed for so complex tasks. I would advise you to use the indent command, in particular the following arguments:
-prs, --space-after-parentheses
Put a space after every '(' and before every ')'.
See STATEMENTS.
-sai, --space-after-if
Put a space after each if.
See STATEMENTS.
You should read the command's man page for more details.
Obviously, this command can be used to filter the buffer's content using:
:%!indent

Inject a code into the unique function in multiple files (Sublime editor)

Taking the advice of Xaelias I'll modify this post, because the initial question was quite unclear and overcomplicated.
So basically I have multiple script files that need to be edited (too many of them to afford to edit them manually). What I need to do for each script file is to insert a certain code at a specific location inside each of them.
So if my script file was called foo.script, and if the code inside it was as follows:
cut_bar() {
some code...
}
cut_cabbage() {
some code...
}
...
Then I'd like my final look of the foo.script file to be as follows:
cut_bar() {
some code...
message msg_foo_bar
}
cut_cabbage() {
some code...
message msg_foo_cabbage
...
(cut_ is a universal prefix shared by all those functions inside of which the code needs to be added).
Is there any way I can do this in Sublime Text editor? Or is there no other way but to develop a small program that does all of this (in which case, tips would be appreciated likewise!).
We'll try a first solution, which is far from perfect, but might be enough for what you want to do. If it does not work, we'll try another solution.
You want to do a search and replace (⌥⌘F (on mac) or Find→Replace...).
Make sure that the RegEx modifier is active (.* on the left)
Find What: (?<=^cut_)(.*?)(\(\)\h*\{(?:.|\v)*?)(^\}\h*$) (explanations below)
Replace With: \1\2\tmsg_foo_\1\n\3
If it does not work as intended, maybe we'll just need to tweak a little the RegEx. Or maybe we'll need to resort to python and ST plugins!
RegEx explanation:
(?<=^cut_): we want our match to start at the beginning of a line (^) with cut_ this is not captured because as you said, this is a constant, so we don't really care
(.*?): this matches the rest of the name of the method. This is captured and will be \1
(\(\)\h*\{(?:.|\v)*?): we stop the name capture at (), \h is for any horizontal space (spaces or tabs) that could be between the end of the name, and {, then we match every character and \v (vertical space such as new lines) (this is captured as \2)
(^\}\h*$): ... up until we meet a line that starts with }, and might have any kind of horizontal space before the end of the line ($), this is captured as \3
From there, the replace part is kind of straightforward I guess.
\1\2\ is everything we captured but do not want to modify (the name of the method, and its body, except for the last line })
Then we put what you wanted, msg_foo_\1 which will transform into msg_foo_bar for example, and then put back the ending }

Swap text around equal sign

Is there an easy way to flip code around an equal sign in vi/vim?
Eg: I want to turn this:
value._1 = return_val.delta_clear_flags;
value._2._1 = return_val.delta_inactive_time_ts.tv_sec;
value._2._2 = return_val.delta_inactive_time_ts.tv_nsec;
value._3 = return_val.delta_inactive_distance_km;
(...)
into this:
return_val.delta_clear_flags = value._1;
return_val.delta_inactive_time_ts.tv_sec = value._2._1;
return_val.delta_inactive_time_ts.tv_nsec = value._2._2;
return_val.delta_inactive_distance_km = value._3;
(...)
on A LOT of lines in a file.
I know this seems a little trivial, but I've been running into lots of cases when coding where I've needed to do this in the past, and I've never had a good idea/way to do it that didn't require a lot of typing in vim, or writing a awk script. I would think this would be possible via a one liner in vi.
Explanations of the one-liners is very welcome and will be looked upon highly when I select my accepted answer. :)
Something like this:
:%s/\([^=]*\)\s\+=\s\+\([^;]*\)/\2 = \1
You might have to fiddle with it a bit if you have more complex code than what you have shown in the example.
EDIT: Explanation
We use the s/find/replace comand. The find part gets us this:
longest possible string consisting of anything-but-equal-signs, expressed by [^=]* ...
... followed by one or more spaces, \s\+ (the extra \ in front of + is a vim oddity)
... followed by = and again any number of spaces, =\s\+
... followed by the longest possible string of non-semicolon characters, [^;]*
Then we throw in a couple of capturing parentheses to save the stuff we'll need to construct the replacement string, that's the \(stuff\) syntax
And finally, we use the captured strings in the replace part of the s/find/replace command: that's \1 and \2.
For interest's sake, here's how I did it as a recorded macro:
qq0"+df=xA<BACKSPACE> = <ESC>"+pxi;<ESC>jq
Peforming that on the first line sets the "q" macro to do what's required. Then on each subsequent line you can execute the macro by typing:
#q
or, say you want to apply the macro to the next 10 lines:
10#q
I always find macros easier for a quick switch like this than figuring out the regex, because they're essentially an extension of how I would do it by hand.
Edit: Dan Olson points out in his comment that if you want to then apply the macro to a range of lines, for instance lines 6-100, you can enter the following. I don't know if there's a more concise syntax that doesn't require the ".*" pattern match.
:6,100g/.*/normal #q
Explanation of the macro
qq
start recording in register q
0
go to beginning of line
"+df=
delete up to the '=' and put the text into the '+' register
x
delete extra space
A
go to end of line and enter insert mode
<BACKSPACE> = <ESC>
Delete the semicolon, insert an equals sign and a space
"+p
insert the test copied earlier into register '+'
xi;<ESC>
reinsert the trailing semicolon
j
move down to the next line, ready to reapply the macro
q
stop recording
:%s/^\s*\(.\{-}\)\s*=\s*\(.\{-}\)\s*;\s*$/\2 = \1;/
should work nicely.
:%s/\([^ =]*\)\s*=\s*\([^;]*\);/\2 = \1;/

Resources