dotfiles/nvim/autoload/utils.vim
2026-06-02 08:20:14 +02:00

141 lines
4.2 KiB
VimL

" Create command alias safely, see https://stackoverflow.com/q/3878692/6064933
" The following two functions are taken from answer below on SO:
" https://stackoverflow.com/a/10708687/6064933
function! utils#Cabbrev(key, value) abort
execute printf('cabbrev <expr> %s (getcmdtype() == ":" && getcmdpos() <= %d) ? %s : %s',
\ a:key, 1+len(a:key), <SID>Single_quote(a:value), <SID>Single_quote(a:key))
endfunction
function! s:Single_quote(str) abort
return "'" . substitute(copy(a:str), "'", "''", 'g') . "'"
endfunction
" Custom fold expr, adapted from https://vi.stackexchange.com/a/9094/15292
function! utils#VimFolds(lnum) abort
" get content of current line and the line below
let l:cur_line = getline(a:lnum)
let l:next_line = getline(a:lnum+1)
if l:cur_line =~# '^"{'
return '>' . (matchend(l:cur_line, '"{*') - 1)
endif
if l:cur_line ==# '' && (matchend(l:next_line, '"{*') - 1) == 1
return 0
endif
return '='
endfunction
" Custom fold text, adapted from https://vi.stackexchange.com/a/3818/15292
" and https://vi.stackexchange.com/a/6608/15292
function! utils#MyFoldText() abort
let l:line = getline(v:foldstart)
let l:fold_line_num = v:foldend - v:foldstart
let l:fold_text = substitute(l:line, '^"{\+', '', 'g')
let l:fill_char_num = &textwidth - len(l:fold_text) - len(l:fold_line_num) - 10
return printf('+%s%s %s (%s L)', repeat('-', 4), l:fold_text, repeat('-', l:fill_char_num), l:fold_line_num)
endfunction
" Toggle cursor column
function! utils#ToggleCursorCol() abort
if &cursorcolumn
set nocursorcolumn
echo 'cursorcolumn: OFF'
else
set cursorcolumn
echo 'cursorcolumn: ON'
endif
endfunction
function! utils#SwitchLine(src_line_idx, direction) abort
if a:direction ==# 'up'
if a:src_line_idx == 1
return
endif
move-2
elseif a:direction ==# 'down'
if a:src_line_idx == line('$')
return
endif
move+1
endif
endfunction
function! utils#MoveSelection(direction) abort
" only do this if previous mode is visual line mode. Once we press some keys in
" visual line mode, we will leave this mode. So the output of `mode()` will be
" `n` instead of `V`. We can use `visualmode()` instead to check the previous
" mode, see also https://stackoverflow.com/a/61486601/6064933
if visualmode() !=# 'V'
return
endif
let l:start_line = line("'<")
let l:end_line = line("'>")
let l:num_line = l:end_line - l:start_line + 1
if a:direction ==# 'up'
if l:start_line == 1
" we can also directly use `normal gv`, see https://stackoverflow.com/q/9724123/6064933
normal! gv
return
endif
silent execute printf('%s,%smove-2', l:start_line, l:end_line)
normal! gv
elseif a:direction ==# 'down'
if l:end_line == line('$')
normal! gv
return
endif
silent execute printf('%s,%smove+%s', l:start_line, l:end_line, l:num_line)
normal! gv
endif
endfunction
" Output current time or unix timestamp in human-readable format.
function! utils#iso_time(timestamp) abort
" Get current datetime
if !a:timestamp
return strftime('%Y-%m-%d %H:%M:%S%z')
endif
" this timestamp in expressed in milliseconds
if len(a:timestamp) == 13
let l:timestamp = a:timestamp[:-4]
" this timestamp in expressed in microseconds
elseif len(a:timestamp) == 16
let l:timestamp = a:timestamp[:-7]
else
let l:timestamp = a:timestamp
endif
return strftime('%Y-%m-%d %H:%M:%S%z', l:timestamp)
endfunction
" Redirect command output to a register for later processing.
" Ref: https://stackoverflow.com/q/2573021/6064933 and https://unix.stackexchange.com/q/8101/221410 .
function! utils#CaptureCommandOutput(command) abort
let l:tmp = @m
redir @m
silent! execute a:command
redir END
"create a scratch buffer for dumping the text, ref: https://vi.stackexchange.com/a/11311/15292.
tabnew | setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile
let l:lines = split(@m, '\n')
call nvim_buf_set_lines(0, 0, 0, 0, l:lines)
let @m = l:tmp
endfunction
" Edit all files matching the given patterns.
function! utils#MultiEdit(patterns) abort
for p in a:patterns
for f in glob(p, 0, 1)
execute 'edit ' . f
endfor
endfor
endfunction