The vim statusline wouldn't change mode text - vim

I wrote a simple vim statusline plugin by my self, just add color and mode in the statusline, and after finishing it, it all went well, but now the statusline wouldn't change as I switch mode.
And I put the script file in ~/.vim/plugin/
The vim version is 7.4 Huge
I did this in virtual mathine with a centos7 OS
Here are my code:
hi NormalColor guifg=Black guibg=Green ctermbg=46 ctermfg=0
hi InsertColor guifg=Black guibg=Cyan ctermbg=51 ctermfg=0
hi ReplaceColor guifg=Black guibg=maroon1 ctermbg=165 ctermfg=0
hi VisualColor guifg=Black guibg=Orange ctermbg=202 ctermfg=0
hi DefaultColor guifg=Black guibg=Orange ctermbg=202 ctermfg=0
hi DefaultLineColor guifg=Black guibg=Orange ctermbg=187 ctermfg=0
let s:mode_map = {
\ 'n': ' NORMAL ',
\ 'i': ' INSERT ',
\ 'R': ' REPLACE ',
\ 'v': ' VISUAL ',
\ 'V': ' V-LINE ',
\ "\<C-v>": ' V-BLOCK ',
\ 'c': ' COMMAND ',
\ 's': ' SELECT ',
\ 'S': ' S-LINE ',
\ "\<C-s>": ' S-BLOCK ',
\ 't': ' TERMINAL '
\ }
let s:mode_color = {
\ 'n': '%#NormalColor#',
\ 'i': '%#InsertColor#',
\ 'R': '%#ReplaceColor#',
\ 'v': '%#VisualColor#',
\ 'V': '%#VisualLineColor#',
\ "\<C-v>": '%#VisualBlockColor#',
\ 'c': '%#CommandColor#',
\ 's': '%#SelectColor#',
\ 'S': '%#SelectLineColor#',
\ "\<C-s>": '%#SelectBlockColor#',
\ 't': '%#TerminalColor#'
\ }
let s:line_default_color = '%#DefaultLineColor#'
let s:default_statusline_label = ' %f %M %y%=%3l/%-5L %p%% '
function! SetDefaultStatuslineLabel()
return ' %f %M %y%=%3l/%-5L %p%% '
endfunction
function! GetModeName()
return get(s:mode_map, mode(), '')
endfunction
function! GetModeColor()
return get(s:mode_color, mode(), 'DefaultColor')
endfunction
let s:mode_partition = GetModeColor().GetModeName()
function! ConcatAll()
return s:mode_partition.
\ s:line_default_color.
\ s:default_statusline_label
endfunction
" set statusline=%!ConcatAll()
augroup Statusline
autocmd!
autocmd VimEnter,WinEnter,BufWinEnter * set statusline=%!ConcatAll()
augroup END

You are setting the name of the mode at the time the autocmd gets executed.
If you want to update the mode dynamically with your custom function you need to call them at runtime. To do so wrap the call in %{}, e.g. let s:mode_partition = '%{ GetModeColor().GetModeName() }'

Related

vim sbuffer with fuzzy search

