VIM open c++ header file in vertical split by combining three commands - vim

I have indexed my c++ codebase with ctags, I can open a header file as follows:
:tag myfile.h
(It doesn't matter where myfile.h is located, as long as it is inside the indexed codebase it will open correctly in vim)
When I'm editing a c++ file, I can get the header filename as follows:
:e%<.h
e.g. when editing myfile.cpp, executing this command will display myfile.h on the command line.
A file can be opened in vertical split, by issuing:
:vs <myfile>
Now what I want to accomplish, is to have 1 command or function which I can use to open a header file of the corresponding c++ file that I'm currently editing in vertical split. Hence basically I want to combine the 3 above commands as if I would be doing a Unix pipe, e.g.:
:vs tag | e%<.h
" :vs to open file in vertical split
" :tag to find tag
" :e%<.h to get header filename
Obviously the Unix pipe doesn't work on vim, alternatively I've tried to write a function at which I assign the result of a command to a variable, e.g.
headerFileName = :e%<.h
Which apparently is not the correct way of doing this, I'm a bit lost here so I hope somebody can provide some help.

There exist several plugins that already do this (without needing a ctags database BTW).
For instance, with alternate (aka a.vim), you just have to type :VS from the header file or the source file to open the other one in a vertically split window.
Note that alternate have an option to tell where to find the other file (same directory, substitute on directory name, ...)
Otherwise, I suspect you are looking for expand() and :exe. If you write a function it may be
function! s:whatever() abort
let crt = expand('%:t:r')
vnew
exe 'tag '.crt.'.h'
endfunction
command! whatever call s:whatever()

Related

Vim long file paths break/split over multiple lines in quickfix window

A long file paths is broken up over multiple lines in the Vim quickfix window which then for example does not allow to jump to the error location displayed in the qf.
The file (and the lines around) are diplayed in the quickfix window as (the example is the output from neomakes pdflatex)
|| Enter file name:
|| /long/path/to/file/.../loca
tionOfTexFiles/myTexFile.tex|144 error| Emergency stop.
|| read
to be able to follow to the file line by lnext/cnext I should have
/long/path/to/file/.../locationOfTexFiles/myTexFile.tex|144 error| Emergency stop.
For quickfix files I have the following relevant (in my view) settings which are set to:
setlocal nolinebreak
setlocal nowrap
setlocal textwidth=9999
So I am wondering how I can display the file path in one line within the quickfix window?
On :make, Vim invokes 'makeprg', captures the output, and then parses it according to 'errorformat'. The latter does support multi-line error messages (cp. :help errorformat-multi-line), but that is mostly for what I would call intentional linebreaks, as specified by the compiler. What you suffer from is unintentional linebreaks because of line wrapping (due to overly long paths).
Now, I don't know about "neomakes pdflatex", but it looks like that tool creates the linebreaks, whereas it shouldn't, as Vim is capturing the output, and there's no receiving terminal (or user). Investigating in that direction (or opening an issue at the project's tracker) might be helpful.
The mentioned Vim options ('linebreak', 'wrap', etc.) have nothing to do with it. They apply to normal buffers; the quickfix buffer as such is not modifiable.
Workarounds
A possible workaround might be to :cd first to a directory that is "closer" to the processed files (or even :set autochdir); this might avoid the long paths in the output.
Alternatively, you may "unmangle" the output by adding a sed stage after the compiler:
let &makeprg .= "| sed -e 's/.../...'"
If I'm not mistaken, the issue is on pdflatex side. The || mark is a good indication: you'll have one per output line -- in case filename and/or lines numbers are recognized, they'll be fed in between the bars.
So. This means you'll need a way to fix the path names. It'll be better to do it outside vim. I'm not saying this is trivial. I'm just saying that if you can have a program able to fix pdflatex outputs, you'll just be one pipe away from the solution (plus a correct forwarding of error codes...).
If you prefer to implement it in vim script, this is possible. But you'll experience side-effects. In my BuildToolsWrapper plugin I'm able to post-process compilation output in vim side, but the result is far from being perfect. I'm working on getqflist() result, and parse each line. When I found a line where I want to fix the filename, it's not simply about fixing the filename but also about assigning a valid buffer number to it. See this function where I can replace a filename with another one. The magic happens where lh#buffer#get_nr() is used. Still you'd need to implement a vim script able to merge split filenames.
IOW: my understanding is that vim is not involved. It could be used to fix the issue, but IMO this is not the easier path to undertake.

