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

easytags.vim 2.4.11: Vim(let):E713: Cannot use empty key for Dictionary #16

Closed
zhaocai opened this issue Aug 19, 2011 · 16 comments
Closed

Comments

@zhaocai
Copy link

zhaocai commented Aug 19, 2011

Can anyone help for the following issue? Thanks.
Error Message:
easytags.vim 2.4.11: Vim(let):E713: Cannot use empty key for Dictionary (at function xolox#easytags#autoload..xolox#easytags#update..103_filter_merge_tags..103_find_tagged_files..103_canonicalize, line 5)

Configuration:

set tags=./tags;,$HOME/.vim/vimtags
let g:easytags_always_enabled = 1
let g:easytags_file = '/.vim/vimtags/easytags'
let g:easytags_dynamic_files = 1
let g:easytags_by_filetype = "
/.vim/vimtags/"
let g:easytags_auto_highlight = 1

if has("autocmd")
autocmd FileType cpp,python,java let g:easytags_include_members = 1
endif

" If you like one of the existing styles you can link them:
highlight link cMember Special

" You can also define your own style if you want:
highlight cMember gui=italic

" set this if you use symlinks
let g:easytags_resolve_links = 1

@xolox
Copy link
Owner

xolox commented Aug 19, 2011

I think the error happens because the plug-in is trying to read a corrupt tags file. If you can reproduce the issue, please execute the Vim command :call confirm(string(tagfiles())) in the same buffer where you got the error. This will pop up a list of the tags files that the plug-in is trying to read. Are there any non-expected entries in the list? Maybe the plug-in is trying to read something which is not actually a tags file (that could definitely cause an error such as the one you're seeing). Anyway, I will probably update the plug-in to just ignore invalid entries; it shouldn't error out like this.

@zhaocai
Copy link
Author

zhaocai commented Aug 19, 2011

I think I find the problem. ctags somehow cannot generate tags for my .vimrc file now. it produces something like this:

$ cat tags
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.8 //

@zhaocai zhaocai closed this as completed Aug 19, 2011
@zhaocai zhaocai reopened this Aug 19, 2011
@zhaocai
Copy link
Author

zhaocai commented Aug 19, 2011

By the way, I am trying to read the Error Message:
easytags.vim 2.4.11: Vim(let):E713: Cannot use empty key for Dictionary (at function xolox#easytags#autoload..xolox#easytags#update..103_filter_merge_tags..103_find_tagged_files..103_canonicalize, line 5)

Does it mean that the error happens at line 5 in function canonicalize and backtracked to xolox#easytags#autoload. If that is right, I cannot understand the error because function canonicalize is just about file names.

@zhaocai
Copy link
Author

zhaocai commented Aug 19, 2011

I have to add --language-force=vim option for ctags to generate tags for the .vimrc. How can I configure this.

@xolox
Copy link
Owner

xolox commented Aug 19, 2011

By the way, I am trying to read the Error Message

The error message starts on the left with the function at the bottom of the call stack and ends at the right with the function in which the actual error was encountered:

  • xolox#easytags#autoload() is called from an automatic command
  • this calls xolox#easytags#update() to update the tags for the current file (runs Exuberant Ctags and intercepts the output instead of writing it to a tags file)
  • this calls s:filter_merge_tags() to merge the old and new tags (to avoid duplicate entries)
  • this calls s:find_tagged_files() to find the pathname(s) for which tags were just generated
  • this calls s:canonicalize() to normalize pathnames so they can be compared with a regular comparison (actually the pathnames are stored in a dictionary)

The output of Exuberant Ctags is parsed from xolox#easytags#update() and apparently the result in your case contains one or more lines which are not headers (the lines that start with !_TAG_) and also don't contain a filename.

I have to add --language-force=vim option for ctags to generate tags for the .vimrc. How can I configure this.

The plug-in should be doing this automatically already, given your configuration (see the function s:prep_cmdline() if you're interested). Please open your .vimrc and execute the Vim command :verbose UpdateTags. This will print the command line that's executed in the background. If the command line disappears you can use the :messages command to view the message history.

@zhaocai
Copy link
Author

zhaocai commented Aug 19, 2011

Thanks for your help. :)

  1. :verbose UpdateTags

    easytags.vim 2.4.11: Executing ctags --fields=+l --c-kinds=+p --c++-kinds=+p --sort=no -f- '--language-force=vim' '/Volumes/Users/zhaocai/Developer/Vim/vimrc'.
    not found in 'runtimepath': "autoload/xolox/shell.vim"
    easytags.vim 2.4.11: Vim(let):E713: Cannot use empty key for Dictionary (at function xolox#easytags#update..105_filter_merge_tags..105_find_tagged_files..105_canonicalize, line 5)
    easytags.vim 2.4.11: Vim(let):E713: Cannot use empty key for Dictionary (at function xolox#easytags#autoload..xolox#easytags#update..105_filter_merge_tags..105_find_tagged_files..105_canonicalize, line 5)

Does 'not found in 'runtimepath': "autoload/xolox/shell.vim" ' tell anything to help?

  1. I tried to type in the terminal.
    ctags --fields=+l --c-kinds=+p --c++-kinds=+p --sort=no -f- '--language-force=vim' '/Volumes/Users/zhaocai/Developer/Vim/vimrc'

It seems the tags generated are correct.

@zhaocai
Copy link
Author

zhaocai commented Aug 20, 2011

I nailed down the problem to the following key mapping:

I just need to comment out this line,
nnoremap z/ :if g:AutoHighlightToggle()set hlsendif

any idea about this problem? Thanks for your help!


http://vim.wikia.com/wiki/Auto_highlight_current_word_when_idle
" Highlight all instances of word under cursor, when idle.
" Useful when studying strange source code.
" Type z/ to toggle highlighting on/off.
nnoremap z/ :if g:AutoHighlightToggle()set hlsendif
function! g:AutoHighlightToggle()
let @/ = ''
if exists('#auto_highlight')
au! auto_highlight
augroup! auto_highlight
setl updatetime=2000
echo 'Highlight current word: off'
return 0
else
augroup auto_highlight
au!
au CursorHold * let @/ = '\V<'.escape(expand(''), '').'>'
augroup end
setl updatetime=300
echo 'Highlight current word: ON'
return 1
endif
endfunction

@zhaocai
Copy link
Author

zhaocai commented Aug 20, 2011

One more thing, I notice easy tag use --sort=no option to generate ctags. why is that? I ask because (1) sort should be good for searching, especially for large tag data (2) sometimes, vim shows up message about unsorted tags error.

@xolox
Copy link
Owner

xolox commented Sep 4, 2011

I nailed down the problem to the following key mapping:

I just need to comment out this line,
nnoremap z/ :if g:AutoHighlightToggle()set hlsendif

any idea about this problem? Thanks for your help!

The s:AutoHighlightToggle() function you're using works by setting a very low 'updatetime' value so that the CursorHold automatic command updates the highlighting in real time (as you type). I have a mapping like this as well and although the functionality is nice it has some nasty consequences:

The easytags plug-in also uses the CursorHold automatic command: Every time the automatic command fires the plug-in checks for changes and runs Exuberant Ctags. The 'updatetime' option is global so when s:AutoHighlightToggle() lowers it to 400 milliseconds this means the easytags plug-in will also be called every 0,4 second...

I'm not sure if there is a sane way to fix this. What I can do is add a check to easytags so that if the 'updatetime' is very low, it will give a warning and temporarily disable execution.

One more thing, I notice easy tag use --sort=no option to generate ctags. why is that?

The easytags plug-in updates your tags files like this:

  • Run Exuberant Ctags, intercept new tags, determine which files were scanned;
  • Read existing tags file, filter old tags for files that were just scanned (so you don't get duplicate tags);
  • Combine filtered old tags and intercepted new tags, sort them and write them to the tags file.

To answer your question: The easytags plug-in uses --sort=no as a minor performance optimization. Because the plug-in has to combine the old/new tags there's no point in having Exuberant Ctags sort its output (because to combine the old/new tags everything has to be sorted at once).

I ask because (1) sort should be good for searching, especially for large tag data (2) sometimes, vim shows up message about unsorted tags error.

  1. Whenever the easytags plug-in writes a tags file to disk it sorts everything so that Vim can use binary search to process tags files;
  2. I've gotten the same error occasionally but haven't been able to reliably reproduce it. If you find a combination of a tags file, input file and Exuberant Ctags command line that always produces this problem please contact me.

I suspect that the unsorted tags error only happens when Vim tries to read the tags file while its being written. In this case I may be able to fix this problem permanently by writing a new tags file to ~/.vim/tags/filetype.tmp and renaming it to ~/.vim/tags/filetype when done.

@xolox
Copy link
Owner

xolox commented Sep 4, 2011

Just now I committed three changes based on your feedback (thanks for that!). If you're satisfied with these changes, please close this issue, otherwise maybe you have suggestions?

@zhaocai
Copy link
Author

zhaocai commented Sep 5, 2011

Thanks for the updates. I just tried it out. It works great except 1 problem:
The g:easytags_by_filetype option does not work correctly.

My Settings:
set tags=./tags;
set tagrelative
let g:easytags_always_enabled = 1
let g:easytags_file = "/.vim/vimtags/easytags"
let g:easytags_dynamic_files = 1
let g:easytags_by_filetype = "
/.vim/vimtags/ft"
Problem details:
file 'tags' is generated in the location of the editing file instead of merging into the &filetype based tag file.

I tried to debug it, but I can get it fixed in an hour. I am sure you can figure it out much quicker than I do.

and I found a small typo to fix:
diff --git a/autoload/xolox/easytags.vim b/autoload/xolox/easytags.vim
index 7f4c169..ed3b78a 100644
--- a/autoload/xolox/easytags.vim
+++ b/autoload/xolox/easytags.vim
@@ -624,7 +624,6 @@ function! s:canonicalize(filename) " {{{2
let canonical = s:resolve(fnamemodify(a:filename, ':p'))
let s:cached_filenames[a:filename] = canonical
return canonical

  • endif
    endif
    return ''
    endfunction

On Sep 4, 2011, at 8:03 AM, xolox wrote:

Just now I committed three changes based on your feedback (thanks for that!). If you're satisfied with these changes, please close this issue, otherwise maybe you have suggestions?

Reply to this email directly or view it on GitHub:
#16 (comment)

xolox added a commit that referenced this issue Sep 5, 2011
Some users want the plug-in to use existing project specific tags files
but fall back to the global tags file or a file type specific tags file
if a project specific tags file does not exist. Other users want the
plug-in to automatically create project specific tags files. Both are
reasonable options to have. I hope with this change we can all
be happy :-) (see also issue #15 and issue #16 on GitHub).
@xolox
Copy link
Owner

xolox commented Sep 5, 2011

Thanks for the updates. I just tried it out. It works great except 1 problem: The g:easytags_by_filetype option does not work correctly. The file 'tags' is generated in the location of the editing file instead of merging into the &filetype based tag file.

Sorry about that, it was an unrelated change (see issue #15) that was not backwards compatible and maybe a bit of a surprise. In the commit above (fae8ddd) I've restored the former behavior when g:easytags_dynamic_files is 1. I hope it works okay now :-)

@zhaocai
Copy link
Author

zhaocai commented Sep 6, 2011

It works well now. Thanks for the update :)

@zhaocai zhaocai closed this as completed Sep 6, 2011
@zhaocai
Copy link
Author

zhaocai commented Sep 6, 2011

One more question about the performance of easytags. I have a kernel project which generates tags of about 10M size. I have eliminated all possible events as the following config.
let g:easytags_always_enabled = 0
let g:easytags_on_cursorhold = 0
let g:easytags_events = ['BufWritePost']
But, still I experienced few seconds delay every time I save a file.

I noticed that you have the vim-shell plugin which can run cmd in the background. But it does not help this situation.

My guess is, if I do not want to get instant highlight update, the other work to update tags should be all done in the background and return to the UI without noticeable delay.

On Sep 5, 2011, at 2:59 PM, xolox wrote:

Thanks for the updates. I just tried it out. It works great except 1 problem: The g:easytags_by_filetype option does not work correctly. The file 'tags' is generated in the location of the editing file instead of merging into the &filetype based tag file.

Sorry about that, it was an unrelated change (see issue #15) that was not backwards compatible and maybe a bit of a surprise. In the commit above (fae8ddd) I've restored the former behavior when g:easytags_dynamic_files is 1. I hope it works okay now :-)

Reply to this email directly or view it on GitHub:
#16 (comment)

@xolox
Copy link
Owner

xolox commented Sep 15, 2011

The plug-in is slowing Vim down in your case because every time you save a file the plug-in updates the tags file, in effect reading+filtering+sorting+writing the whole 10 MB every time... Right now my plug-in doesn't have a good way to deal with this problem and solving it is kind of tricky. There are two basic options:

  • Use the support for dynamic tags files to create tags files for all or selected subdirectories of your kernel tree. Now you won't have highlighting for all kernel functions in every file (a disadvantage) but because the tags are distributed over a set of tags files the plug-in should update tags much faster.
  • I have a private branch of the easytags repository that contains an executable that wraps Exuberant Ctags and performs tags file updating outside of Vim. The code basically works but it has to be compiled with a C compiler and I'm not sure I'm up to distributing binaries of this program to users of the easytags plug-in (binaries are complicated to support). Also this wrapper introduces a new layer of complexity while the easytags plug-in is already very complex (too complex in fact, it's become hard to extend and refactor).

If the first option is not useful to you and you're okay with compiling a binary that wraps Exuberant Ctags, I may decide to publish the wrapper code (even though it's still kind of a mess). I hope this helps!

@zhaocai
Copy link
Author

zhaocai commented Sep 20, 2011

Hi Peter

I got another solution for this performance issue: using remote server to update tags.

Basically, a new vim window is opened to do the work asynchronously. This will update the tags without blocking current vim window. Part of the code snippets are attached for your reference.


.vimrc

let g:easytags_servername = "EASYTAGSREMOTE"
let g:easytags_server_rc = "~/.vimrc_easytags"

let g:easytags_update_interval = 60
":TODO: Sun Sep 11, 2011 12:48PM, zhaocai
" better solution is to peek server busy/free status

if v:servername != g:easytags_servername
for s:eventname in g:easytags_events
execute 'autocmd' s:eventname '* call g:EasyTagsRemoteUpdate(' string(s:eventname) ')'
endfor
endif


.func

func! g:EasyTagsRemoteUpdate(event)
" filetype check {{{5
if index(xolox#easytags#supported_filetypes(), &ft) < 0
return 0
endif

" first run: open server                                              {{{5
if !remote#exists_server(g:easytags_servername)
    call remote#open_remoteserver(g:easytags_servername,g:easytags_server_rc)
    let l:try_nr = 100
    while l:try_nr > 0
        try
            call remote_send(g:easytags_servername, ":colorscheme solarized<CR>")
            call remote_send(g:easytags_servername, ":let &titlestring= \"" . g:easytags_servername .  "\"<CR>")
            call remote_send(g:easytags_servername, ":set autoread<CR>")
            break
        catch /^Vim\%((\a\+)\)\=:E241/
            sleep 200m
        endtry
        let l:try_nr = l:try_nr - 1
    endwhile
endif
" first run: create local timer                                       {{{5
if !exists("g:last_easytags_update_time")
    let g:last_easytags_update_time = localtime() - g:easytags_update_interval - 1
endif

" call remote server                                                  {{{5
if (localtime() - g:last_easytags_update_time) > g:easytags_update_interval
    call remote_send(g:easytags_servername, ":view " . expand("%:p") . "<CR>")
    call remote_send(g:easytags_servername, ":UpdateTags<CR>")
    let g:last_easytags_update_time = localtime()
endif

endf

On Sep 15, 2011, at 5:22 PM, Peter Odding wrote:

The plug-in is slowing Vim down in your case because every time you save a file the plug-in updates the tags file, in effect reading+filtering+sorting+writing the whole 10 MB every time... Right now my plug-in doesn't have a good way to deal with this problem and solving it is kind of tricky. There are two basic options:

  • Use the support for dynamic tags files to create tags files for all or selected subdirectories of your kernel tree. Now you won't have highlighting for all kernel functions in every file (a disadvantage) but because the tags are distributed over a set of tags files the plug-in should update tags much faster.
  • I have a private branch of the easytags repository that contains an executable that wraps Exuberant Ctags and performs tags file updating outside of Vim. The code basically works but it has to be compiled with a C compiler and I'm not sure I'm up to distributing binaries of this program to users of the easytags plug-in (binaries are complicated to support). Also this wrapper introduces a new layer of complexity while the easytags plug-in is already very complex (too complex in fact, it's become hard to extend and refactor).

If the first option is not useful to you and you're okay with compiling a binary that wraps Exuberant Ctags, I may decide to publish the wrapper code (even though it's still kind of a mess). I hope this helps!

Reply to this email directly or view it on GitHub:
#16 (comment)

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

No branches or pull requests

2 participants