I usually have plenty of files opened in different windows and tabs within vim (or neovim). To jump to the window where the file is open I use :sbuffer. For that, I input the begging of the file name and autocomplete with . I would like to find the name of the file in the way fuzzy search does.
How I see this going, I press , I input a part of the file name, until I see the file found by fuzzy search, then I press . If the file is already opened in a window in any tab, vim moves there rather than opening it in the actual window.
Do you know how to achieve this with any fuzzy search plugin? I'm not worried about the behaviour if the file is not open as usually I take manual care of splits when opening files.
Thanks!
Fzf is probably one of your best options here.
You'll need both fzf.vim and fzf.
Also, there's a readme for fzf vim in fzf main repo (yeah...).
I can't recall where I found this, but here's a config I copied from Fzf manual somewhere:
let g:fzf_command_prefix = 'Fzf'
let g:fzf_buffers_jump = 1 " [Buffers] to existing split
function! s:build_location_list(lines) abort
call setloclist(0, map(copy(a:lines), '{ "filename": v:val }'))
lopen
endfunction
function! s:build_quickfix_list(lines) abort
call setqflist(map(copy(a:lines), '{ "filename": v:val }'))
copen
endfunction
" An action can be a reference to a function that processes selected lines
let g:fzf_action = {
\ 'ctrl-l': function('s:build_quickfix_list'),
\ 'ctrl-r': function('s:build_location_list'),
\ 'ctrl-t': 'tab split',
\ 'ctrl-x': 'split',
\ 'ctrl-v': 'vsplit'}
" \ 'ctrl-o': '<S-tab>',
" \ 'ctrl-i': 'insert_match',
" function! s:insert_match(lines) abort
" <c-r>=echo('a:lines')<cr>
" endfunction
nnoremap <leader>ff :FzfFiles $HOME<cr>
nnoremap <leader><c-f> :FzfFiles .<cr>
nnoremap <leader>F :FzfFiles /<cr>
nnoremap <leader>fb :FzfBuffers<cr>
nnoremap <leader>b :FzfBuffers<cr>
nnoremap <leader>fw :FzfWindows<cr>
nnoremap <leader>ft :FzfTags<cr>
nnoremap <leader>f<c-t> :FzfBTags<cr>
nnoremap <leader>fc :FzfCommit<cr>
nnoremap <leader>f<c-c> :FzfBCommit<cr>
nnoremap <leader>fg :FzfGFiles?<cr>
nnoremap <leader>f<c-g> :FzfGFiles<cr>
nnoremap <leader>fl :FzfLines<cr>
nnoremap <leader>f<c-l> :FzfBLines<cr>
nnoremap <leader>f; :FzfHistory:<cr>
nnoremap <leader>f/ :FzfHistory/<cr>
nnoremap <leader>fh :FzfHistory<cr>
nnoremap <leader>fm :FzfHelptags<cr>
nnoremap <leader>fs <esc>:FzfSnippets<cr>
nnoremap <leader>fr <esc>:Rg<cr>
inoremap <c-x><c-s> <c-o>:FzfSnippets<cr>
" Enable per-command history.
" CTRL-N and CTRL-P will be automatically bound to next-history and
" previous-history instead of down and up. If you don't like the change,
" explicitly bind the keys to down and up in your $FZF_DEFAULT_OPTS.
let g:fzf_history_dir = '~/.local/share/fzf-history'
let g:fzf_tags_command = 'ctags -R'
" Border color
let g:fzf_layout = {'up':'~90%', 'window': { 'width': 0.8, 'height': 0.8,'yoffset':0.5,'xoffset': 0.5, 'highlight': 'Todo', 'border': 'rounded' } }
let $FZF_DEFAULT_OPTS = '--layout=reverse --info=inline --bind "ctrl-o:toggle+up,ctrl-space:toggle-preview"'
let $FZF_DEFAULT_COMMAND="rg --files --hidden --glob '!.git/**'"
"-g '!{node_modules,.git}'
" Customize fzf colors to match your color scheme
let g:fzf_colors =
\ { 'fg': ['fg', 'Normal'],
\ 'bg': ['bg', 'Normal'],
\ 'gutter': ['bg', 'Normal'],
\ 'hl': ['fg', 'Comment'],
\ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
\ 'bg+': ['bg', 'Visual', 'CursorColumn'],
\ 'hl+': ['fg', 'Statement'],
\ 'info': ['fg', 'PreProc'],
\ 'border': ['fg', 'vertsplit'],
\ 'prompt': ['fg', 'Conditional'],
\ 'pointer': ['fg', 'Exception'],
\ 'marker': ['fg', 'Keyword'],
\ 'spinner': ['fg', 'Label'],
\ 'header': ['fg', 'Comment'] }
" \ 'border': ['fg', 'Conditional'],
"Get Files
command! -bang -nargs=? -complete=dir Files
\ call fzf#vim#files(<q-args>, fzf#vim#with_preview({'options': ['--layout=reverse', '--info=inline']}), <bang>0)
" Get text in files with Rg
command! -bang -nargs=* Rg
\ call fzf#vim#grep(
\ "rg --column --line-number --no-heading --color=always --smart-case --glob '!.git/**' ".shellescape(<q-args>), 1,
\ fzf#vim#with_preview(), <bang>0)
" Ripgrep advanced
function! RipgrepFzf(query, fullscreen) abort
let command_fmt = 'rg --column --line-number --no-heading --color=always --smart-case %s || true'
let initial_command = printf(command_fmt, shellescape(a:query))
let reload_command = printf(command_fmt, '{q}')
let spec = {'options': ['--phony', '--query', a:query, '--bind', 'change:reload:'.reload_command]}
call fzf#vim#grep(initial_command, 1, fzf#vim#with_preview(spec), a:fullscreen)
endfunction
command! -nargs=* -bang RG call RipgrepFzf(<q-args>, <bang>0)
" Git grep
command! -bang -nargs=* GGrep
\ call fzf#vim#grep(
\ 'git grep --line-number '.shellescape(<q-args>), 0,
\ fzf#vim#with_preview({'dir': systemlist('git rev-parse --show-toplevel')[0]}), <bang>0)
I tweaked it only a tad, but with something you'll probably enjoy because it's fzf paradigm to set switchbuf=usetab (or useopen). It lets Vim use a window where the buffer is already opened rather than the current.
let g:fzf_buffers_jump = 1 " [Buffers] to existing split
I hope it helps!
I'm personnally using the FZF plugin for all my fuzzy searches.
Here's a piece of code archieving what you ask:
set switchbuf=useopen,usetab
function! HandleFZFSink(filename)
echo a:filename
try
exe "sbuffer " . a:filename
catch
exe "edit " . a:filename
endtry
endfunction
function! FZFTmp()
let cmd = 'ls --color=never 2> /dev/null'
silent! exe fzf#run({'source': cmd, 'sink': function('HandleFZFSink'), 'down':'40%'})
endfunction
nnoremap <silent> , :<C-u>call FZFTmp()<CR>

