Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TagbarToggle and reopen file #750

Closed
hnordholz opened this issue Feb 10, 2021 · 15 comments · Fixed by #768 or #769
Closed

TagbarToggle and reopen file #750

hnordholz opened this issue Feb 10, 2021 · 15 comments · Fixed by #768 or #769

Comments

@hnordholz
Copy link

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
Copy link
Collaborator

raven42 commented May 21, 2021

@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
Copy link
Author

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
Copy link
Member

alerque commented May 22, 2021

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. 🤷

raven42 added a commit to raven42/tagbar that referenced this issue May 24, 2021
Closes preservim#750

On `:bdelete` or `:bwipe` of a file, remove the file from the known file
listing even if the tagbar window is not open. Previously was only
removing the file if the tagbar window was open.
@raven42
Copy link
Collaborator

raven42 commented May 24, 2021

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.

raven42 added a commit that referenced this issue May 24, 2021
Closes #750

On `:bdelete` or `:bwipe` of a file, remove the file from the known file
listing even if the tagbar window is not open. Previously was only
removing the file if the tagbar window was open.
@hnordholz
Copy link
Author

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
Copy link
Collaborator

raven42 commented May 24, 2021

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
Copy link
Author

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

@raven42
Copy link
Collaborator

raven42 commented May 24, 2021

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
Copy link
Author

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
Copy link
Collaborator

raven42 commented May 24, 2021

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.

@raven42 raven42 reopened this May 24, 2021
@hnordholz
Copy link
Author

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 84afd8e

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
Copy link
Collaborator

raven42 commented May 25, 2021

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
Copy link
Collaborator

raven42 commented May 25, 2021

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
 
+    " Separate these autocmds out from the others as we want to always perform
+    " these actions even if the tagbar window closes.
+    augroup TagbarCleanupAutoCmds
+        if !g:tagbar_no_autocmds
+            autocmd BufDelete,BufWipeout *
+                        \ nested call s:HandleBufDelete(expand('<afile>'), expand('<abuf>'))
+        endif
+    augroup END
+
     let s:autocommands_done = 1
 endfunction
 
  1. 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.
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
 
+    let s:known_files = {
+        \ '_files'   : {}
+    \ }
+
     call tagbar#debug#log('CloseWindow finished')
 endfunction
 

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
Copy link
Collaborator

raven42 commented May 25, 2021

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 added a commit to raven42/tagbar that referenced this issue May 26, 2021
Fixes preservim#750

Once the tagbar window is opened and a file is registered, that file
stays in memory even if the tagbar window is closed. This allows tagbar
to cache the info so if the tagbar window is opened again, it doesn't
have to rescan the file and rerun ctags on the file.

However if this buffer is wiped out using `:bwipe <file>`, then the
buffer is completely unloaded from vim memory and also needs to be
unloaded from tagbar memory. This works if the tagbar window is open,
but in the event the tagbar window is closed, all autocmds are
unregistered, so tagbar never gets the BufWipeout notification. This
results in tagbar leaving the buffer in active memory even though the
buffer doesn't exist anymore.

This fix will leave the BufWipeout and BufDelete autocmds active even if
the tagbar window is closed. This allows the buffer cleanup to occur on
a `:bwipe` command even if the tagbar window is closed.
@raven42
Copy link
Collaborator

raven42 commented May 26, 2021

@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?

raven42 added a commit that referenced this issue May 27, 2021
Fixes #750

Once the tagbar window is opened and a file is registered, that file
stays in memory even if the tagbar window is closed. This allows tagbar
to cache the info so if the tagbar window is opened again, it doesn't
have to rescan the file and rerun ctags on the file.

However if this buffer is wiped out using `:bwipe <file>`, then the
buffer is completely unloaded from vim memory and also needs to be
unloaded from tagbar memory. This works if the tagbar window is open,
but in the event the tagbar window is closed, all autocmds are
unregistered, so tagbar never gets the BufWipeout notification. This
results in tagbar leaving the buffer in active memory even though the
buffer doesn't exist anymore.

This fix will leave the BufWipeout and BufDelete autocmds active even if
the tagbar window is closed. This allows the buffer cleanup to occur on
a `:bwipe` command even if the tagbar window is closed.
dev-hann added a commit to dev-hann/tagbar that referenced this issue Sep 18, 2023
Closes preservim#750

On `:bdelete` or `:bwipe` of a file, remove the file from the known file
listing even if the tagbar window is not open. Previously was only
removing the file if the tagbar window was open.
dev-hann added a commit to dev-hann/tagbar that referenced this issue Sep 18, 2023
…servim#769)

Fixes preservim#750

Once the tagbar window is opened and a file is registered, that file
stays in memory even if the tagbar window is closed. This allows tagbar
to cache the info so if the tagbar window is opened again, it doesn't
have to rescan the file and rerun ctags on the file.

However if this buffer is wiped out using `:bwipe <file>`, then the
buffer is completely unloaded from vim memory and also needs to be
unloaded from tagbar memory. This works if the tagbar window is open,
but in the event the tagbar window is closed, all autocmds are
unregistered, so tagbar never gets the BufWipeout notification. This
results in tagbar leaving the buffer in active memory even though the
buffer doesn't exist anymore.

This fix will leave the BufWipeout and BufDelete autocmds active even if
the tagbar window is closed. This allows the buffer cleanup to occur on
a `:bwipe` command even if the tagbar window is closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants