autoload/misc.vim
¶
Enforce vim script implementation to reduce ambiguities and improve robustness:
scriptversion 4
function! misc#apply_project_locals() abort
let b:meta_dir = misc#meta_detect(expand('<afile>'))
if type(b:meta_dir) != v:t_string
return
endif
if !exists('b:meta_spell')
const l:spf = printf('%s%s.%s.add', b:meta_dir, &spelllang,
\ &encoding)
if filereadable(l:spf)
\ && index(split(&spellfile, ','), l:spf) == -1
execute 'setlocal spellfile+=' .. l:spf
endif
let b:meta_spell = v:true
endif
for l:file in ['abbr.vim', 'project.vim']
let l:var = 'b:meta_' .. fnamemodify(l:file, ':r')
if !exists(l:var)
let l:file_path = b:meta_dir .. '/' .. l:file
if filereadable(l:file_path)
execute 'source ' .. l:file_path
endif
endif
let {l:var} = v:true
endfor
endfunction
- call_build(target: Optional[str]) None ¶
Utility function to run a build.
This supports ninja and make, and prefers ninja when both build files exist.
- Parameters
target – Item to build, or build tool’s default if not given.
function! misc#call_build(...) abort
if filereadable('build.ninja')
let &makeprg = executable('samu') ? 'samu' : 'ninja'
else
set makeprg=make
endif
execute printf('make -C %s %s', getcwd(), get(a:, 1, ''))
endfunction
Note
samurai is a ninja reimplementation that turns up on a few machines I use.
- disable_plugin(plugin: str) None ¶
Mark a function as loaded to prevent loading.
This is purely to remove duplication in setup.
- Parameters
plugin – Name of the plugin to shadow
function! misc#disable_plugin(str) abort
let g:loaded_{a:str} = v:true
endfunction
- edit_project_file(name: str) None ¶
Edit project-specific configuration file.
- Parameters
name – Configuration file to edit
function! misc#edit_project_file(name) abort
let b:meta_dir = misc#meta_detect(expand('<afile>'))
if type(b:meta_dir) != v:t_string
return
endif
if !isdirectory(b:meta_dir)
call mkdir(b:meta_dir, 'p')
endif
execute printf(':edit %s/%s', b:meta_dir, a:name)
endfunction
- get_qf_title(type: str) str ¶
Return title of active quickfix list.
- Parameters
type – Type of quickfix list to operate on
- Returns
Window title
function! misc#get_qf_title(type) abort
const l:type = a:type[0] ==# 'q' ? 'qf' : 'loc'
execute printf('call get%slist(%s#{title: v:true}).title',
\ l:type, (l:type ==# 'loc' ? '0, ' : ''))
endfunction
function! misc#insert_options() abort
python3 << EOF
for k in sorted(vim.options):
vim.current.buffer.append(f'{k}={vim.options[k]!r}')
EOF
endfunction
- meta_detect(file: str) Optional[str] ¶
Find location for project-specific configuration files.
- Parameters
file – Location to search for directory from
- Returns
Directory for project-specific configuration files, if possible
const s:project_env_dir = g:vim_data_dir .. '/project_env/'
function! misc#meta_detect(file) abort
if exists('b:meta_dir')
return b:meta_dir
endif
let l:p = resolve(fnamemodify(a:file, ':p:h'))
const l:cmd = printf('git -C %s rev-parse --show-toplevel',
\ shellescape(l:p))
silent const l:output = systemlist(l:cmd)
if v:shell_error == 0 && len(l:output) == 1
return s:project_env_dir .. l:output[0]
endif
" Lazy method to handle scheme prefixed filenames
let l:break = ''
while l:p !=# l:break
if isdirectory(l:p .. '/.meta')
return printf('%s%s/.meta', s:project_env_dir, l:p)
endif
let l:break = l:p
let l:p = fnamemodify(l:p, ':h')
endwhile
return v:none
endfunction
Note
The reason we’re storing project specific files deep in g:vim_data_dir
instead of under the project itself is so that we need not concern ourselves
with the security implications of remote vimrc
snippets from random
users and projects.
- modeline_stub(verbose: bool = False) None ¶
Insert a modeline on the last line of a buffer
- Parameters
verbose – If truthy, return a verbose modeline
function! misc#modeline_stub(verbose = v:false) abort
let l:x = printf(' vim: ft=%s%s', &filetype, &expandtab ? '' : ' noet')
if a:verbose
let l:x ..= printf(
\ ' ts=%d sw=%d tw=%d fdm=%s%s',
\ &tabstop, &shiftwidth, &textwidth, &foldmethod,
\ (&foldmethod ==# 'marker' ? ' fmr=' .. &foldmarker : '')
\ )
endif
if !empty(&commentstring)
let l:x = printf(&commentstring, l:x)
endif
let l:x ..= ':'
call substitute(l:x, '\ \+', ' ', 'g')->trim()->append('$')
endfunction
function! misc#path_search(...) abort
call inputsave()
let @/ = input('Path? ', get(a:, 1, expand('%:p:h')), 'file')
call inputrestore()
if getreg('/') ==# ''
return
endif
normal! n
endfunction
Note
This feels like exactly the kind of thing :promptfind
would be
useful for in gvim, but it doesn’t support vim’s completion
functionality.
- preserve_layout(command: str) None ¶
Execute command and preserve original layout.
- Parameters
command – Command to execute
function! misc#preserve_layout(command) abort
const l:view = winsaveview()
execute a:command
call winrestview(l:view)
endfunction
- print_option(option: str) None ¶
Pretty print an option’s value.
- Parameters
option – Option to display
function! misc#print_option(value) abort
const l:value = eval(a:value[0] ==# '&' ? a:value : '&' .. a:value)
echo sort(split(l:value, ','))->join("\n")
endfunction
function! misc#scissors() abort range
const l:max_len = getline(a:firstline, a:lastline)->map(
\ {_, s -> strdisplaywidth(s)}
\ )->max()
const l:bound = &textwidth == 0 ? l:max_len : min([l:max_len,
\ &textwidth])
const l:perf = (l:bound / 2) - 1
const l:marker = printf('%s%%s%s', repeat('-', l:perf),
\ repeat('-', l:perf + (l:perf % 2)))
call append(a:firstline - 1, printf(l:marker, '8<'))
call append(a:lastline + 1, printf(l:marker, '>8'))
endfunction
- str2chars(str: str) List[str] ¶
Convert a string to a list of characters.
- Parameters
str – String to convert
- Returns
Individual characters from input
function! misc#str2chars(str) abort
return split(a:str, '\zs')
endfunction
- title_word(word: str) str ¶
Convenience function to apply title case to a word.
- Parameters
word – Text to operate on
- Returns
Title-cased input
function! misc#title_word(word) abort
return toupper(slice(a:word, 0, 1)) .. slice(a:word, 1)
endfunction
- toggle_flag(option: str, flag: str) None ¶
Toggle an option.
- Parameters
option – Option to toggle
flag – Flag to change on given option
function! misc#toggle_flag(option, flag) abort
const l:optstr = eval('&' .. a:option)
if stridx(l:optstr, ',') == -1
" Simple char options like 'fo'
const l:flip = '+-'[l:optstr =~# a:flag]
else
" Comma lists options like 'cot'
const l:flip = '+-'[index(split(l:optstr, ','), a:flag) != -1]
endif
execute printf('set %s%s=%s', a:option, l:flip, a:flag)
endfunction
- version() str ¶
Find vim’s base version.
Many distributions package vim with cherry picked patches, and sometimes it is nice to know the current base version.
- Returns
vim version including the maximum consecutive patch
function! misc#version() abort
let l:n = 1
while has('patch' .. n)
let l:n += 1
endwhile
return printf('%d.%d.%04d', v:version / 100, v:version % 100, n - 1)
endfunction