vim - What's the best way to set statusline color to change, based on mode

I've tried to improve my vim experience trying to have the vim statusline color to change everytime the mode changes.
I've triend this: (found here)
"Automatically change the statusline color depending on mode
function! ChangeStatuslineColor()
if (mode() =~# '\v(n|no)')
exe 'hi! StatusLine ctermfg=008'
elseif (mode() =~# '\v(v|V)' || g:currentmode[mode()] ==# 'V·Block' || get(g:currentmode, mode(), '') ==# 't')
exe 'hi! StatusLine ctermfg=005'
elseif (mode() ==# 'i')
exe 'hi! StatusLine ctermfg=004'
else
exe 'hi! StatusLine ctermfg=006'
endif
return ''
endfunction
...and include:
set statusline+=%{ChangeStatuslineColor()}
But there's an issue, if you switch to insert mode and then press Esc to come back to normal mode, it doesn't change back the color. It'll change back the color only when you manually enter a different mode.
Sorry for necroposting, but I think I found a way better solution for this task.
Set up desired colors like this
hi NormalColor guifg=Black guibg=Green ctermbg=46 ctermfg=0
hi InsertColor guifg=Black guibg=Cyan ctermbg=51 ctermfg=0
hi ReplaceColor guifg=Black guibg=maroon1 ctermbg=165 ctermfg=0
hi VisualColor guifg=Black guibg=Orange ctermbg=202 ctermfg=0
Now add to statusline
set statusline+=%#NormalColor#%{(mode()=='n')?'\ \ NORMAL\ ':''}
set statusline+=%#InsertColor#%{(mode()=='i')?'\ \ INSERT\ ':''}
set statusline+=%#ReplaceColor#%{(mode()=='R')?'\ \ REPLACE\ ':''}
set statusline+=%#VisualColor#%{(mode()=='v')?'\ \ VISUAL\ ':''}
It works perfect, doesn't need any workarounds for visual mode and doesn't require additional cursor movements to trigger color change.
I found that the below approach was the best for me. It gives me colors for all different modes, not just insert, replace, visual and normal.
function! GitBranch()
return system("git rev-parse --abbrev-ref HEAD 2>/dev/null | tr -d '\n'")
endfunction
function! StatuslineGit()
let l:branchname = GitBranch()
return strlen(l:branchname) > 0?' '.l:branchname.' ':''
endfunction
let g:currentmode={
\ 'n' : 'n',
\ 'v' : 'v',
\ 'V' : 'vl',
\ '' : 'vb',
\ 'i' : 'i',
\ 'R' : 'r',
\ 'Rv' : 'rv',
\ 'c' : 'c',
\ 't' : 'f',
\}
hi NormalColor ctermbg=black ctermfg=white
hi InsertColor ctermbg=darkgreen ctermfg=black
hi ReplaceColor ctermbg=darkred ctermfg=black
hi VisualColor ctermbg=darkblue ctermfg=black
set laststatus=2
set statusline=
set statusline+=%#NormalColor#%{(g:currentmode[mode()]=='n')?'\ \ normal\ ':''}
set statusline+=%#InsertColor#%{(g:currentmode[mode()]=='i')?'\ \ insert\ ':''}
set statusline+=%#ReplaceColor#%{(g:currentmode[mode()]=='r')?'\ \ replace\ ':''}
set statusline+=%#ReplaceColor#%{(g:currentmode[mode()]=='rv')?'\ \ v-replace\ ':''}
set statusline+=%#VisualColor#%{(g:currentmode[mode()]=='v')?'\ \ visual\ ':''}
set statusline+=%#VisualColor#%{(g:currentmode[mode()]=='vl')?'\ \ v-line\ ':''}
set statusline+=%#VisualColor#%{(g:currentmode[mode()]=='vb')?'\ \ v-block\ ':''}
set statusline+=%#NormalColor#%{(g:currentmode[mode()]=='c')?'\ \ command\ ':''}
set statusline+=%#NormalColor#%{(g:currentmode[mode()]=='f')?'\ \ finder\ ':''}
set statusline+=%#PmenuSel#
set statusline+=%{StatuslineGit()}
set statusline+=%#Statusline#
set statusline+=\ %f
set statusline+=%m
set statusline+=%=
set statusline+=%#StatusLineNc#
set statusline+=\ %y
set statusline+=\ %{&fileencoding?&fileencoding:&encoding}
set statusline+=\ %p%%
set statusline+=\ %l:%c
May be you should try this vim plugin vim-airline. It can automatically change statusline color as mode changing based on which colortheme you set.
I like to have two vim configs, one which uses plugins and another which only has a vimrc. To do this without plugin like airline i normally use this snippet from: http://vim.wikia.com/wiki/Change_statusline_color_to_show_insert_or_normal_mode
function! InsertStatuslineColor(mode)
if a:mode == 'i'
hi statusline guibg=magenta
elseif a:mode == 'r'
hi statusline guibg=blue
else
hi statusline guibg=red
endif
endfunction
au InsertEnter * call InsertStatuslineColor(v:insertmode)
au InsertChange * call InsertStatuslineColor(v:insertmode)
au InsertLeave * hi statusline guibg=green
" default the statusline to
green when entering Vim
hi statusline guibg=green
As stated on the wiki:
The following small piece changes the color of the statusline when you
enter insert mode, and when you leave insert mode. There are no
mapping keys or new commands to remember, it works totally
automatically.
Of course if you don't like the colors chosen you can just alter these bits:
guibg=magenta
I know that this question was asked long time ago and you probably got what you'd want but anyway I will post my solution which in my opinion is good enough to share it here.
hi StatusLine ctermfg=253 ctermbg=233 cterm=bold
hi StatusLineNormal ctermfg=251 ctermbg=26 cterm=bold
hi StatusLineInsert ctermfg=251 ctermbg=22 cterm=bold
hi StatusLineReplace ctermfg=251 ctermbg=88 cterm=bold
hi StatusLineVisual ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineVisualL ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineVisualB ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineCommand ctermfg=251 ctermbg=26 cterm=bold
hi StatusLineSelect ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineSelectL ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineSelectB ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineTerminal ctermfg=251 ctermbg=22 cterm=bold
let s:statusline_modes_dict = {
\ 'n' : {
\ 'text' : 'NORMAL',
\ 'color_group' : 'StatusLineNormal'
\ },
\ 'i' : {
\ 'text' : 'INSERT',
\ 'color_group' : 'StatusLineInsert'
\ },
\ 'R' : {
\ 'text' : 'REPLACE',
\ 'color_group' : 'StatusLineReplace'
\ },
\ 'v' : {
\ 'text' : 'VISUAL',
\ 'color_group' : 'StatusLineVisual'
\ },
\ 'V' : {
\ 'text' : 'V-LINE',
\ 'color_group' : 'StatusLineVisualL'
\ },
\ "\<C-v>" : {
\ 'text' : 'V-BLOCK',
\ 'color_group' : 'StatusLineVisualB'
\ },
\ 'c' : {
\ 'text' : 'COMMAND',
\ 'color_group' : 'StatusLineCommand'
\ },
\ 's' : {
\ 'text' : 'SELECT',
\ 'color_group' : 'StatusLineSelect'
\ },
\ 'S' : {
\ 'text' : 'S-LINE',
\ 'color_group' : 'StatusLineSelectL'
\ },
\ "\<C-s>" : {
\ 'text' : 'S-BLOCK',
\ 'color_group' : 'StatusLineSelectB'
\ },
\ 't' : {
\ 'text' : 'TERMINAL',
\ 'color_group' : 'StatusLineTerminal'
\ },
\ }
function Get_current_mode_text ()
let md = mode()
if (has_key (s:statusline_modes_dict, md))
return s:statusline_modes_dict[md]['text']
endif
return md
endfunction
function Get_current_mode_color_group ()
let md = mode()
if (has_key (s:statusline_modes_dict, md))
return "%#" . s:statusline_modes_dict[md]['color_group'] . "#"
endif
return "%#StatusLine#"
endfunction
" left
set statusline=
set statusline+=%{%Get_current_mode_color_group()%}\
set statusline+=%{Get_current_mode_text()}\
set statusline+=%#Statusline#\
Here statusline_modes_dict stores keys that are exactly what mode() returns and it has text to be shown in the status line and highlight group (color_group) that of course has to be added to colorscheme, or somewhere else.
Maybe there is possibility to merge Get_current_mode_text() and Get_current_mode_color_group() into a single function to reduce operations but I have failed to make it work in a statusline.

Is there a way to redirect the output of ":ilist pattern" to a Vim quickfix window?

I use quickfix windows all the time to traverse cscope results all the time.
So I was wondering if there something similar for "Include file searches" (:help ilist)
From /r/vim:
function! WordOccurance()
redir => output
silent! exec join(['ilist', expand('<cword>')], ' ')
redir END
let lines = split(output, '\n')
if lines[0] =~ '^Error detected'
echomsg "Could not find the word in file"
return
endif
let [filename, line_info] = [lines[0], lines[1:-1]]
let qf_entries = map(line_info, "{
\ 'filename': filename,
\ 'lnum': split(v:val)[1],
\ 'text': getline(split(v:val)[1])
\ }"
\ )
call setqflist(qf_entries)
cwindow
endfunction
noremap <silent> ]I :call WordOccurance()<CR>
First off all, :ilist searches the current buffer, not "include file searches".
My GrepHere plugin provides a :GrepHere command that works like :ilist, but puts the matches into the quickfix window.

E421: Getting color name not recognized in perfectly valid statement

I want to change the colors of my parentheses colorized with Better Rainbow Parentheses.
The colors are specified like this:
let g:rbpt_colorpairs = [
\ ['brown', 'RoyalBlue3'],
\ ['Darkblue', 'SeaGreen3'],
\ ['darkgray', 'DarkOrchid3'],
\ ['darkgreen', 'firebrick3'],
\ ['darkcyan', 'RoyalBlue3'],
\ ['darkred', 'SeaGreen3'],
\ ['darkmagenta', 'DarkOrchid3'],
…
\ ]
The function changing the colors in the plugin is this:
func! rainbow_parentheses#toggle()
if !exists('s:active')
cal rainbow_parentheses#load(0)
endif
let afunc = exists('s:active') && s:active ? 'clear' : 'activate'
cal call('rainbow_parentheses#'.afunc, [])
endfunc
Since I’m using Solarized I want specific hex colors, so I got this:
let g:rbpt_colorpairs = [
\ ['yellow', '#b58900'],
\ ['orange', '#cb4b16'],
\ ['red', '#dc322f'],
\ ['magenta', '#d33682'],
\ ['violet', '#6c71c4'],
\ ['blue', '#268bd2'],
\ ['cyan', '#2aa198'],
…
\ ]
Yet, on restart and turning the plugin on, I get this error multiple times:
E421: Color name or number not recognized: cterm=orange guifg=#cb4b16
Even better, doing the :exe done in the function manually works like a charm, like:
:exe 'hi default level4c ctermfg=orange guifg=#cb4b16'
Even with concatenation it works:
:let foo = '#cb4b16
:exe 'hi default level4c ctermfg=orange guifg='.foo
What could be wrong?!
The problem is not in the GUI RGB color, it's in the cterm=orange definition.
See :help cterm-colors for recognized values; orange is not one of them.
function! Gfagivesorange()
colors morning
hi Spellbad term=standout cterm=bold ctermfg=Red ctermbg=White
hi Spellbad term=standout cterm=NONE ctermfg=Orange ctermbg=White
call Myhi()
endfunc
This function will give you Orange (red which is not Bold). It is a NCURSES thing, but people aren't mastering or knowing NCURSES (not many of informaticians).

How can I fold GNU C style functions in Vim correctly?

When writing C code, I use a mixture of GNU and K&R style. This means that the return value, each parameter and the opening body curly brace of a function is on its own line. I would also like to use Vim's folding feature but with foldmethod=syntax, the folding looks like this:
Is it possible to see the function name in the fold summary without any special fold markers or foldexprs?
Something which might be a good compromise - if you use the indent fold - is to set the foldminlines parameter to a higher number.
:set foldmethod=indent
:set foldminlines=5
If most of your functions are long, it will affect only your list of parameters. The downside obviously is, that it will automatically unfold also small functions which are smaller then 5 lines long.
Try this as a starting point (I have it in my vimrc but I found it online):
" Folding {
function! CssFoldText()
let line = getline(v:foldstart)
let nnum = nextnonblank(v:foldstart + 1)
while nnum < v:foldend+1
let line = line . " " . substitute(getline(nnum), "^ *", "", "g")
let nnum = nnum + 1
endwhile
return line
endfunction
setlocal foldtext=CssFoldText()
setlocal foldmethod=marker
setlocal foldmarker={,}
setlocal fillchars=fold:/
setlocal foldlevel=-1
" highlight Folded term=underline cterm=bold gui=bold guifg=Blue guibg=Black
" highlight FoldColumn term=underline cterm=bold gui=bold guifg=Blue guibg=Black
"}
It's possible to do it also with syntax folding. You need to add the following to ~/.vim/after/syntax/c.vim:
let s:contains = ''
if exists("c_curly_error")
let s:contains = ' contains=ALLBUT,cBadBlock,cCurlyError,#cParenGroup,cErrInParen,cErrInBracket,#cStringGroup,#Spell'
endif
let s:pattern = '%('
if &ft ==# "cpp"
" struct/class inheriting
let s:pattern .= ''
\ . '%(<struct|<class)#<='
\ . '\s\ze\s*\S+[^:]:[^:]\s*\S+.*'
let s:pattern .= '|'
" Constructors
let s:pattern .= ''
\ . '%('
\ . '%([^,:]|\n|^|<%(public|private|protected)>\s*:)'
\ . '\n\s*'
\ . ')#<='
\ . '%(<%(while|for|if|switch|catch)>)#!'
\ . '\S\ze\S*%(::\S+)*\s*\(.*\)\s*%(:.*)?'
let s:pattern .= '|'
endif
let s:pattern .= '%(<%(while|for|if|switch|catch)\(.*)#<=\)\ze\s*' . '|'
let s:pattern .= ''
\ . '%('
\ . '^\s*%(//.*|.*\*/|\{|<%(public|private|protected)>\s*:|.*\>)?'
\ . '\s*\n\s*\S+'
\ . ')#<='
\ . '\s\ze\s*\S+\s*'
\ . '%(.*[^:]:[^:].*)#!'
\ . '%(\s+\S+)*'
let s:pattern .= ')%(;\s*)#<!%(//.*|/\*.*\*/)?\n\s*'
syn clear cBlock
exec 'syn region cBlock_ end="}" fold' . s:contains
\ . ' start = "\%#=1\C\v' . s:pattern . '\{"'
\ . ' start = "\%#=1\C\v%(' . s:pattern . ')#<!\{"'
unlet s:contains s:pattern
But beware, if file is big, recalculating folds may be quite heavy.

Resources