preservim / tagbar

Vim plugin that displays tags in a window, ordered by scope
https://preservim.github.io/tagbar
Other
6.12k stars 486 forks source link

TagbarToggle and reopen file #750

Closed hnordholz closed 3 years ago

hnordholz commented 3 years ago

Open File Open Tagbar Close Tagbar Wipe File Open File Open Tagbar Select a tag Message: Error detected while processing function 83_JumpToTag[11]..83_GotoFileWindow: line 11: E86: Buffer 4 does not exist

Suggestion: In autoload/tagbar.vim at the end of s:CloseWindow():

Add-> let s:known_files._files = {}

   call tagbar#debug#log('CloseWindow finished')

endfunction

raven42 commented 3 years ago

@hnordholz can you list your procedure a little more and share what commands you are using in each case? I've tried a few different methods similar to what you are describing and I am not seeing this error message. Here is what I've tried:

Attempt 1:

shell: vim test.c // open a file - currently only file and buffer open in vim vim: :Tagbar // open tagbar vim: :Tagbar // close tagbar vim: :bd // delete buffer (I'm assuming this is what you mean by "Wipe File") vim: :Tagbar // open tagbar vim: navigate to tagbar window which does load tags from unloaded buffer... then selected a tag When I did this, the file opened again and jumped to the tag

Attempt 2:

shell: vim test.c // open a file - currently only file and buffer open in vim vim: :Tagbar // open tagbar vim: :Tagbar // close tagbar vim: :bd // delete buffer (I'm assuming this is what you mean by "Wipe File") shell: rm test.c // Completely remove the file from the file system vim: :Tagbar // open tagbar vim: navigate to tagbar window which does load tags from unloaded buffer... then selected a tag When I did this, the test.c file opened as an empty file and cursor jumped to the 1st line

Attempt 3:

shell: vim // open vim without any file vim: :e test.c // open test.c - currently only file and buffer open in vim vim: :Tagbar // open tagbar vim: :Tagbar // close tagbar vim: :bd // delete buffer (I'm assuming this is what you mean by "Wipe File") shell: rm test.c // Completely remove the file from the file system vim: :Tagbar // open tagbar vim: navigate to tagbar window which does load tags from unloaded buffer... then selected a tag When I did this, the test.c file opened as an empty file and cursor jumped to the 1st line (same result as Attempt 2)

hnordholz commented 3 years ago

Well, I overlooked an important step: you need to wipe out the file from another buffer: Procedure: Two existing files a.c and b.c vim a.c b.c TagbarOpen TagbarClose bn // goto next buffer bwipe a.c e a.c TagbarOpen Select a tag...

I realized, that when you use bdelete instead of bwipe the problem does not occur. So it might not really be a bug, but a wrong usage of bwipe on my side. I also want to mention, that I am using neovim v0.5.

alerque commented 3 years ago

I am using neovim v0.5

No you're not; v0.5 hasn't even been released yet. You may be using an early development snapshot, but there hasn't even been a feature freeze leading up to alpha/beta releases yet. I've complained about the upstream version scheme before because this is not clear to a lot of people. They improved the GitHub release titles but they didn't fix the in-app identification. :shrug:

raven42 commented 3 years ago

Thanks @hnordholz. I was able to reproduce. There was code in place to unload the contents of a buffer from tagbar, but that was only being executed when the tagbar window was open. I've opened a PR to address this and make sure to remove the file from tagbar memory even if the tagbar window isn't open.

hnordholz commented 3 years ago

Sorry, but it still doesn't work on my machine. I tried it also with VIM 8.2 and the result is the same. Works nicely with bdelete, but not with bwipe. I also double checked, that I really have the last commit running.

raven42 commented 3 years ago

edit: only able to repro before commit with :bwipe

Hmm... I am able to reproduce just fine before the commit with :bwipe, but with the commit, both work just fine without any error.

Can you capture the tagbar debug log and post that here while you are doing this to provide more info? You can use :TagbarDebug <file> to dump the logs to the file. Do this before any other tagbar command so we can get the info needed.

hnordholz commented 3 years ago

Ok, here is the log-file. tagbar.log

raven42 commented 3 years ago

I'm not seeing the logs of the event in here. From the logs it looks like only a.c was loaded... there is nothing about loading the info about loading file b.c or closing file a.c. Did you capture the logs from the whole procedure? You need to first use the :TagbarDebug command to start the logging, then go through the procedure you have to capture the logs of the event causing the error.

hnordholz commented 3 years ago

What I did: vim a.c b.c TagbarDebug tagbar.log TagbarOpen TagbarClose bn bw a.c e a.c TagbarOpen then clicked on a tag and got the error Message. then closed vim

That‘s all.

My .vimrc contains only one line: packadd tagbar

In the next days I will try to debug the stuff by myself. Perhaps I have an unusual strange environment. By the way: my operating system is Kubuntu 2010.

Regards Henning

raven42 commented 3 years ago

Yes I understand the procedure you are doing. I was able to reproduce this before the commit following the steps you provided. I am not able to reproduce this after the commit. If you are able to use the :TagbarDebug as I indicated and go through the procedure again the logs may have more info as to what is going on. I would need to see the logs during the :bwipe part of the procedure. The logs provided only showed loading of a.c. There was no reference to b.c in the logs that were provided. There should be log entries showing b.c being parsed and tags loaded. I want to try to help, but I need more info.

hnordholz commented 3 years ago

Thank you for your patience.

I changed the procedure a little bit, to avoid the 'buggy operator'. Attached you will find a script 'test_tagbar.vim'. I also added a.c and b.c and the newly produced log file. I just run /usr/bin/vim -c "source test_tagbar.vim". Then I got the error message and closed the program with :qa

