summaryrefslogtreecommitdiffstats
path: root/autoload/vital/_crystal/Data/String.vim
diff options
context:
space:
mode:
Diffstat (limited to 'autoload/vital/_crystal/Data/String.vim')
-rw-r--r--autoload/vital/_crystal/Data/String.vim177
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