]> git.madduck.net Git - etc/vim.git/blobdiff - .vim/bundle/vim-lsp/autoload/lsp/utils/tree.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Merge commit 'a39f715c13be3352193ffd9c5b7536b8786eff64' as '.vim/bundle/vim-lsp'
[etc/vim.git] / .vim / bundle / vim-lsp / autoload / lsp / utils / tree.vim
diff --git a/.vim/bundle/vim-lsp/autoload/lsp/utils/tree.vim b/.vim/bundle/vim-lsp/autoload/lsp/utils/tree.vim
new file mode 100644 (file)
index 0000000..b7da56d
--- /dev/null
@@ -0,0 +1,295 @@
+" This file is part of an installation of vim-yggdrasil, a vim/neovim tree viewer library.
+" The source code of vim-yggdrasil is available at https://github.com/m-pilia/vim-yggdrasil
+"
+" vim-yggdrasil is free software, distributed under the MIT license.
+" The full license is available at https://github.com/m-pilia/vim-yggdrasil/blob/master/LICENSE
+"
+" Yggdrasil version (git SHA-1): 043d0ab53dcdd0d91b7c7cd205791d64d4ed9624
+"
+" This installation was generated on 2020-03-15T14:47:27-0700 with the following vim command:
+"     :YggdrasilPlant -plugin_dir=./ -namespace=lsp/utils
+
+scriptencoding utf-8
+
+" Callback to retrieve the tree item representation of an object.
+function! s:node_get_tree_item_cb(node, object, status, tree_item) abort
+    if a:status ==? 'success'
+        let l:new_node = s:node_new(a:node.tree, a:object, a:tree_item, a:node)
+        call add(a:node.children, l:new_node)
+        call s:tree_render(l:new_node.tree)
+    endif
+endfunction
+
+" Callback to retrieve the children objects of a node.
+function! s:node_get_children_cb(node, status, childObjectList) abort
+    for l:childObject in a:childObjectList
+        let l:Callback = function('s:node_get_tree_item_cb', [a:node, l:childObject])
+        call a:node.tree.provider.getTreeItem(l:Callback, l:childObject)
+    endfor
+endfunction
+
+" Set the node to be collapsed or expanded.
+"
+" When {collapsed} evaluates to 0 the node is expanded, when it is 1 the node is
+" collapsed, when it is equal to -1 the node is toggled (it is expanded if it
+" was collapsed, and vice versa).
+function! s:node_set_collapsed(collapsed) dict abort
+    let l:self.collapsed = a:collapsed < 0 ? !l:self.collapsed : !!a:collapsed
+endfunction
+
+" Given a funcref {Condition}, return a list of all nodes in the subtree of
+" {node} for which {Condition} evaluates to v:true.
+function! s:search_subtree(node, Condition) abort
+    if a:Condition(a:node)
+        return [a:node]
+    endif
+    if len(a:node.children) < 1
+        return []
+    endif
+    let l:result = []
+    for l:child in a:node.children
+        let l:result = l:result + s:search_subtree(l:child, a:Condition)
+    endfor
+    return l:result
+endfunction
+
+" Execute the action associated to a node
+function! s:node_exec() dict abort
+    if has_key(l:self.tree_item, 'command')
+        call l:self.tree_item.command()
+    endif
+endfunction
+
+" Return the depth level of the node in the tree. The level is defined
+" recursively: the root has depth 0, and each node has depth equal to the depth
+" of its parent increased by 1.
+function! s:node_level() dict abort
+    if l:self.parent == {}
+        return 0
+    endif
+    return 1 + l:self.parent.level()
+endf
+
+" Return the string representation of the node. The {level} argument represents
+" the depth level of the node in the tree and it is passed for convenience, to
+" simplify the implementation and to avoid re-computing the depth.
+function! s:node_render(level) dict abort
+    let l:indent = repeat(' ', 2 * a:level)
+    let l:mark = '• '
+
+    if len(l:self.children) > 0 || l:self.lazy_open != v:false
+        let l:mark = l:self.collapsed ? '▸ ' : '▾ '
+    endif
+
+    let l:label = split(l:self.tree_item.label, "\n")
+    call extend(l:self.tree.index, map(range(len(l:label)), 'l:self'))
+
+    let l:repr = l:indent . l:mark . l:label[0]
+    \          . join(map(l:label[1:], {_, l -> "\n" . l:indent . '  ' . l}))
+
+    let l:lines = [l:repr]
+    if !l:self.collapsed
+        if l:self.lazy_open
+            let l:self.lazy_open = v:false
+            let l:Callback = function('s:node_get_children_cb', [l:self])
+            call l:self.tree.provider.getChildren(l:Callback, l:self.object)
+        endif
+        for l:child in l:self.children
+            call add(l:lines, l:child.render(a:level + 1))
+        endfor
+    endif
+
+    return join(l:lines, "\n")
+endfunction
+
+" Insert a new node in the tree, internally represented by a unique progressive
+" integer identifier {id}. The node represents a certain {object} (children of
+" {parent}) belonging to a given {tree}, having an associated action to be
+" triggered on execution defined by the function object {exec}. If {collapsed}
+" is true the node will be rendered as collapsed in the view. If {lazy_open} is
+" true, the children of the node will be fetched when the node is expanded by
+" the user.
+function! s:node_new(tree, object, tree_item, parent) abort
+    let a:tree.maxid += 1
+    return {
+    \ 'id': a:tree.maxid,
+    \ 'tree': a:tree,
+    \ 'object': a:object,
+    \ 'tree_item': a:tree_item,
+    \ 'parent': a:parent,
+    \ 'collapsed': a:tree_item.collapsibleState ==? 'collapsed',
+    \ 'lazy_open': a:tree_item.collapsibleState !=? 'none',
+    \ 'children': [],
+    \ 'level': function('s:node_level'),
+    \ 'exec': function('s:node_exec'),
+    \ 'set_collapsed': function('s:node_set_collapsed'),
+    \ 'render': function('s:node_render'),
+    \ }
+endfunction
+
+" Callback that sets the root node of a given {tree}, creating a new node
+" with a {tree_item} representation for the given {object}. If {status} is
+" equal to 'success', the root node is set and the tree view is updated
+" accordingly, otherwise nothing happens.
+function! s:tree_set_root_cb(tree, object, status, tree_item) abort
+    if a:status ==? 'success'
+        let a:tree.maxid = -1
+        let a:tree.root = s:node_new(a:tree, a:object, a:tree_item, {})
+        call s:tree_render(a:tree)
+    endif
+endfunction
+
+" Return the node currently under the cursor from the given {tree}.
+function! s:get_node_under_cursor(tree) abort
+    let l:index = min([line('.'), len(a:tree.index) - 1])
+    return a:tree.index[l:index]
+endfunction
+
+" Expand or collapse the node under cursor, and render the tree.
+" Please refer to *s:node_set_collapsed()* for details about the
+" arguments and behaviour.
+function! s:tree_set_collapsed_under_cursor(collapsed) dict abort
+    let l:node = s:get_node_under_cursor(l:self)
+    call l:node.set_collapsed(a:collapsed)
+    call s:tree_render(l:self)
+endfunction
+
+" Run the action associated to the node currently under the cursor.
+function! s:tree_exec_node_under_cursor() dict abort
+    call s:get_node_under_cursor(l:self).exec()
+endfunction
+
+" Render the {tree}. This will replace the content of the buffer with the
+" tree view. Clear the index, setting it to a list containing a guard
+" value for index 0 (line numbers are one-based).
+function! s:tree_render(tree) abort
+    if &filetype !=# 'lsp-tree'
+        return
+    endif
+
+    let l:cursor = getpos('.')
+    let a:tree.index = [-1]
+    let l:text = a:tree.root.render(0)
+
+    setlocal modifiable
+    silent 1,$delete _
+    silent 0put=l:text
+    $d
+    setlocal nomodifiable
+
+    call setpos('.', l:cursor)
+endfunction
+
+" If {status} equals 'success', update all nodes of {tree} representing
+" an {obect} with given {tree_item} representation.
+function! s:node_update(tree, object, status, tree_item) abort
+    if a:status !=? 'success'
+        return
+    endif
+    for l:node in s:search_subtree(a:tree.root, {n -> n.object == a:object})
+        let l:node.tree_item = a:tree_item
+        let l:node.children = []
+        let l:node.lazy_open = a:tree_item.collapsibleState !=? 'none'
+    endfor
+    call s:tree_render(a:tree)
+endfunction
+
+" Update the view if nodes have changed. If called with no arguments,
+" update the whole tree. If called with an {object} as argument, update
+" all the subtrees of nodes corresponding to {object}.
+function! s:tree_update(...) dict abort
+    if a:0 < 1
+        call l:self.provider.getChildren({status, obj ->
+        \   l:self.provider.getTreeItem(function('s:tree_set_root_cb', [l:self, obj[0]]), obj[0])})
+    else
+        call l:self.provider.getTreeItem(function('s:node_update', [l:self, a:1]), a:1)
+    endif
+endfunction
+
+" Destroy the tree view. Wipe out the buffer containing it.
+function! s:tree_wipe() dict abort
+    execute 'bwipeout' . l:self.bufnr
+endfunction
+
+" Apply syntax to an lsp-tree buffer
+function! s:filetype_syntax() abort
+    syntax clear
+    syntax match LspTreeMarkLeaf        "•" contained
+    syntax match LspTreeMarkCollapsed   "▸" contained
+    syntax match LspTreeMarkExpanded    "▾" contained
+    syntax match LspTreeNode            "\v^(\s|[▸▾•])*.*"
+    \      contains=LspTreeMarkLeaf,LspTreeMarkCollapsed,LspTreeMarkExpanded
+
+    highlight def link LspTreeMarkLeaf        Type
+    highlight def link LspTreeMarkExpanded    Type
+    highlight def link LspTreeMarkCollapsed   Macro
+endfunction
+
+" Apply local settings to an lsp-tree buffer
+function! s:filetype_settings() abort
+    setlocal bufhidden=wipe
+    setlocal buftype=nofile
+    setlocal foldcolumn=0
+    setlocal foldmethod=manual
+    setlocal nobuflisted
+    setlocal nofoldenable
+    setlocal nohlsearch
+    setlocal nolist
+    setlocal nomodifiable
+    setlocal nonumber
+    setlocal nospell
+    setlocal noswapfile
+    setlocal nowrap
+
+    nnoremap <silent> <buffer> <Plug>(lsp-tree-toggle-node)
+        \ :call b:lsp_tree.set_collapsed_under_cursor(-1)<cr>
+
+    nnoremap <silent> <buffer> <Plug>(lsp-tree-open-node)
+        \ :call b:lsp_tree.set_collapsed_under_cursor(v:false)<cr>
+
+    nnoremap <silent> <buffer> <Plug>(lsp-tree-close-node)
+        \ :call b:lsp_tree.set_collapsed_under_cursor(v:true)<cr>
+
+    nnoremap <silent> <buffer> <Plug>(lsp-tree-execute-node)
+        \ :call b:lsp_tree.exec_node_under_cursor()<cr>
+
+    nnoremap <silent> <buffer> <Plug>(lsp-tree-wipe-tree)
+        \ :call b:lsp_tree.wipe()<cr>
+
+    if !exists('g:lsp_tree_no_default_maps')
+        nmap <silent> <buffer> o    <Plug>(lsp-tree-toggle-node)
+        nmap <silent> <buffer> <cr> <Plug>(lsp-tree-execute-node)
+        nmap <silent> <buffer> q    <Plug>(lsp-tree-wipe-tree)
+    endif
+endfunction
+
+" Turns the current buffer into an lsp-tree tree view. Tree data is retrieved
+" from the given {provider}, and the state of the tree is stored in a
+" buffer-local variable called b:lsp_tree.
+"
+" The {bufnr} stores the buffer number of the view, {maxid} is the highest
+" known internal identifier of the nodes. The {index} is a list that
+" maps line numbers to nodes.
+function! lsp#utils#tree#new(provider) abort
+    let b:lsp_tree = {
+    \ 'bufnr': bufnr('%'),
+    \ 'maxid': -1,
+    \ 'root': {},
+    \ 'index': [],
+    \ 'provider': a:provider,
+    \ 'set_collapsed_under_cursor': function('s:tree_set_collapsed_under_cursor'),
+    \ 'exec_node_under_cursor': function('s:tree_exec_node_under_cursor'),
+    \ 'update': function('s:tree_update'),
+    \ 'wipe': function('s:tree_wipe'),
+    \ }
+
+    augroup vim_lsp_tree
+        autocmd!
+        autocmd FileType lsp-tree call s:filetype_syntax() | call s:filetype_settings()
+        autocmd BufEnter <buffer> call s:tree_render(b:lsp_tree)
+    augroup END
+
+    setlocal filetype=lsp-tree
+
+    call b:lsp_tree.update()
+endfunction