Skip to content

Show children matched to filter but whose parent not, and respect isExpanded key from sources #143

@kenji0923

Description

@kenji0923

I think it might be helpful to make children item in the tree structure matched after giving a filter string, even though their parent do not match. Especialy for symbols returned by LSP, it might be sometimes useful to keep its tree structure for more information (e.g. in python file with multiple classes, documentSymbol will return multiple init methods, which are almost useless without knowing which class it belongs to). Also, isExpanded key in Item seems not be respected in start(). After a redraw (or refresh?), the top items are automatically expanded, but children of them are not though isExpanded=true (I believe that all items from ddu-source-lsp/lsp_documentSymbol have that key true).

The followings are what I see so far.

nvim :verbose version

NVIM v0.11.5
Build type: RelWithDebInfo
LuaJIT 2.1.1741730670
Compilation: /usr/bin/cc -O2 -g -flto=auto -fno-fat-lto-objects -Wall -Wextra -pedantic -Wno-unused-parameter -Wstri
ct-prototypes -std=gnu99 -Wshadow -Wconversion -Wvla -Wdouble-promotion -Wmissing-noreturn -Wmissing-format-attribut
e -Wmissing-prototypes -fsigned-char -fstack-protector-strong -Wno-conversion -fno-common -Wno-unused-result -Wimpli
cit-fallthrough -fdiagnostics-color=auto  -DUNIT_TESTING -D_GNU_SOURCE -DINCLUDE_GENERATED_DECLARATIONS -DUTF8PROC_S
TATIC -I/home/kshu/.local/neovim/.deps/usr/include/luajit-2.1 -I/home/kshu/.local/neovim/.deps/usr/include -I/home/k
shu/.local/neovim/build/src/nvim/auto -I/home/kshu/.local/neovim/build/include -I/home/kshu/.local/neovim/build/cmak
e.config -I/home/kshu/.local/neovim/src -I/usr/include

   system vimrc file: "$VIM/sysinit.vim"
  fall-back for $VIM: "/usr/local/neovim/share/nvim"

Run :checkhealth for more info

vimrc (Assuming the working directory is ~/work/development/vim/2026-01_ddu_handling_expanded)

set nocompatible

let s:plugin_path = expand('~/work/development/vim/2026-01_ddu_handling_expanded')

execute 'set runtimepath+=' .. s:plugin_path .. '/repos/' .. 'vim-lsp'
execute 'set runtimepath+=' .. s:plugin_path .. '/repos/' .. 'vim-lsp-settings'
execute 'set runtimepath+=' .. s:plugin_path .. '/repos/' .. 'denops.vim'
execute 'set runtimepath+=' .. s:plugin_path .. '/repos/' .. 'ddu.vim'
execute 'set runtimepath+=' .. s:plugin_path .. '/repos/' .. 'ddu-ui-ff'
execute 'set runtimepath+=' .. s:plugin_path .. '/repos/' .. 'ddu-source-lsp'
execute 'set runtimepath+=' .. s:plugin_path .. '/repos/' .. 'ddu-filter-matcher_substring'

function s:ddu_ff_settings() abort
    setlocal cursorline

    call lsp#disable_diagnostics_for_buffer()

    nnoremap <buffer><silent><expr> <CR>
                \ "<Cmd>call ddu#ui#do_action('itemAction')<CR>"
    nnoremap <buffer><silent><expr> <Space>
                \ ddu#ui#get_item()->get('isTree', v:false) ?
                \ "<Cmd>call ddu#ui#do_action('expandItem', { 'mode': 'toggle' })<CR>" :
                \ "<Cmd>call ddu#ui#do_action('itemAction')<CR>"
    nnoremap <buffer><silent> i
                \ <Cmd>call ddu#ui#do_action('openFilterWindow')<CR>
    nnoremap <buffer><silent> q
                \ <Cmd>call ddu#ui#do_action('quit')<CR>
endfunction

function! s:on_lsp_buffer_enabled() abort
    let g:lsp_log_verbose = 1
    let g:lsp_log_file = expand(s:plugin_path .. '/vim-lsp.log')

    let g:ddu_source_lsp_clientName = "vim-lsp"

    function! s:start_ddu_lsp_documentSymbol() abort
        call ddu#start(#{
            \       ui: "ff",
            \       sources: [#{
            \           name: "lsp_documentSymbol"
            \       }],
            \       sourceOptions: #{
            \           _: #{
            \               matchers: ["matcher_substring"],
            \           }
            \       },
            \       uiParams: #{
            \           _: #{
            \               ignoreEmpty: v:false,
            \               displayTree: v:true
            \           }
            \       }
            \ })
    endfunction

    nmap <buffer><expr> gs <SID>start_ddu_lsp_documentSymbol()