Navigation of vim autoload functions without ctags

Is there any vim command or plugin which can jump from a reference of a function to its definition in a script file which is in one of the "autoload" directories except using ctags?
For example, put the cursor above "call xyz#abc#foo()" and enter such command will open file ".../autoload/xyz/abc.vim" and set the cursor position at "function xyz#abc#foo()"
I do not bother with generating tags file every time a new plugin is insalled.
(Sorry for the very late answer)
I use tags to navigate my autoloaded functions.
But I also have an old :SearchInRuntime sp autoload/xyz/abc.vim command that'll split open the autoload file we're looking for, if not already open.
But it shouldn't be to hard to implement the feature. Once you have the function name obtained with expand('<cword>') or whatever, you could
build the plugin name: let plgname = 'autoload/'.substitute(matchstr(fnname, '.*\ze#'), '#', '/', 'g').'.vim'
search for it: let matches = globpath('&rtp', plgname, 1, 1)
check you have only one match, ...
open the file: exe 'sp '.matches[0] -- more subtitle approaches may be required to avoid to open it several times.
and then search the function definition: call search('^\s*fun\%[ction]:\=\s\+'.fnname', ....)

Edit Help file outside doc directory causes tags not to work when copying in

I've created a help file under $VIM\vimfiles\doc. After nearly deleting it I wanted to edit it elsewhere and then copy it to the doc directory and then regenerate the tags.
The tags are generated , I can see them in the tagfile, but the file that I copy in, unique name, when I do :h sfcontents for eg and then ctrl-] on a tag I get the error "e426 tag not found"
If I edit the file in the $VIM\vimfiles\doc directory and then run either :Helptags or :helptags $VIM\vimfiles\doc the tag jump works
I can't attach a file but the help file looks something like
vim: filetype=help foldmethod=indent foldclose=all modifiable noreadonly
Table of Contents *sfcontents*
*sfsearch* - Search specific commands help
|count-matches-of-pattern|
|match-specific-column|
...
==============================================================================
count-matches-of-pattern
*count-matches-of-pattern*
:%s/pattern//gn
counts the number of the matches in a file eg count the number of spaces
not at the beginning of a line
:%s/[^ ]\+//gn
==============================================================================
*match-specific-column*
c=column l=line v=virtual column, ie ignore tabs and special chars
/\%5cx will match all occurrences of x at column 5.
/\%>5vx will match all occurrences of x after character 5. If there is a
tab character between poition 1 and position 5 the /\%5>v. against the
following line with a tab at position 4 will return the number 4
123 45
/\%>4cx\%<7cx will match all occurrences of x after column 4 and before
column 7
Or use |YankMatchesToReg| eg YankMatchesToReg /\%265v./x which copies
column 265 to register x across the whole file
==============================================================================
...
vim:tw=88:ts=4:ft=help:norl
I've ended up doing the archive out of the vim directory with the following;
nmap <leader>c :sp C:\Progra~2\vim\vimfiles\doc\commands.txt<cr>
nmap <leader>co :call BackupCommands()<cr>
function! BackupCommands()
exec "silent! !copy C:\\Progra~2\\Vim\\vimfiles\\doc\\commands.txt
C:\\Progra~2\\vimutils\\vimtips\\commands_back.txt"
exec "helptags C:\\Progra~2\\Vim\\vimfiles\\doc\\"
endfunction
I'd prefer to copy from the archive to the doc directory rather than the other way round. Any suggestions.
Straight from Vim's help files (:h write-local-help):
The first line is actually the only one for which the format matters. It will
be extracted from the help file to be put in the "LOCAL ADDITIONS:" section of
help.txt |local-additions|. The first "*" must be in the first column of the
first line. After adding your help file do ":help" and check that the entries
line up nicely.
Short: You're missing *sfsearch.txt* as first characters in your file!
Vim wont add to |local-additions|, therefore wont be searched, assuming your tags file was generated correctly. You can verify that by opening the tags file in the /doc directory and finding your tags there manually. There should be a tags file in each correctly helptagged /doc directory (:helptags <doc-dir>).
IMO, fear of "nearly deleting" a file is not a proper reason for editing in another location and copying back and forth. In fact, you've now introduced another risk of accidentally losing file contents via a wrong copy command.
Instead, use proper version control (Git, Mercurial, etc.), or, if that's too heavyweight, you can try my writebackup plugin, a pure Vimscript implementation. With the companion writebackupToAdjacentDir plugin, you can even backup to other directories.
That said, tag jumping should work even with your copy regime, provided that you run :helptags $VIM\vimfiles\doc after copying your help file to that exact location.

