how to replace string with result of function in Vim? - vim

I want to insert filename and line number into some places in the file. For example this line:
_debug('init');
I want to replace
:s/debug('/debug('(%current_filename_here%:%current_line_number_here%)\ /g
to get this
_debug('(filename.ext:88) init');
I try to use expand('%:t') to get filename and line(".") to get line number, but I don't know how to use it in replace expression.
How can I do this?

You can use \=. For example:
:s#_debug('\zs#\=printf('(%s:%d) ', expand('%:t'), line('.'))#
When the {replacement} starts with "\=" it is evaluated as an expression,

Related

Match on lines that have one string and NOT another

I am able to match strings in lines of a file like so:
re.search(r"\b10/100/1000\b", line) and re.search(r"notco*", line):
However, I need to be able to match lines that have one string, UNLESS they have another.
Example: Match pattern of '40G' unless the line also contains the pattern 'Po'
just negate the second search:
re.search("40G",line) and not re.search("Po",line)
if no need for regex, then ... no need for regex, use in:
"40G" in line and "Po" not in line

insert n characters before pattern

I have a text file where I want to insert 20 spaces before the string 'LABEL'. I'd like to do this in vim.
I was hoping something like s/LABEL/ {20}LABEL/ would work. It doesn't.
This SO question is close to what I want to do, but I can't put 'LABEL' after the '=repeat()'. Vim regex replace with n characters
%s/LABEL/\=repeat(' ',20)/g works.
%s/LABEL/\=repeat(' ',20)LABEL/g gives me E15: Invalid expression: repeat(' ',20)LABEL
How do I get vim to evaluate =repeat() but not =repeat()LABEL?
After \=, a string is expect. And LABEL isn't a valid string
%s/LABEL/\=repeat(' ',20).'LABEL'/g
BTW thanks to \ze, you don't need to repeat what is searched.
%s/\zeLABEL/\=repeat(' ',20)/g
Note that if you need to align various stuff, you could use printf() instead
%s#label1\|other label#\=printf('%20s', submatch(0))#

vim macro replacing \n with ','

I am trying to save a macro which replaces \n with ,
Input:
978818
978818
900298
900272
Output:
'978818','978818','900298','900272'
When I saved the macro using CTRL+R CTRL+R,B in vimrc it looks like below:
let #b = ":%s/\n/','/g^MI'^[A~#kb~#kb^["
But now when I run this macro it give the output as:
978818978818900298900272
and error:
E486: Pattern not found: ','
Don't know why it is trying to match ,
You probably need to escape the \n. vim thinks you want a new line character at that point in the string and replaces it with a literal new line. So the fixed macro should be.
let #b = ":%s/\\n/','/g^MI'^[A~#kb~#kb^["
Edit: If you want something that you can copy and paste-able I believe the macro below is equivalent to what you want.
let #b = ":%s/\\n/','/g\nI'\e$xx"

Substituting everything from = to end of the line in VIM

Let's say I have several lines like:
$repeat_on = $_REQUEST['repeat_on'];
$opt_days = $_REQUEST['opt_day'];
$opt_days = explode(",", $opt_days);
... and so on.
Let's say I use visual mode to select all the lines: how can I replace everything from = to the end of the line so it looks like:
$repeat_on = NULL;
$opt_days = NULL;
$opt_days = NULL;
With the block selected, use this substitute:
s/=.*$/= NULL;
The substitution regex changes each line by replacing anything between = and the end of the line, including the =, with = NULL;.
The first part of the command is the regex matching what is to be replaced: =.*$.
The = is taken literally.
The dot . means any character.
So .* means: 0 or more of any character.
This is terminated by $ for end of line, but this actually isn't necessary here: try it also without the $.
So the regex will match the region after the first = in each line, and replace that region with the replacement, which is = NULL;. We need to include the = in the replacement to add it back, since it's part of the match to be replaced.
When you have a block selected, and you hit : to enter a command, the command line will be automatically prefixed with a range for the visual selection that looks like this:
:'<,'>
Continue typing the command above, and your command-line will be:
:'<,'>s/=.*$/= NULL;
Which will apply the replacement to the selected visual block.
If you'll need to have multiple replacements on a single line, you'll need to add the g flag:
:'<,'>s/=.*$/= NULL;/g
Some alternatives:
Visual Block (fast)
On the first line/character do... Wl<C-v>jjCNULL;<Esc>bi<Space><Esc>
Macro (faster)
On the first line/character do... qqWllCNULL;<esc>+q2#q
:norm (fastest)
On the first line do... 3:no<S-tab> WllCNULL;<Enter>
Or if you've visually selected the lines leave the 3 off the beginning.

How to paste the results of a :g/foo/p search at the end of the file ?

1) I search foo in a file with the global command :g :
:g/foo/p
and I want to paste the results at the end of the file. How must I proceed ?
2) Same question (or is it ?) with the results of an echo statement :
:echo IndexByWord(['word1', 'word2', 'word3', etc])
(about this function, see : Vim : how to index a plain text file?)
Thanks in advance
I don't know about (2), but for (1), change it to :g/foo/t$. This will copy (t) the line to the last addressable line ($).
You can redirect the messages to a register
:redi #"
:g/foo/p
:redi END
:$pu
2) :call append('$', split(IndexByWord(['foo', 'bar']), '\n'))
:h append(
append({lnum}, {expr}) *append()*
When {expr} is a |List|: Append each item of the |List| as a
text line below line {lnum} in the current buffer.
:h split(
split({expr} [, {pattern} [, {keepempty}]]) *split()*
Make a |List| out of {expr}.
Using '$' as lnum is equal to the last line in the buffer.
You need to use split() because the function you referred to, IndexByWord(), returns a string. It looks to me that you might want to change IndexByWord() to return a list.
If you change this line in IndexByWord():
return join(result_list, "\n")
into
return result_list
Appending is a bit simpler then:
:call append('$', IndexByWord(['foo', 'bar']))

Resources