Skip indentation of first line after JUnit #Test annotation - vim

In general I prefer to have annotation tags for methods, including #Test ones, on the line before the method declaration like this
#Test
public void testMyMethod() {
// Code
}
rather than
#Test public void testMyMethod() {
// Code
}
I have java specific settings in ~/.vim/ftplugins/java.vim. What can I add to java.vim such that indentation is skipped at the first line after the #Test tag? At the moment vim will, as it is supposed to according to java.vim, indent 4 characters giving
#Test
____* <-- cursor placed here
while I would prefer
#Test
* <-- Cursor placed here

I do something similar in C++, where my company's coding style doesn't want indents in namespace blocks. There's an answer for that at this post, adapting it to your question would just swap the '^\s*namespace.*' bit to your desired pattern. If it's for all annotations, perhaps simply...
function! IndentAnnotation()
let l:cline_num = line('.')
let l:pline_num = prevnonblank(l:cline_num - 1)
let l:pline = getline(l:pline_num)
let l:retv = cindent('.')
while l:pline =~# '\(^\s*{\s*\|^\s*//\|^\s*/\*\|\*/\s*$\)'
let l:pline_num = prevnonblank(l:pline_num - 1)
let l:pline = getline(l:pline_num)
endwhile
if l:pline =~# '^\s*#.*'
let l:retv = 0
endif
return l:retv
endfunction
setlocal indentexpr=IndentAnnotation()
Save this in your vimfiles (inside ~/vimfiles or on windows in your homedir or inside ProgramFiles\vim\vimfiles) as indent/java.vim. You may be able to simplify by removing the while/endwhile hunt for a non-blank line if you require an annotation to occur on a line exactly above the line you're indenting (with no intervening blank lines).

Related

Does Intellij Ideavim plugin support complex function definition?

Does it support following code?
More precisely, does it support defining function? invoking function system? and so on.
Following code is used to auto close my Chinese input method when quit from insert normal.
let g:input_toggle = 1
function! Fcitx2en()
let s:input_status = system("fcitx-remote")
if s:input_status == 2
let g:input_toggle = 1
let l:a = system("fcitx-remote -c")
endif
endfunction
function! Fcitx2zh()
let s:input_status = system("fcitx-remote")
if s:input_status != 2 && g:input_toggle == 1
let l:a = system("fcitx-remote -o")
let g:input_toggle = 0
endif
endfunction
set timeoutlen=150
autocmd InsertLeave * call Fcitx2en()
"autocmd InsertEnter * call Fcitx2zh()
No, IdeaVim understands only several configuration options in ~/.ideavimrc, the rest is ignored. See this feature request for details.

Indent statement after case only without braces in vim cindent