My environment xterm, tmux, vim version 8.2 (original version from Ubuntu/Kubuntu 20.10) ~/.vimrc contains still only one line: packadd tagbar The tagbar commit ID is: commit 84afd8e80217f5757a74522201c4610e79e07611

The log-file doesn't mention b.c, but when b.c was the current buffer, no tagbar was open. Is the file scanned regardless whether the tagbar is shown?

If this is the case, could you run the test script and send me your log file?

tagbar-test.tar.gz

raven42 commented 3 years ago

Success! well kind of... i was able to repro with the commit. Turns out with the combination of plugins I have the previous commit fix for this did cause it to work for me. For me it happens to be the following lightline configuration which was causing the commit to work for me.

    let g:lightline = {
                \ 'component_function': {
                \   'functionName': 'LightlineFunctionName',
                \ },
            \ }

        " ---- LightlineFunctionName() {{{2
    function! LightlineFunctionName()
        if &filetype =~# g:ignored_filetypes
            return ''
        endif
        return tagbar#currenttag("%s", "", 'f', 'nearest-stl')
    endfunction

This combined with the lightline plugin was changing the behavior in my environment slightly so with the commit, the unload of the file was working.

Let me dig into it a little more and see if I can figure out what is going on.

raven42 commented 3 years ago

Ok... here is the issue.

" s:CloseWindow() {{{2
function! s:CloseWindow() abort
    ...
    if s:autocommands_done && !s:statusline_in_use
        call tagbar#StopAutoUpdate()
    endif
    ...
endfunction

In my case, the statusline_in_use was getting set so the autocmds were not being cleared. But if you run with a bare config that doesn't use the status line, then tagbar will clear the autocmds thus we never get notified when for the following:

autocmd BufDelete,BufWipeout * ...

So there are a few ways we could fix this.

  1. Move BufDelete / BufWipeout autocmds into their own augroup so they never get removed. This would have the least impact I think, but would cause some processing to occur when a buffer is deleted or wiped out. This would be done after the tagbar window is opened, and then any buffer is closed or wiped. This is what I'm leaning toward.

    
    diff --git a/autoload/tagbar.vim b/autoload/tagbar.vim
    index 09b6888..1da6055 100644
    --- a/autoload/tagbar.vim
    +++ b/autoload/tagbar.vim
    @@ -582,8 +582,6 @@ function! s:CreateAutocommands() abort
                 autocmd CursorHoldI * call
                         \ s:AutoUpdate(fnamemodify(expand('<afile>'), ':p'), 0)
             endif
    -            autocmd BufDelete,BufWipeout *
    -                        \ nested call s:HandleBufDelete(expand('<afile>'), expand('<abuf>'))
    
             " Suspend Tagbar while grep commands are running, since we don't want
             " to process files that only get loaded temporarily to search them
    @@ -596,6 +594,15 @@ function! s:CreateAutocommands() abort
         endif
     augroup END
2. Second option is we could just remove the autocmds cleanup and once we've registered for autocmds, just keep them registered. This will cause some extra processing of tags if the tagbar window was ever opened. So I can see this being a little bit of an issue if someone has large files open that they don't use tagbar for, but then one file where they quickly want to open tagbar, then close it again once they get the info they need out of it. However this only applies to anybody that isn't using the statusline functionality. Anytime somebody uses either the `tagbar#currenttag()` or `tagbar#currenttagtype()` routines, then they area already seeing this behavior (which I am), and I haven't noticed any performance issues that I am hindered by.
```patch
diff --git a/autoload/tagbar.vim b/autoload/tagbar.vim
index 09b6888..5f093f1 100644
--- a/autoload/tagbar.vim
+++ b/autoload/tagbar.vim
@@ -1098,10 +1098,6 @@ function! s:CloseWindow() abort

     call s:ShrinkIfExpanded()

-    if s:autocommands_done && !s:statusline_in_use
-        call tagbar#StopAutoUpdate()
-    endif
-
     call tagbar#debug#log('CloseWindow finished')
 endfunction
  1. Alternatively we could go with the approach similar to the one mentioned in this issue submission. This would be to update the CloseWindow() routine to trigger a remove all files from the tagbar buffer memory when the tagbar window closes. This would essentially wipe out all tagbar info anytime the tagbar window is closed. I'm not in favor of this because it would mean having to reinitialize and rerun tag parsing on any file again when the tagbar window is opened. It defeats the entire purpose of caching the tagbar info when switching buffers / windows. It would mean extra processing and extra lag anytime the tagbar window is opened. So if somebody is opening / closing the tagbar window often enough, this is going to get really annoying for larger files.
    
    diff --git a/autoload/tagbar.vim b/autoload/tagbar.vim
    index 09b6888..389aab9 100644
    --- a/autoload/tagbar.vim
    +++ b/autoload/tagbar.vim
    @@ -1102,6 +1102,10 @@ function! s:CloseWindow() abort
         call tagbar#StopAutoUpdate()
     endif


So I'll open this one up... I'm leaning toward option 1 as it would seem to have the least impact, but it does introduce a second autocmd group for tagbar. Not sure if that is a deal breaker for anybody.
raven42 commented 3 years ago

For option 3 we might want to look at better cleanup logic. Looping through each entry and doing a s:known_files.rm() on each entry would be better. I'm just not in favor of this option, so I didn't code that up for the example.

raven42 commented 3 years ago

@hnordholz I've pushed up a PR for this issue (#769). Can you give that a try to make sure it works for you too?