Skip to content

Latest commit

 

History

History
329 lines (237 loc) · 9.17 KB

misc.rst

File metadata and controls

329 lines (237 loc) · 9.17 KB

autoload/misc.vim

apply_project_locals() -> None

Find and process project-specific configuration files.

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.

param 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 <michaelforney/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.

param 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.

param 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.

param 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

insert_options() -> None

Insert all options in to the current buffer.

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.

param 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

param 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

path_search(path: Optional[str]) -> None

Search for paths without all the escaping required by /.

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.

param 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.

param 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

scissors() -> None

Place perforation-style lines around the given range.

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.

param 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.

param 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.

param option

Option to toggle

param 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 ’s base version.

Many distributions package with cherry picked patches, and sometimes it is nice to know the current base version.

returns

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