My cinoptions is the folowing :
:set cinoptions={1s,t0,f0s,g0,i0,(0,=0
it works well with brace contained case statement, but not unbraced one :
switch(foo)
{
case(0):
{
...
break;
}
case(1):
... <-- should be indented
break;
}
i need the {1s for all my code need to be formated like that, if i drop the =0 i get this.
switch(foo)
{
case(0):
{
... <-- should not be idented so much
break;
}
case(1):
...
break;
}
Is there any way to specify vim not to indent case in any special way ?
Finaly done it myself, using a in house indent method :
function Indent(line)
" Store current pos
let l:indent = cindent(a:line)
let l:lineprec = a:line - 1
let l:linefirst = split(getline(a:line), " ")[0]
if l:linefirst ==# "{"
let l:case = split(getline(l:lineprec), " ")[0]
if l:case ==# "case"
let l:indent = indent(l:lineprec) + &shiftwidth
endif
endif
return l:indent
endfunction
add in .vimrc :
:set indentexpr=Indent(line(\".\"))
it's kinda specific to my coding style ( case must be followed by a space )

how can I tabularize paragraphs with space as the only separator

I have following nagios config snippet. I could not come up with tabularize command to tabularize parameter values which are only separated by tabs/spaces.
define service{
use local-service,srv-pnp
name http
service_description http
check_command check_http!-w 5 -c 10 -H www.kpoint.com -u /
register 0
}
EDIT:
The expected output is
define service{
use local-service,srv-pnp
name http
service_description http
check_command check_http!-w 5 -c 10 -H www.kpoint.com -u /
register 0
}
Is there any alternative to tabularize?
Following command does the trick.
:Tabularize /^\s*\w*
The link, though does not answer the exact question, has the answer.
Very dirty and quickly way to do it:
function! GetOffsetSpacesAndReplace()
let [line1,col1] = getpos("'<")[1:2]
let [line2,col2] = getpos("'>")[1:2]
let max_len = 0
for i in range(line1, line2)
let my_line = getline(i)
let matching_str = matchstr(my_line, '^\s*\w*\s*')
if len(matching_str) > max_len
let max_len = len(matching_str)
endif
endfor
for i in range(line1, line2)
let my_line = getline(i)
let matching_str = matchstr(my_line, '^\s*\w*\s*')
let col_pos = len(matching_str)
call setpos('.', [0, i, col_pos, 0])
let #s=' '
if max_len - col_pos > 0
execute 'normal! "s'.(max_len - col_pos).'p'
endif
endfor
return 1
endfunction
vmap <silent> <buffer> <F3> :call GetOffsetSpacesAndReplace()<CR>
This function allow you to select visually the inner block and then run the function to indent as you wished.
This is dirty mostly because it answer only your requirements.
In order to use a more flexible tool to do indentation, you should probably check the excellent plugin vim-easy-align.
I'm using it every day without any problems.

VIM: how to show folder name in tab, but only if two files have the same name

I would like to have the following feature in VIM (GVIM in particular). I think Sublime Text has something like that:
In the "normal" case the tab name should be just the file's name, but...
If there are two files opened with the same name but in different directories, I would like to see a tab name parent folder name + file name.
Example:
When there are tabs for the following files:
c:\my\dir\with\files\justAfile.txt
c:\my\dir\with\files\myfile.txt
c:\my\dir\with\backup\myfile.txt
Tab names would be then:
justAfile.txt | files\myfile.txt | backup\myfile.txt
Is this doable with some clever configuration?
In GVIM, you can customize the tab labels with the 'guitablabel' option.
In terminal Vim; there's no 'guitablabel' equivalent; one has to render the entire 'tabline'. Fortunately, the Vim help has an example which delegates the label rendering to a separate function, so re-using your custom function is pretty easy.
The help pages for the mentioned options link to examples; you probably have to use fnamemodify() to canonicalize all buffers' paths to full absolute paths, find the common base directory, and then strip that off the paths.
On the other hand, if it's okay for you to :cd to the base directory, you'll get that kind of tab label pretty much out-of-the-box.
Assuming the following files:
z.txt
a/b/c/d.txt
a/b/f/d.txt
My current setup will make the tabline look like so (I reversed-engineered the behavior from Sublime Text 2):
z.txt | d.txt - c | d.txt - f
My code has a lot of extras like treating Nerdtree/FZF tabs specially, and naming tabs according to the left-most buffer when there are splits. You can remove these extras yourself if you don't want them, or change anything you don't like. I also assumed Unix only, and terminal VIM only (GVIM would need minor tweaking I guess).
I am providing the code below without guarantee, as a starting point for you to customize according to your needs.
set tabline=%!GetTabLine()
function! GetTabLine()
let tabs = BuildTabs()
let line = ''
for i in range(len(tabs))
let line .= (i+1 == tabpagenr()) ? '%#TabLineSel#' : '%#TabLine#'
let line .= '%' . (i + 1) . 'T'
let line .= ' ' . tabs[i].uniq_name . ' '
endfor
let line .= '%#TabLineFill#%T'
return line
endfunction
function! BuildTabs()
let tabs = []
for i in range(tabpagenr('$'))
let tabnum = i + 1
let buflist = tabpagebuflist(tabnum)
let file_path = ''
let tab_name = bufname(buflist[0])
if tab_name =~ 'NERD_tree' && len(buflist) > 1
let tab_name = bufname(buflist[1])
end
let is_custom_name = 0
if tab_name == ''
let tab_name = '[No Name]'
let is_custom_name = 1
elseif tab_name =~ 'fzf'
let tab_name = 'FZF'
let is_custom_name = 1
else
let file_path = fnamemodify(tab_name, ':p')
let tab_name = fnamemodify(tab_name, ':p:t')
end
let tab = {
\ 'name': tab_name,
\ 'uniq_name': tab_name,
\ 'file_path': file_path,
\ 'is_custom_name': is_custom_name
\ }
call add(tabs, tab)
endfor
call CalculateTabUniqueNames(tabs)
return tabs
endfunction
function! CalculateTabUniqueNames(tabs)
for tab in a:tabs
if tab.is_custom_name | continue | endif
let tab_common_path = ''
for other_tab in a:tabs
if tab.name != other_tab.name || tab.file_path == other_tab.file_path
\ || other_tab.is_custom_name
continue
endif
let common_path = GetCommonPath(tab.file_path, other_tab.file_path)
if tab_common_path == '' || len(common_path) < len(tab_common_path)
let tab_common_path = common_path
endif
endfor
if tab_common_path == '' | continue | endif
let common_path_has_immediate_child = 0
for other_tab in a:tabs
if tab.name == other_tab.name && !other_tab.is_custom_name
\ && tab_common_path == fnamemodify(other_tab.file_path, ':h')
let common_path_has_immediate_child = 1
break
endif
endfor
if common_path_has_immediate_child
let tab_common_path = fnamemodify(common_path, ':h')
endif
let path = tab.file_path[len(tab_common_path)+1:-1]
let path = fnamemodify(path, ':~:.:h')
let dirs = split(path, '/', 1)
if len(dirs) >= 5
let path = dirs[0] . '/.../' . dirs[-1]
endif
let tab.uniq_name = tab.name . ' - ' . path
endfor
endfunction
function! GetCommonPath(path1, path2)
let dirs1 = split(a:path1, '/', 1)
let dirs2 = split(a:path2, '/', 1)
let i_different = 0
for i in range(len(dirs1))
if get(dirs1, i) != get(dirs2, i)
let i_different = i
break
endif
endfor
return join(dirs1[0:i_different-1], '/')
endfunction
As Ingo suggests you can use guitablabel. On my installation its only configured to show the file name (:echo &guitablabel reports %M%t). To set this to show the relative path do :set guitablabel=%M%f. Like Ingo says, use :cd DIRECTORY to set the home directory, and :pwd to see where its currently set.
See :help statusline for (many) more formatting options.
Here's my solution that makes the tabname the directory---which is usually a good proxy for the project that tab is meant to represent. This solution can be modified to show the filename if there is only one buffer (modification shown below).
This solution draws a tiny bit from Jerome's. I'm not doing anything as complex as they are, so mine is 5x shorter.
Also, this solution places the tab number alongside the name, making it easy to bounce around, meaning the tabs will look like this: 1:log 2:doc 3:vimfiles and 2gt will move to the second tab.
set tabline=%!TabLine()
function! TabLine()
let line = ''
for i in range(tabpagenr('$'))
let line .= (i+1 == tabpagenr()) ? '%#TabLineSel#' : '%#TabLine#'
let line .= '%' . (i + 1) . 'T'
let line .= TabLabel(i + 1) . ' '
endfor
let line .= '%#TabLineFill#%T'
return line
endfunction
function! TabLabel(n)
" Return list of buffer numbers for each window pane open in tab.
let panelist = tabpagebuflist(a:n)
" See :help setting-tabline then search MyTabLabel if you want to
" use use the active window. I use the topmost pane, which let's
" me rename the tab just by putting a window from a different
" directory in the first position.
let filepath = bufname(panelist[0])
let dirname = fnamemodify(filepath, ':p:h:t')
return a:n . ':' . dirname
endfunction
The modification to show the filename if only one buffer is visible:
function! TabLabel(n)
" Return list of buffer numbers for each window pane open in tab.
let panelist = tabpagebuflist(a:n)
" See :help setting-tabline then search MyTabLabel if you want to
" use use the active window. I use the topmost pane, which let's
" me rename the tab just by putting a window from a different
" directory in the first position.
let filepath = bufname(panelist[0])
let dirname = fnamemodify(filepath, ':p:h:t')
let filename = fnamemodify(filepath, ':t')
let tabname = len(panelist) > 1 ? dirname : filename
return a:n . ':' . tabname
endfunction

How to use a program to do omni-completion for VIM

I'm looking to create a custom omni completion for VIM, and I want to do the actual work of finding possible matches to be done in another program. What would be the best way to go about this?
My idea so far would be to create a vimscript that sends the entire buffer and the location of the cursor to an external script. However I haven't been able to find a more efficient way of getting the buffer than by using join(getline(0, line('$')), '\n'), which is very slow on large files. If you are interested, what I have so far:
AutoComplete vimscript:
fun! MyComplete(findstart, base)
let line = getline('.')
let start = col('.') - 1
while start > 0 && line[start - 1] =~ '\a'
let start -= 1
endwhile
if a:findstart
return start
else
let result = system('java AutoComplete '.shellescape(expand('%')).' '.line('.').' '.start, 'File sourcecode here')
let res = []
for m in split(result)
if m =~ '^' . a:base
call add(res, m)
endif
endfor
return res
endif
endfun
set completefunc=MyComplete
AutoComplete.java:
class AutoComplete {
public static void main(String[] argv) {
// To be expanded into an amazing program...
System.out.print("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec");
}
}
It's better to create a temporary file and pass its name to an external command. For example, this is from clang_complete plugin:
let l:buf = getline(1, '$')
let l:tempfile = expand('%:p:h') . '/' . localtime() . expand('%:t')
try
call writefile(l:buf, l:tempfile)
catch /^Vim\%((\a\+)\)\=:E482/
" TODO: handle exception
endtry
" TODO: call external program here
call delete(l:tempfile)
See also the QueryCommandComplete plugin, which can be useful for you.

Resources