nvim/pack/acp/opt/coc.nvim/autoload/coc/string.vim

210 lines
5.7 KiB
VimL

scriptencoding utf-8
function! coc#string#last_character(line) abort
return strcharpart(a:line, strchars(a:line) - 1, 1)
endfunction
" Get utf16 code unit index from col (0 based)
function! coc#string#character_index(line, byteIdx) abort
if a:byteIdx <= 0
return 0
endif
let i = 0
for char in split(strpart(a:line, 0, a:byteIdx), '\zs')
let i += char2nr(char) > 65535 ? 2 : 1
endfor
return i
endfunction
function! coc#string#common_start(text, other) abort
let arr = split(a:text, '\zs')
let other = split(a:other, '\zs')
let total = min([len(arr), len(other)])
if total == 0
return 0
endif
for i in range(0, total - 1)
if arr[i] !=# other[i]
return i
endif
endfor
return total
endfunction
" Convert utf16 character index to byte index
function! coc#string#byte_index(line, character) abort
if a:character <= 0
return 0
endif
" code unit index
let i = 0
let len = 0
for char in split(a:line, '\zs')
let i += char2nr(char) > 65535 ? 2 : 1
let len += strlen(char)
if i >= a:character
break
endif
endfor
return len
endfunction
" Get character count from start col and end col, 1 based
function! coc#string#get_char_count(text, start_col, end_col) abort
return strchars(strpart(a:text, a:start_col - 1, a:end_col - a:start_col))
endfunction
function! coc#string#character_length(text) abort
let i = 0
for char in split(a:text, '\zs')
let i += char2nr(char) > 65535 ? 2 : 1
endfor
return i
endfunction
function! coc#string#reflow(lines, width) abort
let lines = []
let currlen = 0
let parts = []
for line in a:lines
for part in split(line, '\s\+')
let w = strwidth(part)
if currlen + w + 1 >= a:width
if len(parts) > 0
call add(lines, join(parts, ' '))
endif
if w >= a:width
call add(lines, part)
let currlen = 0
let parts = []
else
let currlen = w
let parts = [part]
endif
continue
endif
call add(parts, part)
let currlen = currlen + w + 1
endfor
endfor
if len(parts) > 0
call add(lines, join(parts, ' '))
endif
return empty(lines) ? [''] : lines
endfunction
" Used when 'wrap' and 'linebreak' is enabled
function! coc#string#content_height(lines, width) abort
let len = 0
let pattern = empty(&breakat) ? '.\zs' : '['.substitute(&breakat, '\([\[\]]\)', '\\\1', 'g').']\zs'
for line in a:lines
if strwidth(line) <= a:width
let len += 1
else
let currlen = 0
for part in split(line, pattern)
let wl = strwidth(part)
if currlen == 0 && wl > 0
let len += 1
endif
let delta = currlen + wl - a:width
if delta >= 0
let len = len + (delta > 0)
let currlen = delta == 0 ? 0 : wl
if wl >= a:width
let currlen = wl%a:width
let len += float2nr(ceil(wl/(a:width + 0.0))) - (currlen == 0)
endif
else
let currlen = currlen + wl
endif
endfor
endif
endfor
return len
endfunction
" get change between two lines
function! coc#string#diff(curr, previous, col) abort
let end = strpart(a:curr, a:col - 1)
let start = strpart(a:curr, 0, a:col -1)
let endOffset = 0
let startOffset = 0
let currLen = strchars(a:curr)
let prevLen = strchars(a:previous)
if len(end)
let endLen = strchars(end)
for i in range(min([prevLen, endLen]))
if strcharpart(end, endLen - 1 - i, 1) ==# strcharpart(a:previous, prevLen -1 -i, 1)
let endOffset = endOffset + 1
else
break
endif
endfor
endif
let remain = endOffset == 0 ? a:previous : strcharpart(a:previous, 0, prevLen - endOffset)
if len(remain)
for i in range(min([strchars(remain), strchars(start)]))
if strcharpart(remain, i, 1) ==# strcharpart(start, i ,1)
let startOffset = startOffset + 1
else
break
endif
endfor
endif
return {
\ 'start': startOffset,
\ 'end': prevLen - endOffset,
\ 'text': strcharpart(a:curr, startOffset, currLen - startOffset - endOffset)
\ }
endfunction
function! coc#string#apply(content, diff) abort
let totalLen = strchars(a:content)
let endLen = totalLen - a:diff['end']
return strcharpart(a:content, 0, a:diff['start']).a:diff['text'].strcharpart(a:content, a:diff['end'], endLen)
endfunction
" insert inserted to line at position, use ... when result is too long
" line should only contains character has strwidth equals 1
function! coc#string#compose(line, position, inserted) abort
let width = strwidth(a:line)
let text = a:inserted
let res = a:line
let need_truncate = a:position + strwidth(text) + 1 > width
if need_truncate
let remain = width - a:position - 3
if remain < 2
" use text for full line, use first & end of a:line, ignore position
let res = strcharpart(a:line, 0, 1)
let w = strwidth(res)
for i in range(strchars(text))
let c = strcharpart(text, i, 1)
let a = strwidth(c)
if w + a <= width - 1
let w = w + a
let res = res . c
endif
endfor
let res = res.strcharpart(a:line, w)
else
let res = strcharpart(a:line, 0, a:position)
let w = strwidth(res)
for i in range(strchars(text))
let c = strcharpart(text, i, 1)
let a = strwidth(c)
if w + a <= width - 3
let w = w + a
let res = res . c
endif
endfor
let res = res.'..'
let w = w + 2
let res = res . strcharpart(a:line, w)
endif
else
let first = strcharpart(a:line, 0, a:position)
let res = first . text . strcharpart(a:line, a:position + strwidth(text))
endif
return res
endfunction