endfunction

augroup DduCommands
    autocmd!
    autocmd FileType ddu-ff call s:ddu_ff_settings()
augroup END

augroup lsp_install
    autocmd!
    autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled()
augroup END

clone_plugin.sh for cloning necessary plugins

rm -rf repos
mkdir -p repos

git clone https://github.com/prabirshrestha/vim-lsp repos/vim-lsp
git clone https://github.com/kenji0923/vim-lsp-settings repos/vim-lsp-settings # To set language server capability to return symbols in the tree structure
git clone https://github.com/vim-denops/denops.vim repos/denops.vim
git clone https://github.com/Shougo/ddu.vim repos/ddu.vim
git clone https://github.com/Shougo/ddu-ui-ff repos/ddu-ui-ff
git clone https://github.com/uga-rosa/ddu-source-lsp repos/ddu-source-lsp
git clone https://github.com/Shougo/ddu-filter-matcher_substring repos/ddu-filter-matcher_substring

test_file.py for testing vim-lsp and ddu-source-lsp

class ClassA:

    def func0(self):
        a = 1
        return a

    def func1(self):
        pass

After opening the test python file by nvim, execute :LspInstallServer basedpyright-langserver, and then restart maybe. Type gs to request documentSymbol to the language server.

After the ui drawn, seems good
Image

Then typed filter, which looks fine,
Image

but after clearing the filter input, children items are duplicated.
Image

In order to remove duplicate, it could be a way to let ddu handle addition of children by expandItem of parents. I modified ddu-source-lsp/lsp_documentSymbol source.

diff --git a/denops/@ddu-sources/lsp_documentSymbol.ts b/denops/@ddu-sources/lsp_documentSymbol.ts
index b5b37f4..bfa7a4b 100644
--- a/denops/@ddu-sources/lsp_documentSymbol.ts
+++ b/denops/@ddu-sources/lsp_documentSymbol.ts
@@ -118,9 +118,6 @@ function parseResult(
   ) => {
     for (const symbol of symbols) {
       const item = symbolToItem(symbol, parentPath, context);
-      if (isDucumentSymbol(symbol) && symbol.children) {
-        setItems(item.treePath as string[], symbol.children);
-      }
       if (isValidItem(item)) {
         items.push(item);
       }

This is a new clone script to fetch the modified ddu-source-lsp repository.
clone_plugin_alt.sh

rm -rf repos
mkdir -p repos

git clone https://github.com/prabirshrestha/vim-lsp repos/vim-lsp
git clone https://github.com/kenji0923/vim-lsp-settings repos/vim-lsp-settings # To set language server capability to return symbols in the tree structure
git clone https://github.com/vim-denops/denops.vim repos/denops.vim
 git clone https://github.com/kenji0923/ddu.vim repos/ddu.vim
git clone https://github.com/Shougo/ddu-ui-ff repos/ddu-ui-ff
git clone -b  feature/disable_manual_pushing_children --single-branch https://github.com/kenji0923/ddu-source-lsp repos/ddu-source-lsp # Fork
git clone https://github.com/Shougo/ddu-filter-matcher_substring repos/ddu-filter-matcher_substring

After executing that script to replace plugins, by starting ddu with requesting documentSymbol by typing gs with opening test_file.py, I saw only one item with the mark of expanded but actually not. This is the first suggestion: can ddu respect isExpanded key from sources?
Image

A more important thing is after expanding the parent to list children items, typing filter keyword, no children remained in the matched list, though there are really matched chilren items , because their parent did not match. My second suggestoin is that it might be helpful to let matched children appear in the list regardless of their parents. Parents of matched children can also be in the list, maybe? And actions to move next matched item, not next shown one, which might be a parent of another matched item, would also be useful? Sorry for I don't have concrete implementation plans.
Image

But with this source implementation, there is no more duplicates even after clearing the filter input.
Image

I have just noticed that Shougo-san suggested to remove the tree support from ddu in the issue. For this LSP documentSymbol purpose, in my opinion, it is okay without the tree structure by flattening symbol items with adding hierarchy information at, for example, end of columns. But for type hierarchy, call hierarchy, and outside of LSP such as filer, tree feature might be better to be here.

Thank you so much for bringing great ecosystem into vim world.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions