Development/Vim
TDF LibreOffice Document Liberation Project Community Blogs Weblate Nextcloud Redmine Ask LibreOffice Donate
Recommended Vim plug-ins
Use Pathogen or Vundle to install any of these mentioned plug-ins.
localvimrc
The localvimrc plug-in allows you to have a .lvimrc file to overwrite/extended your main ~/.vimrc file without cluttering it.
" Works best with vimrc entries:
" let g:localvimrc_sandbox = 0
" let g:localvimrc_whitelist = "/path/to/postgres/tree/.*"
"
if g:localvimrc_sourced_once_for_file
finish
endif
" Place here the specific setting for your LibreOffice environment.
You should add an entry .lvimrc to your global .gitignore file to avoid listing the file when using git.
Fugitive interface with Git
A great plugin to use Git from within Vim is fugitive. It offers diff, blame, jumping around in the commit tree and more all on a few key strokes. Its self-description (A Git wrapper so awesome, it should be illegal) is a little bit exaggerated, but just a little ;-)
OmniCppComplete
If you install the Vim OmniCppComplete plugin you also get auto completion of function names and class members when using ctags as the tags file is built with the necessary OmniCpp options. The vim path variable is evaluated if OmniCpp_NamespaceSearch is set to 2 to determine in which files to look for namespaces, it may help to not have /usr/include in there.. See also above for the vim path variable setting.
ctags
ctags is the other local indexer tool supported by the build system. To use it in vim:
- always run 'make tags' after a toplevel build completed
- add this to your ~/.vimrc:
" Tags files are searched first relative to the current file, then relative to
" the current working directory, and last in the $HOME directory.
set tags=./tags,./../tags,./../../tags,./../../../tags,./../../../../tags,./../../../../../tags,tags,../tags,.
- then you can use
:ts ClassName
or:ts ClassName::FunctionName
in vim to jump to the definition or declaration of a classname, Ctrl + T jumps back - you can also use Ctrl + ] to search for the class or function or variable name at the cursor position and jump to the first hit.
See the vim help :help tags
for more details.
In case you notice problems ctags parsing C++11 code, give Universal Ctags a try.
YouCompleteMe
YouCompleteMe uses clangd to generate useful autocomplete information.
You can generate a clang compilation database file that can be used by YCM through make vim-ide-integration. For more details see [1]
Vimagit
Emacs has magit, Vim has vimagit, basically a frontend to the git add --interactive or git add --patch (respectively git commit --interactive or git commit --patch) commands. Great stuff to create a commit of only portions of your edits from within your favorite editor. Available as vimagit from the vim online script repository, install as a pathogen.vim bundle. See the feature set on the vimagit GitHub page.
The vim path variable
Setting of the vim path variable influences quite some things, like where vim looks for files when hitting gf for GotoFile under cursor, or the OmniCppComplete plugin (see below) looks for namespaces. A possible set in your ~/.vimrc would be
" Where to look for files in gf and ^Wf and similar commands,
" and for include files for i_^X^I and i_^X^D commands.
" The path starts with two commas ,, for searches in the current directory,
" this enables editing lists of files with relative paths without having to
" copy the list to the current directory first.
set path=,,.,./inc,./../inc,./../../inc,./../../../inc,./../../../../inc,$VIM_INC
where the shell environment variable VIM_INC before the first invocation of vim can be set to for example
export VIM_INC="$(pwd)/include,$(pwd)/workdir/UnoApiHeadersTarget/udkapi/normal,$(pwd)/workdir/UnoApiHeadersTarget/offapi/normal,$(pwd)/workdir/CustomTarget/officecfg/registry"
where $(pwd) prints the current working tree directory.
Indentation of keywords and blocks
To properly align a break keyword with the corresponding case keyword, not indent public: and private: within a class declaration and not indent inside a namespace block (if you know what hitting [[ or ]] does then you know why ;-) use these C-indent settings in your .vimrc or .lvimrc:
set cinoptions=b1,g0,N-s " C-indent: break aligned with case, public:/private: 0 indented, no indent in namespace
set cinkeys+=0=break " entering break outdents
Useful macros to place in vimrc (or lvimrc)
Build the current module using Ctrl+K
To build the current file's module when hitting Ctrl + K place this snippet in your ~/.vimrc
" Call appropriate makeprg with Ctrl+K
map <C-K> :call Make()<CR>
if $SRC_ROOT == ""
" Normal makeprg, not in LibreOffice environment
function Make()
make
endfun
else
" XXX NOTE: if BUILDDIR differs from SRC_ROOT (i.e. you build in
" another directory than the source tree) this can not be used!
" In your shell environment set SRC_ROOT to the LibreOffice source
" tree directory, e.g. export SRC_ROOT=/build/libo/core
" The SRC_ROOT variable can be grep'ed from config_host.mk
let s:make_jobs = 6 " define how many jobs you want with make
" The root of the directory where we stop going further up, excluding.
" For example, if /libo/core is the tree's root, the root of that is /libo
let s:dir_root = fnamemodify( $SRC_ROOT, ":h" )
function GetMakeDirLimit( dir )
return a:dir == s:dir_root
endfunction
function GetMakeModuleRoot()
let l:mods = ":p:h"
let l:dir = expand( "%" . l:mods )
while !GetMakeDirLimit( l:dir ) && !filereadable( l:dir . "/Makefile" )
let l:mods .= ":h"
let l:dir = expand( "%" . l:mods )
endwhile
if GetMakeDirLimit( l:dir )
let l:dir = expand( "%:p:h" )
endif
return l:dir
endfunction
function Make()
let l:mymake = ""
if has("gui_running")
" Source some environment for detached gvim if needed.
" It's up to you if and what you put in there or how you name
" the file or where it is located.
if filereadable( $SRC_ROOT . "/Env.Host.sh" )
let l:mymake .= "source $SRC_ROOT/Env.Host.sh && "
endif
endif
" cd into current file's directory before obtaining module's root
let l:my_local_path = expand("%:h")
if (l:my_local_path == "")
let l:my_local_path = "."
endif
exec 'lcd ' . l:my_local_path
let l:module = GetMakeModuleRoot()
"let l:debugt = ""
let l:debugt = " debug=true"
if filereadable( l:module . "/Makefile" )
" Build the entire module.
exec 'lcd ' . l:module
let l:mymake .= "make -rs -j" . s:make_jobs . " wall=true" . l:debugt
else
" Fallback to default, which likely bails out with unknown
" target in the current file's directory.
let l:mymake .= "make"
endif
let &makeprg = l:mymake
make
endfunction
endif
Show the issue in a browser
Of course this function would need to be hacked if firefox isn't the browser to be used, and new prefixes can be added. To use this function, simply place the cursor on a bug reference in the code like i#12345 and hit Ctrl + i.
" Get the issue number under the cursor. An issue number is containing
" digits, lating letters and #. The # characters are removed from the result.
"
" Code heavily inspired from the words_tools.vim of Luc Hermitte
" http://hermitte.free.fr/vim/ressources/dollar_VIM/plugin/words_tools_vim.html
function! GetCurrentIssueText()
let c = col ('.')-1
let l = line('.')
let ll = getline(l)
let ll1 = strpart(ll,0,c)
let ll1 = matchstr(ll1,'[0-9#a-zA-Z]*$')
if strlen(ll1) == 0
return ll1
else
let ll2 = strpart(ll,c,strlen(ll)-c+1)
let ll2 = strpart(ll2,0,match(ll2,'$\|[^0-9#a-zA-Z]'))
let text = ll1.ll2
let text = substitute( text, "#", "", "g" )
return text
endif
endfunction
" Open IssueZilla / Bugzilla for the selected issue
function! OpenIssue( )
let s:browser = "firefox"
let s:issueText = GetCurrentIssueText( )
let s:urlTemplate = ""
let s:pattern = "\\(\\a\\+\\)\\(\\d\\+\\)"
let s:prefix = substitute( s:issueText, s:pattern, "\\1", "" )
let s:id = substitute( s:issueText, s:pattern, "\\2", "" )
if s:prefix == "i"
let s:urlTemplate = "https://issues.apache.org/ooo/show_bug.cgi?id=%"
elseif s:prefix == "n"
let s:urlTemplate = "https://bugzilla.novell.com/show_bug.cgi?id=%"
elseif s:prefix == "fdo"
let s:urlTemplate = "https://bugs.documentfoundation.org/show_bug.cgi?id=%"
endif
if s:urlTemplate != ""
let s:url = substitute( s:urlTemplate, "%", s:id, "g" )
let s:cmd = "silent !" . s:browser . " " . s:url . "&"
execute s:cmd
endif
endfunction
map <silent> <C-i> :call OpenIssue()<CR><C-l>
Show the current function name
To use this function, simply hit f: the line containing the function name will be displayed.
function! ShowFuncName()
let lnum = line(".")
let col = col(".")
echohl ModeMsg
echo getline(search("^[^ \t#/]\\{2}.*[^:]\s*$", 'bW'))
echohl None
call search("\\%" . lnum . "l" . "\\%" . col . "c")
endfunction
map f :call ShowFuncName() <CR>
Remove trailing whitespace when saving
Put this into your .vimrc
to remove all trailing whitespace when saving.
" Remove all trailing whitespace when saving
" See http://vim.wikia.com/wiki/Remove_unwanted_spaces
autocmd BufWritePre * :%s/\s\+$//e
Editing zipped XML files
If you debug some import problem in a zipped XML format, put this to your .vimrc
:
au BufReadCmd *.odt,*.ott,*.ods,*.ots,*.odp,*.otp,*.odg,*.otg,*.odb,*.odf,*.odm,*.odc call zip#Browse(expand("<amatch>"))
au BufReadCmd *.sxw,*.stw,*.sxc,*.stc,*.sxi,*.sti,*.sxd,*.std,*.odb,*.sxm,*.sxg,*.sxs call zip#Browse(expand("<amatch>"))
au BufReadCmd *.bau call zip#Browse(expand("<amatch>"))
au BufReadCmd *.oxt call zip#Browse(expand("<amatch>"))
au BufReadCmd *.docx,*.dotx,*.dotm,*.docm,*.xlsx,*.xltx,*.xlsm,*.xsltm,*.pptx,*.potx,*.ppsx,*.pptm,*.ppsm,*.potm call zip#Browse(expand("<amatch>"))
And then you can open the file in vim directly, editing the relevant XML substream in-place.
Pretty-printing
Pretty-printing is really needed for XML files, as LO typically writes no whitespace around XML tags by default, so it's hard to read or write the XML for a human.
The easy way:
map <F11> :% !xmllint --format --recover - 2>/dev/null<CR>
Then hitting F11 will pretty-print the XML. There are two problems with this approach: it doesn't handle non-XML (for example RTF) files, and it also doesn't handle invalid XML.
A more complex solution to add to .vimrc
:
map <F11> :% !prettyprint<CR>
(prettyprint script, XML formatter, RTF formatter)
Jumping to a random line
Jumping to a random line is useful in testsuite files where a framework is local to a file, so adding a new test in a particular file is useful, but always appending new tests at the end would cause too much conflicts.
Vim Tips Wiki covers to to some extent, a Python script is also available. Here is a macro to use the later:
command GotoRandom pyf /path/to/goto-random.py
Then executing
:GotoRandom
will jump to a random line inside the file
Avoiding UUIDs in SmartArt files
nnoremap <silent><leader>ls :% !pptx-kill-uuid.py<cr>
in your vimrc, then put pptx-kill-uuid.py in PATH.
Finally open `ppt/diagrams/data1.xml`in a PPTX file in vim, press `,ls` and it makes all those UUIDs human-readable.
GNU ID-utils
As mentioned in GNU ID-utils, the eid command makes use of some environment variables when invoking the editor:
export VISUAL='vim'
export EIDARG='+/%s/'
export EIDLDEL='\<'
export EIDRDEL='\>'
To be able to invoke the lid utility from within Vim we need a key mapping and function call, you may place this section into your .vimrc file:
" GNU id-utils, taken from :h ident-search
" Generate the ID file in the current directory or in .. or ../.. or ../../..
" To use it, place the cursor on a word, type "_u" and vim will load the file
" that contains the word. Search for the next occurrence of the word in the
" same file with "n". Go to the next file with "_n".
map _u :call ID_search()<Bar>execute "/\\<" . g:word . "\\>"<CR>
map _n :n<Bar>execute "/\\<" . g:word . "\\>"<CR>
function ID_search()
let g:word = expand("<cword>")
let x = system("lid --key=none ". g:word)
let x = substitute(x, "\n", " ", "g")
execute "next " . x
endfun
lid.vim plugin
lid.vim is a plugin to integrate GNU ID-utils with Vim, providing a lid -g output in the quickfix window that can be travelled using the :cnext and :cprev commands respectively their keyboard mappings.