What is the easiest way to rename the file you're currently editing in Vim?

What would be the most practical way to rename the file you're currently editing in Vim without messing up your current splits configuration?
Generally, one would need to ... save the file under a different name, delete the original one, and re-open the new one without making a mess of the current layout.
Anyone have any idea how to do that in one command (function) or less?
:saveas newname will save the buffer with the new name, make that name the current buffer, and set the alternate buffer to the old file.
:call delete(expand('#')) will then delete the file associated with the alternate buffer.
You can easily turn that into a command with something like
:command! -bang -complete=file -nargs=+ Rename saveas<bang> <args> | call delete(expand('#'))`
The user manual provides a thorough description of how to create user commands. Here's an explanation of the elements I'm using above.
-bang allows the command to called as either Rename or Rename! and <bang> in the constructed command is replaced by either an empty string or !, depending on how it is called. This is used to support the same functionality in the :saveas command.
-complete=file will let you tab-complete the path that will be used for the new file, similar to :e and :saveas do.
-nargs=+ specifies that :Rename requires at least one argument (the filename), but can take more. <args> is replaced with whatever arguments are given to :Rename. This allows you to specify the extra arguments that :saveas accepts, so you could do something like :Rename ++enc=latin1 newfile to rename the file to newfile and change the encoding to latin1.
Tim Pope has a plugin that has a function :Rename that does this: vim-eunuch.
You can also do the following sequence of steps:
:saveas newfile
:bw <buffer_for_the_old_file>
:!rm old_file
of course this is not as nice as renaming the file in the shell.
Call up the explorer with :Explorer or just :E, select your file, and then press r to rename.
Use :Move provided by eunuch.
eunuch also provides other useful file operations, like :Remove, sudoedit.

How to implement own tag jump in VIM with CTRL-]?

If :h is used in VIM, it will automaticall follow |links| via CTRL+], opening new help topics and maintaining tag jumps list (CTRL+T will go back in jumps history). How to implement such behavior in my own file format? For example, i want CTRL+] on text inside {} to open a file named something.txt and CTRL+T to go back. How to implement this?
It's all done with tags. Essentially the vim files are simple text files, but they're supported by a file in the same directory named 'tags'. All this file contains is entries that look like:
'bg' options.txt /*'bg'*
'bh' options.txt /*'bh'*
'bin' options.txt /*'bin'*
'binary' options.txt /*'binary'*
'biosk' options.txt /*'biosk'*
'bioskey' options.txt /*'bioskey'*
Each line is a tag entry, split over three fields: the tag identifier, the file the tag lives in, and the ex command to find that tag: any ex command works; as can be seen in the example above though, the vim help files just use the search command: '/'.
You can either write a tags file manually, or use a program such as Exuberent ctags to create the file automatically. The tags file is generally read from the same directory the file you're editing lives in, but you can change this in Vim by adjusting the value of the 'tags' option.
More details in vim if you type ":help tags"

Resources