"=============================================================================
" File : autoload/unite/source/outline/modules/util.vim
" Author : h1mesuke <himesuke@gmail.com>
" Updated : 2012-01-11
" Version : 0.5.1
" License : MIT license {{{
"
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! unite#sources#outline#modules#util#import() abort
return s:Util
endfunction
"-----------------------------------------------------------------------------
function! s:get_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\d\+_')
endfunction
let s:SID = s:get_SID()
delfunction s:get_SID
let s:Util = unite#sources#outline#modules#base#new('Util', s:SID)
"-----------------------------------------------------------------------------
" Heading
function! s:Util_get_indent_level(context, lnum) abort
let line = a:context.lines[a:lnum]
let sw = a:context.buffer.sw
let ts = a:context.buffer.ts
let indent = substitute(matchstr(line, '^\s*'), '\t', repeat(' ', ts), 'g')
return strlen(indent) / sw + 1
endfunction
call s:Util.function('get_indent_level')
function! s:Util_get_comment_heading_level(context, lnum, ...) abort
let line = a:context.lines[a:lnum]
if line =~ '^\s'
let level = (a:0 ? a:1 : s:Util_get_indent_level(a:context, a:lnum) + 3)
else
let level = (strlen(substitute(line, '\s*', '', 'g')) > 40 ? 2 : 3)
let level -= (line =~ '=')
endif
return level
endfunction
call s:Util.function('get_comment_heading_level')
"-----------------------------------------------------------------------------
" Matching
" join_to( {context}, {lnum}, {pattern} [, {limit}])
function! s:Util_join_to(context, lnum, pattern, ...) abort
let lines = a:context.lines
let limit = (a:0 ? a:1 : 3)
if limit < 0
return s:join_to_backward(lines, a:lnum, a:pattern, limit * -1)
endif
let lnum = a:lnum
let limit = min([a:lnum + limit, len(lines) - 1])
while lnum <= limit
let line = lines[lnum]
if line =~# a:pattern
break
endif
let lnum += 1
endwhile
return join(lines[a:lnum : lnum], "\n")
endfunction
call s:Util.function('join_to')
function! s:join_to_backward(context, lnum, pattern, limit) abort
let lines = a:context.lines
let lnum = max([1, a:lnum - a:limit])
while lnum > 0
let line = lines[lnum]
if line =~# a:pattern
break
endif
let lnum -= 1
endwhile
return join(lines[lnum : a:lnum], "\n")
endfunction
function! s:Util_join_to_rparen(context, lnum, ...) abort
let limit = (a:0 ? a:1 : 3)
let line = s:Util_join_to(a:context, a:lnum, ')', limit)
let line = substitute(line, "\\s*\n\\s*", ' ', 'g')
let line = substitute(line, ')\zs.*$', '', '')
return line
endfunction
call s:Util.function('join_to_rparen')
" neighbor_match( {context}, {lnum}, {pattern} [, {range} [, {exclusive}])
function! s:Util_neighbor_match(context, lnum, pattern, ...) abort
let lines = a:context.lines
let range = get(a:000, 0, 1)
let exclusive = !!get(a:000, 1, 0)
if type(range) == type([])
let [prev, next] = range
else
let [prev, next] = [range, range]
endif
let [bwd_range, fwd_range] = s:neighbor_ranges(a:context, a:lnum, prev, next, exclusive)
for lnum in bwd_range
if lines[lnum] =~# a:pattern
return 1
endif
endfor
for lnum in fwd_range
if lines[lnum] =~# a:pattern
return 1
endif
endfor
return 0
endfunction
call s:Util.function('neighbor_match')
function! s:neighbor_ranges(context, lnum, prev, next, exclusive) abort
let max_lnum = len(a:context.lines) - 1
let bwd_range = range(max([1, a:lnum - a:prev]), max([1, a:lnum - a:exclusive]))
let fwd_range = range(min([a:lnum + a:exclusive, max_lnum]), min([a:lnum + a:next, max_lnum]))
return [bwd_range, fwd_range]
endfunction
" neighbor_matchstr( {context}, {lnum}, {pattern} [, {range} [, {exclusive}])
function! s:Util_neighbor_matchstr(context, lnum, pattern, ...) abort
let lines = a:context.lines
let range = get(a:000, 0, 1)
let exclusive = !!get(a:000, 1, 0)
if type(range) == type([])
let [prev, next] = range
else
let [prev, next] = [range, range]
endif
let [bwd_range, fwd_range] = s:neighbor_ranges(a:context, a:lnum, prev, next, exclusive)
for lnum in bwd_range
let matched = matchstr(lines[lnum], a:pattern)
if !empty(matched)
return matched
endif
endfor
for lnum in fwd_range
let matched = matchstr(lines[lnum], a:pattern)
if !empty(matched)
return matched
endif
endfor
return ""
endfunction
call s:Util.function('neighbor_matchstr')
let s:SHARED_PATTERNS = {
\ '*': {
\ 'parameter_list': '\S\s*\zs([^)]*)',
\ 'parameter_list_and_after': '\S\s*\zs([^)]*).*$',
\ 'after_lbrace' : '{.*$',
\ 'after_lbracket': '[.*$',
\ 'after_lparen' : '(.*$',
\ 'after_colon' : ':.*$',
\ },
\ 'c': {
\ 'heading-1': '^\s*\/\*\s*[-=*]\{10,}\s*$',
\ 'header' : ['^/\*', '\*/\s*$'],
\ },
\ 'cpp': {
\ 'heading-1': '^\s*/[/*]\s*[-=/*]\{10,}\s*$',
\ 'header' : {
\ 'leading': '^//',
\ 'block' : ['^/\*', '\*/\s*$'],
\ },
\ },
\ 'sh': {
\ 'heading-1': '^\s*#\s*[-=#]\{10,}\s*$',
\ 'header' : '^#',
\ },
\}
function! s:Util_shared_pattern(filetype, which) abort
return s:SHARED_PATTERNS[a:filetype][a:which]
endfunction
call s:Util.function('shared_pattern')
"-----------------------------------------------------------------------------
" List
let s:List = unite#sources#outline#modules#base#new('List', s:SID)
let s:Util.List = s:List
function! s:List_sort_by_lnum(dicts) abort
return sort(a:dicts, 's:compare_by_lnum')
endfunction
function! s:compare_by_lnum(d1, d2) abort
let n1 = a:d1.lnum
let n2 = a:d2.lnum
return n1 == n2 ? 0 : n1 > n2 ? 1 : -1
endfunction
call s:List.function('sort_by_lnum')
unlet s:List
"-----------------------------------------------------------------------------
" Path
let s:Path = unite#sources#outline#modules#base#new('Path', s:SID)
let s:Util.Path = s:Path
" Path.normalize( {path} [, {mods}])
function! s:Path_normalize(path, ...) abort
let path = a:path
if a:0
let mods = a:0
let path = fnamemodify(path, mods)
endif
let path = substitute(path, '[/\\]', '/', 'g')
return path
endfunction
call s:Path.function('normalize')
unlet s:Path
"-----------------------------------------------------------------------------
" String
let s:String = unite#sources#outline#modules#base#new('String', s:SID)
let s:Util.String = s:String
" String.capitalize( {str} [, {flag}])
function! s:String_capitalize(str, ...) abort
let flag = (a:0 ? a:1 : '')
return substitute(a:str, '\<\(\h\)\(\w\+\)\>', '\u\1\L\2', flag)
endfunction
call s:String.function('capitalize')
" Ported from:
" Sample code from Programing Ruby, page 145
"
function! s:String_nr2roman(nr) abort
if a:nr <= 0 || 4999 < a:nr
return string(a:nr)
endif
let factors = [
\ ["M", 1000], ["CM", 900], ["D", 500], ["CD", 400],
\ ["C", 100], ["XC", 90], ["L", 50], ["XL", 40],
\ ["X", 10], ["IX", 9], ["V", 5], ["IV", 4],
\ ["I", 1],
\]
let nr = a:nr
let roman = ""
for [code, factor] in factors
let cnt = nr / factor
let nr = nr % factor
if cnt > 0
let roman .= repeat(code, cnt)
endif
endfor
return roman
endfunction
call s:String.function('nr2roman')
function! s:String_shellescape(str) abort
if &shell =~? '^\%(cmd\%(\.exe\)\=\|command\.com\)\%(\s\|$\)' || unite#util#is_windows()
return '"' . substitute(a:str, '"', '""', 'g') . '"'
else
return "'" . substitute(a:str, "'", "'\\\\''", 'g') . "'"
endif
endfunction
call s:String.function('shellescape')
unlet s:String
"-----------------------------------------------------------------------------
" Misc
function! s:Util_print_debug(which, msg) abort
if get(g:, 'unite_source_outline_' . a:which . '_debug', 0)
echomsg "unite-outline: " . a:msg
endif
endfunction
call s:Util.function('print_debug')
function! s:Util_print_progress(msg) abort
echon a:msg
redraw
endfunction
call s:Util.function('print_progress')
function! s:Util__cpp_is_in_comment(heading_line, matched_line) abort
return ((a:matched_line =~ '^\s*//' && a:heading_line =~ '^\s*//') ||
\ (a:matched_line =~ '^\s*/\*' && a:matched_line !~ '\*/\s*$'))
endfunction
call s:Util.function('_cpp_is_in_comment')
let &cpo = s:save_cpo
unlet s:save_cpo