vim: how to replace a variable with its value in ~/.vimrc - vim

I would like something similar too this in my .vimrc.
let dir=“/home/user/Downloads/”
set path=$dir
nnoremap gr :grep '\b<cword>\b' $dir/*<CR>
The code above is wrong of course, but maybe you can understand what I am trying to do. I would like to set path to the value of dir to /home/user/Downloads/, and replace the word dir in the third line with the value of dir. I tried and failed, can anyone tell help me out, any help appreciated!

First of all, there are fancy quotes; you need to use plain (") ones. Other than that, the :let is okay.
let dir = "/home/user/Downloads/"
You could use :execute to evaluate the defined variable with :set, but it's easier to use :let, because it can change Vim options, too, with the special notation &{optionname}:
let &path = dir
For the mapping, if dir doesn't change during runtime, it's easiest to use :execute. Note how the quoted backslashes must be escaped (i.e. doubled):
execute "nnoremap gr :grep '\\b<cword>\\b' " . dir . "/*<CR>"
All that information is part of :help eval. Learn how the excellent and comprehensive help is structured; all the information is in there (you just need to know how to find it)!

You must use this notation:
let variable_name = "value"
and use straight quotes.

To set path:
set path=/home/user/Downloads/
or to append a directory to path.
set path+=/home/user/Downloads/
Path is an Vim variable which does not seem very appropriate to use if you are going to only use it for this one remapping. It would be better to declare you own variable, as path can also have many directories within it which will not work with grep.
let g:search_path="/path/to/your/dir"
nnoremap gr :grep '\<<cword>\>' <C-R>=eval("g:search_path")<CR>
Ctrl+R lets us insert a register here, when then use that to call the expression register, which we use to evaluate g:search_path.
Check out :help expr-register for more on that!
This will evaluate your g:search_path variable on every execution of the mapping, allowing you to change the path and not have to remap gr each time.

Related

Vim Custom Replace Function

Note: I'm currently using Neovim v0.2.2 (But I believe this shouldn't change anything related this post)
I'm currently attempting to create a function within vim that allows for easily replacing text.
I understand I can create a shortcuts and macros and all that, but ideally I just want to give 2 args, and not think about what specifics go where as this can interupt my thought process.
So I decided to just have a simple wrapper disguised as a function (Which I will create a command wrapper for as well, once I figure out what I did wrong here)
function! VisualReplace(query, replacement)
" Example = '<,'>s/query\%V/replacement/g
'<,'>s/a:query\%V/a:replacement/g
endfunction
As you can see, it's a very simple function that just applies the args in it's respective position, Yet, this fails even when called as a function using : call VisualReplace('some_query', 'some_replacement'
Alternatively, if you simply use the Example I have commented out directly, there's no issue, So I was hoping someoen could enlighten me on a potential fix
If need be, I could possibly look into string building & build it incrementally
Error msg:
Pattern not found: a:query\%V
General theory
Vimscript is evaluated exactly like the Ex commands typed in the : command-line. There were no variables in ex, so there's no way to specify them. When typing a command interactively, you'd probably use <C-R>= to insert variable contents:
:sleep <C-R>=timetowait<CR>m<CR>
... but in a script, :execute must be used. All the literal parts of the Ex command must be quoted (single or double quotes), and then concatenated with the variables:
execute 'sleep' timetowait . 'm'
Your function
In order to get the a:query and a:replacement arguments into :substitute, use :execute and either string concatenation or printf():
function! VisualReplace(query, replacement)
execute "'<,'>s/" . a:query . '\%V/' . a:replacement . '/g'
endfunction
Additional critique
Passing a range to a function is so common, there's special syntactic sugar for it: The range attribute to :function, and a:firstline and a:lastline implicit arguments. Read more about it at :help function-range-example. While your use case here seems to be specifically for visual mode, in general it's useful to keep the scope of functions as broad as possible.
#Ingo Karkat answered perfectly. However, I feel like there might be some workflow alternatives which might help. (Assuming you aren't trying to script this behavior)
Visual Star
It looks like you are build a search based on a visual section. You may want to consider using a visual-star plugin to simplify the process. Here is a an example of a visual star mapping:
xnoremap * :<c-u>let #/=#"<cr>gvy:let [#/,#"]=[#",#/]<cr>/\V<c-r>=substitute(escape(#/,'/\'),'\n','\\n','g')<cr><cr>
This mapping will allow you to visually select text and then execute * to make it a search pattern. Similar to how * works in normal mode on the current word.
Search refining
I get the impression that you are trying to refine your search pattern. Vim has a nice way of doing this with q/ or pressing <c-f> while searching with /. See :h q/. This will bring up the command-line window which will allow you to edit the query/command-line with all your normal Vim keys.
Search and Replace with gn motion
Sometimes doing a substitution is just overkill or doesn't quite fit the situation right. You can mimic a search and replace by using the gn motion to operate on a search pattern. By using an operator and the gn motion together you can use the dot command, ., to repeat the action easily.
Example:
/foo
cgnbar<esc>
Now you can use . to repeat the foo -> bar replacement. Use n to skip. You can use other operators as well, e.g. gU to uppercase.
See :h gn and :h operator for more help.
Related Vimcasts episodes:
Refining search patterns with the command-line window
Operating on search matches using gn
Search for the selected text

How to create a macro with vim commands?

I am trying to create a macro to use it globaly. I have inserted this command to my .vimrc file
let #c='<esc>:r c.c'
or
let #c=':r c.c'
but in both cases when I use "#c" on any file it only prints 'c>:r c.c' on the the file
Try adding a '^M' at the end of your macro, then "#c" should work. Else ':#c' should work as mentioned by ebenezer. You should use Ctrl+VEnter to insert '^M'.
let #c=':r c.c^M'
Best way would be to record the macro first and then save it to the .vimrc.
If these doesn't work, you can check the content of your register c using "cp and see if there is something missing.
This is described in another answer. Try something like this:
let #c = ':r c.c'
and then, in your file, use
:#c
to execute it.
If you want to include special characters in your macro (like Escape or Enter) then use a non-literal string (double quotes, not single quotes) and the correct syntax. See :help expr-string. You could use raw special characters, as #Amit suggests, but this will make your vimrc file hard to read.
Assuming that you are starting in Normal mode and want to type #c, there is no need to start off with an Escape.
For testing purposes, I tried
:let #c = ":echo 'foo'\<CR>"
and it worked as expected. I even added this line (without the leading :) to my vimrc file just to make sure, and tested it that way. This should work:
:let #c = ":r c.c\<CR>"

How to expand function arguments in Vim command line?

Vim's Utl plugin offers a convenient way for doing web queries from within the editor. When called directly from the command line, a dictionary lookup can be done like this:
:Utl ol http://dict.leo.org/?search=my+search+term
What's the correct way for defining a custom command with the same purpose (my+search+term being user input)? I can't seem to get <f-args> right with this one:
command -nargs=1 SearchLeo :exe ":Utl ol http://dict.leo.org/?search=" . expand("<f-args>")
What's the correct way of defining function arguments here? Or should I turn this into a more complete function? Thanks!
You probably don't need expand() here; it's just for expanding globs (like *.txt) or the special variables like % for the current file.
You're quoting the argument twice, once through <f-args> (<q-args> would be slightly more correct, though it only matters with a variable number of arguments), once literally.
Use this:
command -nargs=1 SearchLeo :exe ":Utl ol http://dict.leo.org/?search=" . <q-args>

File name expansion in vim when using set option=value

I'm trying to add an autocmd to vim that will execute whenever I open a file in a certain subdirectory and that sets the search path. Unfortunately path name expansion doesn't seem to work inside a set command.
Specifically I'd like to have a line like this in my vimrc:
setlocal path+=**;%:p:h
But this will just give me the literal value. Just calling expand() doesn't work either. Is there a way to get variable expansion to work here?
What about:
execute 'setlocal path +=**;' . fnameescape(expand('%:p:h'))
There's no need for the expansion of the current file's directory; just adding . to path will do. From the help:
To search relative to the directory of the current file, use:
:set path=.
Use
let &l:path.=(empty(&l:path)?(''):(',')).'**;'.escape(expand('%:p:h'), ',\*; ')
. This is much cleaner then using :execute 'setlocal path', especially knowing that fnameescape() was designed to escape paths for commands, not for options and I can say it is not really safe to use it here: it definitely is not going to escape comma and semicolon and add additional escape for space (one for escaping for :set, one for the option itself). (empty(&l:path)?(''):(',')) is here to imitate the behavior of set+=.

Vim search and highlighting control from a script

I'm writing a script in which I want to control searches programmatically, and get them highlighted. The search() function results are not highlighted (I think), so using that function is not of use to me.
What I want to do is use the 'normal /' command to search for a variable, but that doesn't seem to be straightforward. I can script the command:
execute 'normal /' . my_variable . '\<CR>'
(or other variations as suggested in the vim tip here: http://vim.wikia.com/wiki/Using_normal_command_in_a_script_for_searching )
but it doesn't do anything. I can see the correct search term down in the command line after execution of the script line, but focus is in the document, the search register has not been altered, and the cursor has not done any search. (It seems as though the < CR > isn't getting entered, although no error is thrown -- and yes, I have tried using the literal ^M too.)
I can at least control the search register by doing this:
execute 'let #/ ="' . a:term .'"'
and then the obvious thing seems to be to do a:
normal n
But that 'normal n' doesn't do anything if I run it in a script. Setting the search register does work, if I manually press 'n' after the scrip terminates the search happens (and highlighting appears, since hlsearch is on). I don't even care if the cursor is positioned, I just want the register pattern to be highlighted. But various combinations of 'set hlsearch' in the script don't work either.
I know I could use 'match()', but I want to get it working with regular search highlighting, and I wonder what I'm doing wrong. It must be something simple but I'm not seeing it. Thanks for any help.
run:
let #/ = a:searchStr
from inside your function then run
normal n
from outside your function (inside it does nothing) eg.
command -nargs=* Hs call MySearch() | normal n
or you can use:
set hlsearch
instead of normal n if you don't want the cursor to move
(I cannot work out another way of doing this without having something outside the function.)
If your script is using functions, then this quote from :help function-search-undo is relevant:
The last used search pattern and the redo command "."
will not be changed by the function. This also
implies that the effect of :nohlsearch is undone
when the function returns.
Vim usually tries to reset the search pattern (and a few other things) when a function ends, often you can get around this by adding the n (next search) to the end of a mapping, or using :map <expr> and having your function return the key sequence to be executed.
On closer inspection, it seems \<CR> is not picked up inside single quotes. Try using this instead:
execute 'normal /' . my_variable . "\<CR>"

Resources