Is there any way to make VIM fold one line more? - vim

I am using an adaptation of the VIM folding settings published here and here. Now, notice the program below:
When folded on my VIM, it produces the following result:
I don't really like that look, I'd prefer the following:
Which I got by rewriting the code:
But leaving the code like that is horrible. Is it possible to update the VimScript so I get the folding I want, without having to leave the JavaScript code like that?
Here is my exact setting:
setlocal foldmethod=expr
setlocal foldexpr=GetPotionFold(v:lnum)
setlocal foldminlines=0
function! s:NextNonBlankLine(lnum)
let numlines = line('$')
let current = a:lnum + 1
while current <= numlines
if getline(current) =~? '\v\S'
return current
endif
let current += 1
endwhile
return -2
endfunction
function! s:IndentLevel(lnum)
return indent(a:lnum) / &shiftwidth
endfunction
function! GetPotionFold(lnum)
if getline(a:lnum) =~? '\v^\s*$'
return '-1'
endif
let this_indent = <SID>IndentLevel(a:lnum)
let next_indent = <SID>IndentLevel(<SID>NextNonBlankLine(a:lnum))
if next_indent == this_indent
return this_indent
elseif next_indent < this_indent
return this_indent
elseif next_indent > this_indent
return '>' . next_indent
endif
endfunction
function! NeatFoldText()
let line = getline(v:foldstart)
let lines_count = v:foldend - v:foldstart + 1
let lines_count_text = '| ' . printf("%10s", lines_count . ' lines') . ' |'
let foldchar = ' '
let foldtextstart = strpart(line, 0, (winwidth(0)*2)/3)
let foldtextend = lines_count_text . repeat(foldchar, 6)
let foldtextlength = strlen(substitute(foldtextstart . foldtextend, '.', 'x', 'g')) + &foldcolumn
return foldtextstart . repeat(foldchar, winwidth(0)-foldtextlength) . foldtextend
endfunction
set foldtext=NeatFoldText()
hi Folded ctermbg=255 ctermfg=21
hi FoldColumn ctermbg=white ctermfg=darkred
And here is the sample code:
function foo(x){
var y = x*x;
var z = y+y;
return z;
};
function bar(x){
var y = x*x;
var z = y+y;
return z;
};
function foobar(x){
var y = x*x;
var z = y+y;
return z;
};
function barfoo(x){
var y = x*x;
var z = y+y;
return z;
};

set foldmethod=marker
set foldmarker={,}
Should give you what you want.

You are using a fold expression that is (as far as I can see from a glance) designed for indent folding (used for HAML, Python, Haskell and other indent-syntax languages).
For C, you should just be using :set foldmethod=syntax.

Related

How to color specific Vim tabs [duplicate]

If I'm opening .js, .html, .rb and other filetype, is it possible to change tab color each filetype?
Tab means vim's tab not like space.
Use the format %#String# will color with the string hightlight :
- set tabline=%#String#\ toto
A script to put in your vimrc:
function! TabTest()
let res = ''
for i in range(tabpagenr('$'))
let i += 1
" Get open buffer
let i_window = tabpagewinnr(i)
let l_buffer = tabpagebuflist(i)
let i_buffer = l_buffer[i_window - 1]
" Get type
let s_type = getbufvar(i_buffer, '&filetype')
" Set color according to filetype
let s_color = ''
if i == tabpagenr()
let res .= '%#TabLine#'
elseif 'javascript' == s_type
let res .= '%#String#'
elseif 'html' == s_type
let res .= '%#Comment#'
else
let res .= '%#Normal#'
endif
" set the tab page number (for mouse clicks)
let res .= '%' . (i + 1) . 'T'
" Set label text
let s_buffer = bufname(i_buffer)
try
let s_file = split(s_buffer, '/')[-1]
catch
let s_file = '[No Name]'
endtry
let res .= ' ' . s_file
endfor
return res
endfunction
set tabline=%!TabTest()
As you are asking for an color hightlight according to the filetype, you must get the filetype of a buffer:
- let s_type = getbufvar(i_buffer, '&filetype')
For this you must get the buffer number of the activer buffer in the tab:
- let i_window = tabpagewinnr(i)
- let l_buffer = tabpagebuflist(i)
- let i_buffer = l_buffer[i_window - 1]
Then you must wisely distinguish accroding to the filetype with a if. So you definitely want to hide all this in a function:
set tabline=%!TabTest()
More :
h tabline
h statusline
You will have to write your own :help 'tabline' (see also :help 'statusline') for that… and all its supporting code.
Having different colors is the easy part:
:set tabline=%#Error#\ foo.js\ %*%#DiffAdd#\ bar.rb\ %*%#Search#\ baz.scss\ %*
It's the code that will determine the correct tabline value on various events that won't be trivial at all.

vim - folding with more than one marker

I have a debug file which looks like this:
==>func1:
.....
..
==>func2:
......
...
<==func2
..
<==func1
==>func3:
......
...
<==func3
Basically, I would like to be able to fold each one of the functions to eventually see something like this:
+-- x lines: ==> func1:
+-- x lines: ==> func3:
but still be able to expand func1 and see func2 folded:
==>func1:
.....
..
+-- x lines: ==> func2:
..
<==func1
is there any way to do so? thanks.
The unmatched markers need extra handle, here's an expr solution( see :h fold-expr):
setlocal foldmethod=expr
setlocal foldexpr=GetFoldlevel(v:lnum)
function GetFoldlevel(lnum)
let line = getline(a:lnum)
let ret = '='
if line[0:2] == '==>'
let name = matchstr(line, '^==>\zs\w*')
let has_match = HasMarkerMatch(a:lnum, name)
if has_match
let ret = 'a1'
endif
elseif line[0:2] == '<=='
let ret ='s1'
endif
return ret
endfunction
function HasMarkerMatch(lnum, name)
let endline = line('$')
let current = a:lnum + 1
let has_match = 0
while current <= endline
let line = getline(current)
if line =~ '^<=='.a:name
let has_match = 1
break
endif
let current += 1
endwhile
return has_match
endfunction

VimL print values in a list infinitly

I have a list of symbols, and want to use the Vim8 timers API to loop over the symbols list every 80ms and return that symbol. I worked out something like this:
let s:frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
let s:numTestimonials = len(s:frames)
let s:start = 0
function! PrintValues()
return s:frames[s:start]
let s:start = (s:start) + 1 % s:numTestimonials
endfunction
let timer = timer_start(80, 'PrintValues', {'repeat': -1})
But as soon as it reaches the last symbol in the list, it will throw an error, E684: list index out of range: 10. Any ideas how to accomplish what I want?
You need to have the 1 inside parentheses before the mod
let s:start = (s:start + 1) % s:numTestimonials
1 % s:numTestimonials is always 1 and is evaluated before adding s:start
Some little changes made to your code (Tested on vim 7.4):
let timer = timer_start(500, 'PrintValues', {'repeat': -1})
let s:frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
let s:numTestimonials = len(s:frames)
let s:start = 0
function! PrintValues(timer)
execute "normal! i".s:frames[s:start]
let s:start = (s:start + 1) % s:numTestimonials
endfunction

How detect Vim buffer contains a fold?

looking for an advice how to programatically detect, if current Vim's buffer contains at least one fold defined ? Regardless if a fold is open or closed.
Attempting to call mkview only if there is a fold defined in current buffer:
autocmd BufWrite ?* if fold_defined() | mkview | endif
function fold_defined()
???
endfunction
function! HasFold()
let view = winsaveview()
let fold = 0
for move in ['zj', 'zk']
exe 'keepj norm!' move
if foldlevel('.') > 0
let fold = 1
break
endif
endfor
call winrestview(view)
return fold
endfunction
Based on perreal's advice, I did wrote one of possible solutions to my question:
" Detect presence of fold definition in the current buffer
function FoldDefined()
let result = 0
let save_cursor = getpos('.')
call cursor(1,1)
let scanline = line('.')
let lastline = line('$')
while scanline <= lastline
if foldlevel(scanline) > 0
let result = 1
break
endif
let scanline = scanline + 1
endwhile
call setpos('.', save_cursor)
return result
endfunction
function! FoldDefined()
return len(filter(range(1, line('$')), 'foldlevel(v:val)>1'))>0
endfunction

is there a way on vim to show all column numbers in the current buffer line?

It would be very nice to have an option that would show all the column numbers of the current line or maybe of all the buffer, so I could know where exactly to navigate. Is there such an option or do i have to program it myself (nooo XD)?
:h 'statusline'
It is as easy as defining exactly what you what to see printed. e.g.
" RulerStr() comes from http://www.vanhemert.co.uk/vim/vimacros/ruler2.vim
function! RulerStr()
let columns = &columns
let inc = 0
let str = ""
while (inc < columns)
let inc10 = inc / 10 + 1
let buffer = "."
if (inc10 > 9)
let buffer = ""
endif
let str .= "....+..." . buffer . inc10
let inc += 10
endwhile
let str = strpart(str, 0, columns)
return str
endfunction
let s:saved_stl = {}
function! s:ToggleRuler()
let buf = bufnr('%')
if has_key(s:saved_stl, buf)
let &l:stl = s:saved_stl[buf]
unlet s:saved_stl[buf]
else
let s:saved_stl[buf] = &l:stl
setlocal stl=%{RulerStr()}
endif
endfunction
nnoremap <silent> µ :call <sid>ToggleRuler()<cr>
You can use "set ruler". It will show the line number and column position at the bottom.

Resources