How to echo special characters like %, <cfile> in Vim? - vim

Say I wanna see what directory I am in, I type
:echo .
and get the error message:
E15:Invalid expression .
How can I echo out those special characters like %, ., <cfile>?

There is a dedicated command to print the current directory path:
:pwd
(See :help :pwd and the whole “The current directory” section in the
help: :help current-directory.)
To quickly find out what paths Vim command-line specials are expanded
to, use
:echo expand('%:p:h')
or, shorter,
:!echo %:p:h
The former command is based on the expand() function that expands
wildcards and special keywords in a given argument (see :help expand).
The latter command takes advantage of the fact that wildcards are
expanded before running an external command (see :help cmdline-special).

You need to use expand()
For example
:echo expand("%:h")
prints the actual directory (of the currenct buffer).
See also :help expand
If you want to inquire about the current-directory (which is buffer independant), you should just du a :pwd. (See :help current-directory)
(Edit: changed from :cd to :pwd as per comment of ib).

Related

Vim Ack, Ag: Search in directory of file that you are editing in

I want to be able to search files that only reside in the directory of the file that I opened inside vim.
The documentary of Ack says:
:Ack[!] [options] {pattern n} [{directory}] *:Ack*
Search recursively in {directory} (which defaults to the current
directory) for the {pattern}. Behaves just like the |:grep| command, but
will open the |Quickfix| window for you. If [!] is not given the first
occurrence is jumped to.
On VimFandom I found that I could get the current directory of the file with
echo expand('%:p:h') but how could I get this to evaluate in the Ack command?
I'd need something like this:
:Ack searchpattern expand('%:p:h')
The expression register, "=, will let you evaluate an expression and put/paste the output. Using <c-r> on the command-line will insert content from a register.
:Ack pat <c-r>=expand('%:p:h')<cr>
For more help see:
:h "=
:h i_CTRL-R
Using :grep instead of :Ack
You can set 'grepprg' to use the silver searcher or other grep-like tool, e.g. ripgrep.
set grepprg=ag\ --vimgrep\ $*
set grepformat=%f:%l:%c:%m
:grep understands % and :h as parameters. This means you can do:
:grep pat %:h
For more help see:
:h 'grepprg'
:h :grep
If directory has no further children (otherwise is recursive search):
nnoremap <leader>f <Esc>:cd %:p:h<CR><Esc>:Ag<CR>
Where,
:cd %:p:h changes directory to the location of current file
:Ag<CR> directly goes to the interactive search window if you have fzf-vim
By "interactive search" I mean customizing your search pattern dynamically (try wildcard, test if adding more keywords, ...)
On the other hand, if you don't need the interactive search, you are sure what you look for, then:
nnoremap <leader>f <Esc>:cd %:p:h<CR><Esc>:Ag<Space>
Use :exe[cute]:
:exe 'Ack searchpattern ' . expand('%:p:h')
. (dot) means string concatenation.
I have a little mapping for cases like this: %% inserts the directory of the current file.
cnoremap <expr> %% filename#command_dir('%%')
And the function definition:
function filename#command_dir(keymap) abort
if getcmdtype() isnot# ':'
return a:keymap
endif
let l:dir = expand('%:h')
return empty(l:dir) ? '.' : (dir.'/')
endfunction

vim grep not finding anything

According to this documentation
http://vim.wikia.com/wiki/Find_in_files_within_Vim
if grep is used like
:vim[grep][!] /{pattern}/[g][j] {file} ...
it should be able to find files by a matching pattern.
I have a text file named text.txt in the directory where I am starting vim from.
Content of text.txt is
look for me
In vim I enter the command
:grep /look/gj *.txt
but I don't get any results. Although the file text.txt contains the string "look".
You are simply confusing two commands: :vimgrep and :grep.
:help :vimgrep uses internal methods for searching files and has its own syntax and flags.
:help :grep uses an external program for searching so it doesn't have a defined syntax; the syntax you use is determined by what external program is used under the hood.
You can't really expect the :vimgrep syntax to work in :grep.
You're using vim's syntax for grep instead of using grep(1) syntax.
As written here: How do I search in all files of my project using VIM?
Syntax for :grep is, by default, the same as the grep(1) command:
:grep 'my pattern.*' /path/to/dir
By default it will search the current directory (:pwd).
The major difference between :grep and :vimgrep is that :vimgrep (:vim for >short) uses Vim-compatible regular expressions, whereas :grep uses whatever >regular expressions your &grepprg uses.
The searches generally work in the current directory as well so I would check the output of :pwd and :ls to see if you are seeing what you expect to be seeing.
If you :cd ~ however, you can search subdirectories with vimgrep by using ** as the path:
:vim /look for me/ **/*.txt
I would also suggest that unless you have specific requirements, you do not use the g or j flags after the search pattern.

Opening a related file in vim

In Vim, how can I get the name of the current file, pass it to an external script, read the output of the script (which will be a filename) and open that file in vim in a new buffer? For example, I'm editing lib/foo.rb and want to open spec/foo_spec.rb automatically.
Here is a simple solution using backtick expansion:
:e `foo.sh %`
% is expanded by Vim to the current buffer name,
then the backtick expression is evaluated in a sub-shell,
and the result is used as argument for :e.
See :help expand() for %, and :help backtick-expansion for… backtick expansion.

Vim Open unite in current folder

I got the following hotkey mapping:
nnoremap <leader>f Unite file -path=~/Workspace
This works great, however, I want to make it so that path equals the current folder I'm in (which will be seperate from working directory).
Anyone know how I can make this happen? :S
You can use the expand() function to use %:p:h in places where a file name is not expected (these expansions are for file-name arguments, not others like what it appears to happen with your command)
:echo expand('%:p:h')
But you can't map that directly. It is a command that needs to be built "on-the-fly", so you can use :execute to build and execute an evaluated expression:
nnoremap <leader>f :exec "Unite file -path=" . expand('%:p:h')
How about using:
:UniteWithBufferDir file
or
:UniteWithCurrentDir file
(depending on what you want)
Unite allows dynamic argument by using backtick, as documented in the Unite help doc:
You don't have to use |:execute| for dynamic arguments.
You can use evaluation cmdline by ``.
Note: In the evaluation, The special characters(spaces, "\" and ":")
are escaped automatically.
>
:Unite -buffer-name=search%`bufnr('%')` line:forward:wrap<CR>
So in your case, the mapping will be:
:nnoremap <leader>f :Unite file -path=`expand('%:p:h')`

redirection to a file of a search in Vim

My problem is simple. I search a specific pattern in a file (let's say label in a Tex file)
:g/label/#
but there are lots of occurrences. So I'd like to redirect this output to another file to be able to work easily with it.
Do you have a trick or a command that I don't know?
it's not clear from the original post what you mean by "work easily with it" but it's often useful to see and quickly jump between all of the matches in a buffer without "extracting" the matches to a separate buffer.
vim has an internal grep built in. your example would be something like this (in vim, % denotes the current file)
:vimgrep /label/ %
This will take you to the first occurrence and report how many matches there were. What's cool is that you can look at all of the matches listed by opening up the quickfix error list using
:cope
Now you can just scroll around and press enter on a line to jump to the exact position of the match.
The quickfix error list is exactly the same buffer you use if you run make from inside vim and your compiler throws errors: it gives you a list of what and where the errors are.
After you've jumped to one location pointed by quickfix, you can go to forwards and backwards in the list via :cn and :cp. :ccl closes the error list.
You can also expand your "error" list via :vimgrepa /newpattern/ % or :vimgrepadd
The (documented) caveat is that vim's internal grep is slower than most native grep implementations (but you do get it "for free" in windows, for example). If you do have a grep installed, you can use :grep instead of :vimgrep for similar results.
quoting :help grep
Vim has two ways to find matches for a
pattern: Internal and external. The
advantage of the internal grep is that
it works on all systems and uses the
powerful Vim search patterns. An
external grep program can be used when
the Vim grep does not do what you
want.
The internal method will be slower,
because files are read into memory.
The advantages are:
- Line separators and encoding are automatically recognized, as if a file
is being edited.
- Uses Vim search patterns. Multi-line patterns can be used.
- When plugins are enabled: compressed and remote files can be searched.
You can also use the location list if you're already using the error list for dealing with compilation errors. just add l (for location) to the beginning of the grep command (:lvimgrep,:lvimgrepa :lgrep, :lgrepa) and use :lopen :ln :lp :lcl instead of the :c* ones.
For more commands consult
:help grep
:help quickfix-window
:help quickfix
:help quickfix-error-lists
:redir > matches.txt|execute 'g/foo/#'|redir END
See :h :redir, you can also redirect to registers, variables, the clipboard etc.
What you're doing is essentially 'grep -n label file' from command line. So you can run that command and > it into a file easily enough.
The derivation of 'grep' is even from basically the same source.
I've gotten this of the net at some point:
function GoToLine(mainbuffer)
let linenumber = expand("<cword>")
silent bd!
silent execute "buffer" a:mainbuffer
silent execute ":"linenumber
silent nunmap <Enter>
endfunction
command -nargs=1 GoToLine :call GoToLine(<f-args>)
function GrepToBuffer(pattern)
let mainbuffer = bufnr("%")
silent %yank g
enew
silent put! g
execute "%!egrep -n" a:pattern "| cut -b1-80 | sed 's/:/ /'"
silent 1s/^/\="# Press Enter on a line to view it\n"/
silent :2
silent execute "nmap <Enter> 0:silent GoToLine" mainbuffer "<Enter>"
" silent nmap <C-G> <C-O>:bd!<Enter>
endfunction
command -nargs=+ Grep :call GrepToBuffer(<q-args>)
Put it in your .vimrc, then :Grep Foo
Requires external grep program to work properly.
(Just an idea -- untested.)
You can delete all the lines with your pattern in it, write to another file, and undo the delete.
:g/label/d
:w matches
u

Resources