Skip to content

Instantly share code, notes, and snippets.

@kamichidu
Last active August 29, 2015 14:06
Show Gist options
  • Save kamichidu/2025d57b72db02ed52a8 to your computer and use it in GitHub Desktop.
Save kamichidu/2025d57b72db02ed52a8 to your computer and use it in GitHub Desktop.
let s:V= vital#of('vital')
let s:S= s:V.import('Data.String')
let s:L= s:V.import('Data.List')
unlet s:V
"
" Public API
" ---
"
let s:style= {}
function! s:style.head_joint(context, parent, node)
if !empty(a:parent)
return '|'
else
return ''
endif
endfunction
function! s:style.edge(context, parent, node)
return '|'
endfunction
function! s:style.indicator(context, parent, node)
if a:node.is_leaf()
return ' '
endif
if a:node.state() == 'open'
return '-'
elseif a:node.state() == 'close'
return '+'
else
return ' '
endif
endfunction
function! s:style.tail_joint(context, parent, node)
return "\n"
if empty(a:node.children())
return "\n"
else
return ''
endif
endfunction
"
" Public API
" ---
" new()
" tree.root() : A node object
" tree.root({node})
" tree.stringify() : List of string
"
let s:tree= {
\ '__root': {},
\ '__shiftwidth': shiftwidth(),
\ '__style': deepcopy(s:style),
\}
function! s:tree.root(...)
if a:0 == 0
return deepcopy(self.__root)
else
let self.__root= deepcopy(a:1)
endif
endfunction
function! s:tree.shiftwidth(...)
if a:0 == 0
return self.__shiftwidth
else
let self.__shiftwidth= a:1
endif
endfunction
function! s:tree.style(...)
if a:0 == 0
return deepcopy(self.__style)
else
let self.__style= deepcopy(a:1)
endif
endfunction
function! s:tree.stringify()
let context= {}
let context.edge_stack= []
let context.style= self.__style
let context.shiftwidth= self.__shiftwidth
let context.level= 0
return split(join(s:_stringify(context, {}, self.__root), ''), "\n")
endfunction
function! s:_stringify(context, parent, node)
let style= (!empty(a:node.style())) ? a:node.style() : a:context.style
let buffer= []
"
" {edge}* {head joint} {indicator} {node text} {tail joint}
"
let buffer= []
for edge in a:context.edge_stack
let buffer+= [s:_pad_right(edge, a:context.shiftwidth)]
endfor
let head_joint= style.head_joint(a:context, a:parent, a:node)
let indicator= style.indicator(a:context, a:parent, a:node)
let node_text= a:node.text()
let tail_joint= style.tail_joint(a:context, a:parent, a:node)
let buffer+= [head_joint, indicator, node_text, tail_joint]
if a:node.state() == 'open'
call s:L.push(a:context.edge_stack, style.edge(a:context, a:parent, a:node))
let a:context.level+= 1
for child in a:node.children()
let buffer+= s:_stringify(a:context, a:node, child)
endfor
let a:context.level-= 1
endif
return buffer
endfunction
function! s:_pad_right(str, width)
let str= a:str
while strdisplaywidth(str) < a:width
let str.= ' '
endwhile
return str
endfunction
"
" Public API
" ---
" new()
" node.text() : String
" node.text({text})
" node.state() : String
" node.state({state})
" node.open()
" node.close()
" node.indicator() : String
" node.children() : List of node objects
"
let s:node= {
\ 'data': {},
\ '__children': [],
\ '__text': '',
\ '__state': 'close',
\ '__style': {},
\}
function! s:node.text(...)
if a:0 == 0
return self.__text
else
let self.__text= a:1
endif
endfunction
function! s:node.state(...)
if a:0 == 0
return self.__state
else
let self.__state= a:1
endif
endfunction
function! s:node.open(...)
call self.state('open')
let recursive= get(a:000, 0, 0)
if recursive
for child in self.children()
call child.open(recursive)
endfor
endif
endfunction
function! s:node.close(...)
call self.state('close')
let recursive= get(a:000, 0, 0)
if recursive
for child in self.children()
call child.close(recursive)
endfor
endif
endfunction
function! s:node.is_leaf()
return empty(self.children())
endfunction
function! s:node.children(...)
if a:0 == 0
return deepcopy(self.__children)
else
let self.__children= deepcopy(a:1)
endif
endfunction
function! s:node.style(...)
if a:0 == 0
return deepcopy(self.__style)
else
let self.__style= a:1
endif
endfunction
"
" test
"
function! s:_children() dict
if has_key(self.data, 'children')
return self.data.children
endif
let children= []
for dir in self.data.directories
let child= deepcopy(s:node)
call child.text(fnamemodify(dir, ':s|/$||:t:s|$|/|'))
let child.data= {
\ 'files': filter(split(globpath(dir, '*'), "\n"), '!isdirectory(v:val)'),
\ 'directories': filter(split(globpath(dir, '*'), "\n"), 'isdirectory(v:val)'),
\}
let child.children= function('s:_children')
let children+= [child]
endfor
for file in self.data.files
let child= deepcopy(s:node)
call child.text(fnamemodify(file, ':t'))
let child.data= {
\ 'files': [],
\ 'directories': [],
\}
let child.children= function('s:_children')
let children+= [child]
endfor
let self.data.children= children
return children
endfunction
function! s:_()
let tree= deepcopy(s:tree)
let root= deepcopy(s:node)
call root.text('')
let root.data= {'files': [], 'directories': [expand('~/sources/vim-plugin/vim-benchmark/')]}
let root.children= function('s:_children')
call root.open()
call root.children()[0].open()
call root.children()[0].children()[1].open()
call tree.root(root)
call tree.shiftwidth(4)
call tree.style(deepcopy(s:style))
for line in tree.stringify()
echo line
endfor
endfunction
call s:_()
@trusktr
Copy link

trusktr commented Nov 18, 2014

Hi! Does this draw text trees? Can you provide an example? :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment