diff options
Diffstat (limited to 'autoload/vital/_crystal/Data/String.vim')
-rw-r--r-- | autoload/vital/_crystal/Data/String.vim | 177 |
1 files changed, 118 insertions, 59 deletions
diff --git a/autoload/vital/_crystal/Data/String.vim b/autoload/vital/_crystal/Data/String.vim index c2e2382c..7d3ef2c3 100644 --- a/autoload/vital/_crystal/Data/String.vim +++ b/autoload/vital/_crystal/Data/String.vim @@ -1,5 +1,14 @@ if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'crystal') == -1 +" ___vital___ +" NOTE: lines between '" ___vital___' is generated by :Vitalize. +" Do not mofidify the code nor insert new lines before '" ___vital___' +function! s:_SID() abort + return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$') +endfunction +execute join(['function! vital#_crystal#Data#String#import() abort', printf("return map({'starts_with': '', 'split3': '', 'replace_first': '', 'chop': '', 'unescape': '', 'split_posix_text': '', 'replace': '', 'scan': '', 'strwidthpart': '', 'common_head': '', 'reverse': '', 'escape_pattern': '', 'trim_end': '', '_vital_depends': '', 'wrap': '', 'join_posix_lines': '', 'contains_multibyte': '', 'truncate_skipping': '', 'split_leftright': '', 'ends_with': '', 'nsplit': '', 'strwidthpart_reverse': '', 'unescape_pattern': '', 'levenshtein_distance': '', 'trim_start': '', 'justify_equal_spacing': '', 'nr2hex': '', 'iconv': '', 'pad_left': '', 'nr2enc_char': '', 'lines': '', 'repair_posix_text': '', 'nr2byte': '', 'trim': '', 'diffidx': '', 'truncate': '', 'split_by_displaywidth': '', '_vital_created': '', 'padding_by_displaywidth': '', 'hash': '', 'chomp': '', 'pad_between_letters': '', 'dstring': '', 'pad_both_sides': '', 'substitute_last': '', 'pad_right': '', 'remove_ansi_sequences': '', '_vital_loaded': ''}, \"vital#_crystal#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n") +delfunction s:_SID +" ___vital___ " Utilities for string. let s:save_cpo = &cpo @@ -7,12 +16,21 @@ set cpo&vim function! s:_vital_loaded(V) abort let s:V = a:V - let s:P = s:V.import('Prelude') let s:L = s:V.import('Data.List') endfunction function! s:_vital_depends() abort - return ['Prelude', 'Data.List'] + return ['Data.List'] +endfunction + +function! s:_vital_created(module) abort + " Expose script-local funcref + if exists('s:strchars') + let a:module.strchars = s:strchars + endif + if exists('s:wcswidth') + let a:module.wcswidth = s:wcswidth + endif endfunction " Substitute a:from => a:to by string. @@ -61,7 +79,7 @@ function! s:common_head(strs) abort endif let strs = len == 2 ? a:strs : sort(copy(a:strs)) let pat = substitute(strs[0], '.', '\="[" . escape(submatch(0), "^\\") . "]"', 'g') - return pat == '' ? '' : matchstr(strs[-1], '\C^\%[' . pat . ']') + return pat ==# '' ? '' : matchstr(strs[-1], '\C^\%[' . pat . ']') endfunction " Split to two elements of List. ([left, right]) @@ -130,9 +148,7 @@ endfunction " even if a:str contains multibyte character(s). " s:strchars(str) {{{ if exists('*strchars') - function! s:strchars(str) abort - return strchars(a:str) - endfunction + let s:strchars = function('strchars') else function! s:strchars(str) abort return strlen(substitute(copy(a:str), '.', 'x', 'g')) @@ -210,7 +226,7 @@ function! s:nr2byte(nr) abort endfunction function! s:nr2enc_char(charcode) abort - if &encoding == 'utf-8' + if &encoding ==# 'utf-8' return nr2char(a:charcode) endif let char = s:nr2byte(a:charcode) @@ -222,7 +238,7 @@ endfunction function! s:nr2hex(nr) abort let n = a:nr - let r = "" + let r = '' while n let r = '0123456789ABCDEF'[n % 16] . r let n = n / 16 @@ -318,7 +334,7 @@ function! s:levenshtein_distance(str1, str2) abort let letters2 = split(a:str2, '\zs') let length1 = len(letters1) let length2 = len(letters2) - let distances = map(range(1, length1 + 1), 'map(range(1, length2 + 1), "0")') + let distances = map(range(1, length1 + 1), 'map(range(1, length2 + 1), ''0'')') for i1 in range(0, length1) let distances[i1][0] = i1 @@ -373,7 +389,7 @@ function! s:split_by_displaywidth(expr, width, float, is_wrap) abort let text = '' while cs_index < len(cs) - if cs[cs_index] is "\n" + if cs[cs_index] is# "\n" let text = s:padding_by_displaywidth(text, a:width, a:float) let lines += [text] let text = '' @@ -394,7 +410,7 @@ function! s:split_by_displaywidth(expr, width, float, is_wrap) abort if a:is_wrap if a:width < w if a:width < strdisplaywidth(cs[cs_index]) - while get(cs, cs_index, "\n") isnot "\n" + while get(cs, cs_index, "\n") isnot# "\n" let cs_index += 1 endwhile continue @@ -403,7 +419,7 @@ function! s:split_by_displaywidth(expr, width, float, is_wrap) abort endif endif else - while get(cs, cs_index, "\n") isnot "\n" + while get(cs, cs_index, "\n") isnot# "\n" let cs_index += 1 endwhile continue @@ -440,8 +456,9 @@ function! s:truncate(str, width) abort " http://github.com/mattn/googlereader-vim/tree/master if a:str =~# '^[\x00-\x7f]*$' - return len(a:str) < a:width ? - \ printf('%-'.a:width.'s', a:str) : strpart(a:str, 0, a:width) + return len(a:str) < a:width + \ ? printf('%-' . a:width . 's', a:str) + \ : strpart(a:str, 0, a:width) endif let ret = a:str @@ -471,57 +488,20 @@ function! s:truncate_skipping(str, max, footer_width, separator) abort endfunction function! s:strwidthpart(str, width) abort - if a:width <= 0 - return '' - endif - let strarr = split(a:str, '\zs') - let width = s:wcswidth(a:str) - let index = len(strarr) - let diff = (index + 1) / 2 - let rightindex = index - 1 - while width > a:width - let index = max([rightindex - diff + 1, 0]) - let partwidth = s:wcswidth(join(strarr[(index):(rightindex)], '')) - if width - partwidth >= a:width || diff <= 1 - let width -= partwidth - let rightindex = index - 1 - endif - if diff > 1 - let diff = diff / 2 - endif - endwhile - return index ? join(strarr[:index - 1], '') : '' + let str = tr(a:str, "\t", ' ') + let vcol = a:width + 2 + return matchstr(str, '.*\%<' . (vcol < 0 ? 0 : vcol) . 'v') endfunction function! s:strwidthpart_reverse(str, width) abort - if a:width <= 0 - return '' - endif - let strarr = split(a:str, '\zs') - let width = s:wcswidth(a:str) - let strlen = len(strarr) - let diff = (strlen + 1) / 2 - let leftindex = 0 - let index = -1 - while width > a:width - let index = min([leftindex + diff, strlen]) - 1 - let partwidth = s:wcswidth(join(strarr[(leftindex):(index)], '')) - if width - partwidth >= a:width || diff <= 1 - let width -= partwidth - let leftindex = index + 1 - endif - if diff > 1 - let diff = diff / 2 - endif - endwhile - return index < strlen ? join(strarr[(index + 1):], '') : '' + let str = tr(a:str, "\t", ' ') + let vcol = s:wcswidth(str) - a:width + return matchstr(str, '\%>' . (vcol < 0 ? 0 : vcol) . 'v.*') endfunction if v:version >= 703 " Use builtin function. - function! s:wcswidth(str) abort - return strwidth(a:str) - endfunction + let s:wcswidth = function('strwidth') else function! s:wcswidth(str) abort if a:str =~# '^[\x00-\x7f]*$' @@ -564,9 +544,88 @@ else endfunction endif +function! s:remove_ansi_sequences(text) abort + return substitute(a:text, '\e\[\%(\%(\d\+;\)*\d\+\)\?[mK]', '', 'g') +endfunction + +function! s:escape_pattern(str) abort + " escape characters for no-magic + return escape(a:str, '^$~.*[]\') +endfunction + +function! s:unescape_pattern(str) abort + " unescape characters for no-magic + return s:unescape(a:str, '^$~.*[]\') +endfunction + +function! s:unescape(str, chars) abort + let chars = map(split(a:chars, '\zs'), 'escape(v:val, ''^$~.*[]\'')') + return substitute(a:str, '\\\(' . join(chars, '\|') . '\)', '\1', 'g') +endfunction + +function! s:iconv(expr, from, to) abort + if a:from ==# '' || a:to ==# '' || a:from ==? a:to + return a:expr + endif + let result = iconv(a:expr, a:from, a:to) + return empty(result) ? a:expr : result +endfunction + +" NOTE: +" A definition of a TEXT file is "A file that contains characters organized +" into one or more lines." +" A definition of a LINE is "A sequence of zero or more non- <newline>s +" plus a terminating <newline>" +" That's why {stdin} always ends with <newline> ideally. However, there are +" some programs which does not follow the POSIX rule and a Vim's way to join +" List into TEXT; join({text}, "\n"); does not add <newline> to the end of +" the last line. +" That's why add a trailing <newline> if it does not exist. +" REF: +" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_392 +" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_205 +" :help split() +" NOTE: +" it does nothing if the text is a correct POSIX text +function! s:repair_posix_text(text, ...) abort + let newline = get(a:000, 0, "\n") + return a:text =~# '\n$' ? a:text : a:text . newline +endfunction + +" NOTE: +" A definition of a TEXT file is "A file that contains characters organized +" into one or more lines." +" A definition of a LINE is "A sequence of zero or more non- <newline>s +" plus a terminating <newline>" +" REF: +" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_392 +" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_205 +function! s:join_posix_lines(lines, ...) abort + let newline = get(a:000, 0, "\n") + return join(a:lines, newline) . newline +endfunction + +" NOTE: +" A definition of a TEXT file is "A file that contains characters organized +" into one or more lines." +" A definition of a LINE is "A sequence of zero or more non- <newline>s +" plus a terminating <newline>" +" TEXT into List; split({text}, '\r\?\n', 1); add an extra empty line at the +" end of List because the end of TEXT ends with <newline> and keepempty=1 is +" specified. (btw. keepempty=0 cannot be used because it will remove +" emptylines in the head and the tail). +" That's why removing a trailing <newline> before proceeding to 'split' is required +" REF: +" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_392 +" http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_205 +function! s:split_posix_text(text, ...) abort + let newline = get(a:000, 0, '\r\?\n') + let text = substitute(a:text, newline . '$', '', '') + return split(text, newline, 1) +endfunction + let &cpo = s:save_cpo unlet s:save_cpo - " vim:set et ts=2 sts=2 sw=2 tw=0: endif |