Comment/Uncomment in Vim using Regex - regex

I'm trying to use :'<,'>s!^!// ! to comment out highlighted code in visual mode. Is it possible to edit the regex so that it uncomments the code if it is already commented?

Some of the other answers mention plugins. I currently use NERD commenter, which provides a ci (comment invert) command that does what you want.
For starters, here are a couple of ways to avoid commenting out lines that are already commented. For simplicity, I will assume that the comment characters are all in the first column. Either one accepts a range, such as the Visual range '<,'> in your question.
:s#^\(// \)\#!#// #
:v#^// #s!^!// !
OK, if you really want a single command that toggles whether a line is commented out, then you have to capture whether the line is initially commented and then replace with an expression:
:%s!^\(// \|\)!\=strpart('// ', strlen(submatch(1)))
:help /\(
:help /\#!
:help :g
:help sub-replace-expression

A dirty but very versatile trick I use is to exploit the :normal command, that will emulate keystroke sequence you give on the given range.
For instance, to comment, select your whole lines in visual mode (using V) and enter the command :
:normal i//
This is quiet self-explanatory : i open edit mode, and // writes it (because you entered edit mode); the command will be applied to every selected line, with the cursor positioned to the beginning of the line (because we selected whole lines with V and not v; it gets tricky otherwise). With the same idea, you can remove the commenting on a visual selection using :
:normal xx
(This does exactly what it says : deletes the first two characters, as you would type on your keyboard).
There is several pros for this approach, including :
If you use several different languages with different comment signs ({ , /*, //, #, %) , it's just a matter of changing a single strokes.
You can really get creative with the normal command, since you can exploit marks for the command's range, and literally do anything :
:normal A //Hello world
Again, it feels very natural because you are simply feeding a command with the keystroke you would have used on your selection. You can even switch between modes using this trick.

well, I doubt you can do it using only one regex, and that's why Tim Pope has written an extension exactly for that:
https://github.com/tpope/vim-commentary
then all you have to do is gc to comment a line or a visual selection, and gc to uncomment it!

There are several plugins that work to comment and uncomment code across multiple languages. That being said, you would probably want to use two separate regexes in this case. For example, say I have some code...
var x = 5;
// Does stuff 5 times
for ( var i = 0; i < x; i++ ) {
// stuff
}
When I run said regex on this I don't want the already commented lines to be uncommented. So it's better to do something similar, but in reverse (e.g. :'<,'>s!^// !!).
Also, the \ze and \zs operators can be useful here to preserve whitespace. And :* is a shortcut for :'<,'>. For instance I could do
:*s!^\s*\zs// !!
This will remove only the characters // from lines that start with them or with whitespace before them.

Related

mIRC Search for multiple words in text file

I am trying to search a text file that will return a result if more than one word is found in that line. I don't see this explained in the documentation and I have tried various loops with no success.
What I would like to do is something similar to this:
$read(name.txt, s, word1|word2|word3)
or even something like this:
$read(name.txt, w, word1*|*word2*|*word3)
I don't know RegEx that well so I'm assuming this can be done with that but I don't know how to do that.
The documentation in the client self is good but I also recommend this site: http://en.wikichip.org/wiki/mirc. And with your problem there is a nice article : http://en.wikichip.org/wiki/mirc/text_files
All the info is taken from there. So credits to wikichip.
alias testForString {
while ($read(file.txt, nw, *test*, $calc($readn + 1))) {
var %line = $v1
; you can add your own words in the regex, seperate them with a pipe (|)
noop $regex(%line,/(word1|word2|word3|test)/))
echo -a Amount of results: $regml(0)
}
}
$readn is an identifier that returns the line that $read() matched. It is used to start searching for the pattern on the next line. Which is in this case test.
In the code above, $readn starts at 0. We use $calc() to start at line 1. Every match $read() will start searching on the next line. When no more matches are after the line specified $read will return $null - terminating the loop.
The w switch is used to use a wildcard in your search
The n switch prevents evaluating the text it reads as if it was mSL code. In almost EVERY case you must use the n switch. Except if you really need it. Improper use of the $read() identifier without the 'n' switch could leave your script highly vulnerable.
The result is stored in a variable named %line to use it later in case you need it.
After that we use a noop to execute a regex to match your needs. In this case you can use $regml(0) to find the amount of matches which are specified in your regex search. Using an if-statement you can see if there are two or more matches.
Hope you find this helpful, if there's anything unclear, I will try to explain it better.
EDIT
#cp022
I can't comment, so I'll post my comment here, so how does that help in any way to read content from a text file?

Vim: How to apply external command only to lines matching pattern

Two of my favorite Vim features are the ability to apply standard operators to lines matching a regex, and the ability to filter a selection or range of lines through an external command. But can these two ideas be combined?
For example, I have a text file that I use as a lab notebook, with notes from different dates separated by a line of dashes. I can do something like delete all the dash-lines with something like :% g/^-/d. But let's say I wanted to resize all the actual text lines, without touching those dash lines.
For a single paragraph, this would be something like {!}fmt. But how can this be applied to all the non-dash paragraphs? When I try what seems the logical thing, and just chain these two together with :% v/^-/!fmt, that doesn't work. (In fact, it seems to crash Vim...)
Is there a way to connect these two ideas, and only pass lines (not) matching a pattern into an external command like fmt?
Consider how the :global command works.
:global (and :v) make two passes through the buffer,
first marking each line that matches,
then executing the given command on the marked lines.
Thus if you can come up with a command – be it an Ex command or a command-line tool – and an associated range that can be applied to each matching line (and range), you have a winner.
For example, assuming that your text is soft-wrapped and your paragraphs are simply lines that don't begin with minus, here's how to reformat the paragraphs:
:v/^-/.!fmt -72
Here we used the range . "current line" and thus filtered every matching line through fmt. More complicated ranges work, too. For instance, if your text were hard-wrapped and paragraphs were defined as "from a line beginning with minus, up until the next blank line" you could instead use this:
:g/^-/.,'}!fmt -72
Help topics:
:h multi-repeat
:h :range!
:h :range
One way to do it may be applying the command to the lines matching the pattern 'not containing only dashes'
The solution I would try the is something like (not tested):
:g/\v^(-+)#!/normal V!fmt
EDIT I was doing some experiments and I think a recurvie macro should work for you
first of all set nowrapscan:
set nowrapscan
To prevent the recursive macro executing more than you want.
Then you make a search:
/\v^(-+)#!
Test if pressing n and p works with your pattern and tune it up if needed
After that, start recording the macro
qqn:.!awk '{print $2}'^M$
In this case I use awk as an example .! means filter current line with an external program
Then to make the macro recursive just append the string '#q' to the register #q
let #q .= '#q'
And move to the beggining of the buffer to apply the recursive macro and make the modifications:
gg#q
Then you are done. Hope this helps

How do I substitute selected contents despite any regex characters in vim?

In following code:
int return_int_func() { return 0; }
float fv = return_int_func();
Obviously, compiler will warn me fv may lost precisions because of auto-casting. Face lots of those things, I want replace all stuffs with substitute command. In short, I want this:
float fv = static_cast<float>(return_int_func());
But real codes has lots of forms like that:
float fv = obj.int_field;
float fv = obj->load_int_field("name");
float fv = xx.yy->zz;
I want select my target (obj.int_field,obj->load_int_field("name") or xx.yy->zz) and replace it with static_cast<float>(\1). I tried this:
:'<,'>s/\%V/static_cast<float>(&)/g
But vim replaces all characters in selected word with static_cast... and that isn't what I want at all. Then I tried this:
:'<,'>s/\(\%V\)/static_cast<float>(\1)/g
Vim also do the same thing. I have no idea how to replace whole content (and despite any regex characters) with my pattern. Any suggestions?
The solution is almost too easy! Here it is.
:s/\%V.*\%V./static_cast<float>(&)/
This is actually almost the same as the example from the :help. We can take away from this that we should all just have looked up :h /\%V first thing in the morning ...
\%V is a zero-width atom that matches stuff that is selected in Visual mode. Here it can match at the start of the Visual area. .* then matches (greedily) as much as it can; its greediness is reined in by the final \%V., which requires the last character of the match also to lie within the Visual area.
Tip: If you need to make this change many times over many lines, define the following mappings (even better: put them in your vimrc permanently).
nnoremap & :&&<CR>
xnoremap & :&&<CR>
Then you can repeat the substitution shown above by simply selecting something, and then pressing & to perform the substitution.
Let me try to paraphrase your question: You would like to Visual select some text, and then perform a substitution, where the selected text is also part of the replacement text.
I think in this case a macro is a much better tool.
To create the macro, first select the first piece of text that you want to wrap in the static cast. For example, select return_int_func(). (For each step, I'll show what the buffer looks like.)
When you're ready, press qq to start recording into register q, then press c.
float fv = |;
Type the left part of your wrapper text, static_cast<float>(.
float fv = static_cast<float>(|;
Press CTRL-R " (Control-R followed by "): this will reinsert the original text.
float fv = static_cast<float>(return_int_func()|;
Type ) to complete the change, and then Escape to leave insert mode.
float fv = static_cast<float>(return_int_func()▉;
Finally, press q to stop recording.
At this point you have made the first change and also recorded it as a macro in register q.
For all remaining changes, simply select a target such as obj->load_int_field("name") and press #q to repeat the change.
Look up :help 10.1 for more information about macros.
The \%V facility is really not for acting on the selected text as a whole; more for searching inside of that text.
Assuming that you are going to be putting this into a function or maybe mapping this to a key combination, here is an alternative approach that does what you are looking for:
:exec 'normal! gv"adistatic_cast<float>('|exec 'normal! "apa)'
Note that this will use your a buffer, so if you want to use another buffer you can change the two instances of "a with "x, where x is the buffer you wish to use.
Basically this is going to programmatically yank the selected text, insert static_cast<float>(, paste the text that was selected, and then insert ).
You can try
:%s/float fv =(.*)$/float fv = static_cast<float>(\1)/g
if I understood you right, you want to do text substitution only on selected text. This is not so easy to do, at least no so easy as a :s command can do. Because, your visual selection can be in single line, can cross multi lines, also it could char-wise, line-wise, block-wise..
but it can be done with this function:
function! SubVisualText(pat, repl,flag)
try
let v_save = #v
normal! gv"vy
let s = #v
let s = substitute(s, a:pat, a:repl,a:flag)
call setreg('v',s,visualmode())
normal! gv"vp
finally
let #v = v_save
endtry
endfunction
you use it by:
source the function
visual select the area (could be done by v, V or Ctrl-V)
:<ctrl-u>call SubVisualText(pattern, replacement, flag)<Enter>
the <ctrl-u> is for removing the leading range, since the function doesn't need the range.
when you run it, it looks like:(I just tested with Ctrl-V selection)

Vim: Invert string (by words)

This is my string:
"this is my sentence"
I would like to have this output:
"sentence my is this"
I would like to select a few words on a line (in a buffer) and reverse it word by word.
Can anyone help me?
It's not totally clear what the context is here: you could be talking about text in a line in a buffer or about a string stored in a VimScript variable.
note: Different interpretations of the question led to various approaches and solutions.
There are some "old updates" that start about halfway through that have been rendered more or less obsolete by a plugin mentioned just above that section. I've left them in because they may provide useful info for some people.
full line replacement
So to store the text from the current line in the current buffer in a vimscript variable, you do
let words = getline('.')
And then to reverse their order, you just do
let words = join(reverse(split(words)))
If you want to replace the current line with the reversed words, you do
call setline('.', words)
You can do it in one somewhat inscrutable line with
call setline('.', join(reverse(split(getline('.')))))
or even define a command that does that with
command! ReverseLine call setline('.', join(reverse(split(getline('.')))))
partial-line (character-wise) selections
As explained down in the "old updates" section, running general commands on a character- or block-wise visual selection — the former being what the OP wants to do here — can be pretty complicated. Ex commands like :substitute will be run on entire lines even if only part of the line is selected using a character-wise visual select (as initiated with an unshifted v).
I realized after the OP commented below that reversing the words in a partial-line character-wise selection can be accomplished fairly easily with
:s/\%V.*\%V./\=join(reverse(split(submatch(0))))/
wherein
\%V within the RE matches some part of the visual selection. Apparently this does not extend after the last character in the selection: leaving out the final . will exclude the last selected character.
\= at the beginning of the replacement indicates that it is to be evaluated as a vimscript expression, with some differences.
submatch(0) returns the entire match. This works a bit like perl's $&, $1, etc., except that it is only available when evaluating the replacement. I think this means that it can only be used in a :substitute command or in a call to substitute()
So if you want to do a substitution on a single-line selection, this will work quite well. You can even pipe the selection through a system command using ...\=system(submatch(0)).
multiple-line character-wise selections
This seems to also work on a multiple-line character-wise selection, but you have to be careful to delete the range (the '<,'> that vim puts at the beginning of a command when coming from visual mode). You want to run the command on just the line where your visual selection starts. You'll also have to use \_.* instead of .* in order to match across newlines.
block-wise selections
For block-wise selections, I don't think there's a reasonably convenient way to manipulate them. I have written a plugin that can be used to make these sorts of edits less painful, by providing a way to run arbitrary Ex commands on any visual selection as though it were the entire buffer contents.
It is available at https://github.com/intuited/visdo. Currently there's no packaging, and it is not yet available on vim.org, but you can just git clone it and copy the contents (minus the README file) into your vimdir.
If you use vim-addon-manager, just clone visdo in your vim-addons directory and you'll subsequently be able to ActivateAddons visdo. I've put in a request to have it added to the VAM addons repository, so at some point you will be able to dispense with the cloning and just do ActivateAddons visdo.
The plugin adds a :VisDo command that is meant to be prefixed to another command (similarly to the way that :tab or :silent work). Running a command with VisDo prepended will cause that command to run on a buffer containing only the current contents of the visual selection. After the command completes, the buffer's contents are pasted into the original buffer's visual selection, and the temp buffer is deleted.
So to complete the OP's goal with VisDo, you would do (with the words to be reversed selected, and with the above-defined ReverseLine command available):
:'<,'>VisDo ReverseLine
old updates
...previous updates follow ... warning: verbose, somewhat obselete, and mostly unnecessary...
The OP's edit makes it more clear that the goal here is to be able to reverse the words contained in a visual selection, and specifically a character-wise visual selection.
This is decidedly not a simple task. The fact that vim does not make this sort of thing easy really confused me when I first started using it. I guess this is because its roots are still very much in the line-oriented editing functionality of ed and its predecessors and descendants. For example, the substitute command :'<,'>s/.../.../ will always work on entire lines even if you are in character-wise or block-wise (ctrlv) visual selection mode.
Vimscript does make it possible to find the column number of any 'mark', including the beginning of the visual selection ('<) and the end of the visual selection ('>). That is, as far as I can tell, the limit of its support. There is no direct way to get the contents of the visual selection, and there is no way to replace the visual selection with something else. Of course, you can do both of those things using normal-mode commands (y and p), but this clobbers registers and is kind of messy. But then you can save the initial registers and then restore them after the paste...
So basically you have to go to sort of extreme lengths to do with parts of lines what can easily done with entire lines. I suspect that the best way to do this is to write a command that copies the visual selection into a new buffer, runs some other command on it, and then replaces the original buffer's visual selection with the results, deleting the temp buffer. This approach should theoretically work for both character-wise and block-wise selections, as well as for the already-supported linewise selections. However, I haven't done that yet.
This 40-line code chunk declares a command ReverseCharwiseVisualWords which can be called from visual mode. It will only work if the character-wise visual selection is entirely on a single line. It works by getting the entire line containing the visual selection (using getline()) running a parameterized transformation function (ReverseWords) on the selected part of it, and pasting the whole partly-transformed line back. In retrospect, I think it's probably worth going the y/p route for anything more featureful.
" Return 1-based column numbers for the start and end of the visual selection.
function! GetVisualCols()
return [getpos("'<")[2], getpos("'>")[2]]
endfunction
" Convert a 0-based string index to an RE atom using 1-based column index
" :help /\%c
function! ColAtom(index)
return '\%' . string(a:index + 1) . 'c'
endfunction
" Replace the substring of a:str from a:start to a:end (inclusive)
" with a:repl
function! StrReplace(str, start, end, repl)
let regexp = ColAtom(a:start) . '.*' . ColAtom(a:end + 1)
return substitute(a:str, regexp, a:repl, '')
endfunction
" Replace the character-wise visual selection
" with the result of running a:Transform on it.
" Only works if the visual selection is on a single line.
function! TransformCharwiseVisual(Transform)
let [startCol, endCol] = GetVisualCols()
" Column numbers are 1-based; string indexes are 0-based
let [startIndex, endIndex] = [startCol - 1, endCol - 1]
let line = getline("'<")
let visualSelection = line[startIndex : endIndex]
let transformed = a:Transform(visualSelection)
let transformed_line = StrReplace(line, startIndex, endIndex, transformed)
call setline("'<", transformed_line)
endfunction
function! ReverseWords(words)
return join(reverse(split(a:words)))
endfunction
" Use -range to allow range to be passed
" as by default for commands initiated from visual mode,
" then ignore it.
command! -range ReverseCharwiseVisualWords
\ call TransformCharwiseVisual(function('ReverseWords'))
update 2
It turns out that doing things with y and p is a lot simpler, so I thought I'd post that too. Caveat: I didn't test this all too thoroughly, so there may be edge cases.
This function replaces TransformCharwiseVisual (and some of its dependencies) in the previous code block. It should theoretically work for block-wise selections too — it's up to the passed Transform function to do appropriate things with line delimiters.
function! TransformYankPasteVisual(Transform)
let original_unnamed = [getreg('"'), getregtype('"')]
try
" Reactivate and yank the current visual selection.
normal gvy
let #" = a:Transform(#")
normal gvp
finally
call call(function('setreg'), ['"'] + original_unnamed)
endtry
endfunction
So then you can just add a second command declaration
command! -range ReverseVisualWords
\ call TransformYankPasteVisual(function('ReverseWords'))
tangentially related gory detail
Note that the utility of a higher-level function like the ones used here is somewhat limited by the fact that there is no (easy or established) way to declare an inline function or block of code in vimscript. This wouldn't be such a limitation if the language weren't meant to be used interactively. You could write a function which substitutes its string argument into a dictionary function declaration and returns the function. However, dictionary functions cannot be called using the normal invocation syntax and have to be passed to call call(dictfunct, args, {}).
note: A more recent update, given above, obsoletes the above code. See the various sections preceding old updates for a cleaner way to do this.
Maybe:
:s/\v(.*) (.*) (.*) (.*)/\4 \3 \2 \1/
Of course you probably need to be more specific in the first part to find that particular sentence. Generally you can refer to match groups as \number with \0 being the whole match.
Here's a way to do by calling out to Ruby. After selecting the line you want to reverse, you can do this in command mode to replace it:
!ruby -e 'puts ARGF.read.strip.split(/\b/).reverse.join'
I found the solution myself thank to your answers and a lot of trying :)
This works:
function! Test()
exe 'normal ' . 'gv"ay'
let r = join(reverse(split(getreg('a'))))
let #a = r
exe 'normal ' . 'gv"ap'
endfunction
Didn't thought that I was enable to write such a function :)

Easily comment (C++) code in vim

I have looked at the following question:
How to comment out a block of Python code in Vim
But that does not seem to work for me. How do I comment code easily without resorting to plugins/scripts?
Use ctrl-V to do a block selection and then hit I followed by //[ESC].
Alternatively, use shift-V to do a line-based select and then type :s:^://[Enter]. The latter part could easily go into a mapping. eg:
:vmap // :s:^://<CR>
Then you just shift-V, select the range, and type // (or whatever you bind it to).
You can add this to your .vimrc file
map <C-c> :s/^/\/\//<Enter>
Then when you need to comment a section just select all lines (Shift-V + movement) and then press CtrlC.
To un-comment you can define in a similar way
map <C-u> :s/^\/\///<Enter>
that removes a // at begin of line from the selected range when pressing CtrlU.
You can use the NERD commenter plugin for vim, which has support for a whole bunch of languages (I'm sure C++ is one of them). With this installed, to comment/uncomment any line, use <Leader>ci. To do the same for a block of text, select text by entering the visual mode and use the same command as above.
There are other features in this such as comment n lines by supplying a count before the command, yank before comment with <Leader>cy, comment to end of line with <Leader>c$, and many others, which you can read about in the link. I've found this plugin to be extremely useful and is one of my 'must have' plugins.
There's always #ifdef CHECK_THIS_LATER ... #endif which has the advantage of not causing problems with nested C-style comments (if you use them) and is easy to find and either uncomment or remove completely later.