diff options
author | Peter Odding <peter@peterodding.com> | 2010-06-13 02:02:42 +0200 |
---|---|---|
committer | Peter Odding <peter@peterodding.com> | 2010-06-13 02:02:42 +0200 |
commit | ad3bd15a76acaeb8bd5c92e104ab95a7b55f6fee (patch) | |
tree | 563aae675432b6556ad00de5c6d5e50a327bd963 | |
parent | dcbed282e236484adfd7bca593f8fc2bb0503e35 (diff) | |
download | vim-easytags-ad3bd15a76acaeb8bd5c92e104ab95a7b55f6fee.tar.gz |
Fixed tags file corruption on Windows!
* Fixed tags file corruption on Windows: It turns out that the function
readfile() accepts CR+NL line endings and just strips CR characters,
however the writefile() function doesn't write CR+NL but just NL.
Manually adding the CR characters to the end of each line before
writing the tags file solves the corruption bug.
* The headers and entries in tags files are now properly separated from
each other while rewriting the tags file to filter expired entries.
* Don't bother trying to filter expired tags when the tags file doesn't
reference the current filename at all (improves performance a bit).
* Fixed a buggy easytags#file_has_tags() call in easytags#autoload()
that made the plug-in always scan each edited file at least once.
* Changed folds to provide basic outline of function categories.
* Restructured definitions for default configuration of dynamic syntax
highlighting support so definitions don't all have to be indented.
Sorry about the large diff, this version took a few days of
experimentation to build which means lots of little changes.
-rw-r--r-- | autoload.vim | 358 | ||||
-rw-r--r-- | easytags.vim | 4 |
2 files changed, 201 insertions, 161 deletions
diff --git a/autoload.vim b/autoload.vim index 706f450..ac48f4a 100644 --- a/autoload.vim +++ b/autoload.vim @@ -1,12 +1,14 @@ " Vim script " Maintainer: Peter Odding <peter@peterodding.com> -" Last Change: June 10, 2010 +" Last Change: June 13, 2010 " URL: http://peterodding.com/code/vim/easytags -function! easytags#autoload() " {{{1 +" Public interface through (automatic) commands. {{{1 + +function! easytags#autoload() " {{{2 try " Update the entries for the current file in the global tags file? - let pathname = expand('%') + let pathname = s:resolve(expand('%:p')) let tags_outdated = getftime(pathname) > getftime(easytags#get_tagsfile()) if tags_outdated || !easytags#file_has_tags(pathname) UpdateTags @@ -30,32 +32,35 @@ function! easytags#autoload() " {{{1 endtry endfunction -function! easytags#update_cmd(filter_invalid_tags) " {{{1 +function! easytags#update_cmd(filter_invalid_tags) " {{{2 try + let filename = s:resolve(expand('%:p')) let ft_supported = index(easytags#supported_filetypes(), &ft) >= 0 let ft_ignored = g:easytags_ignored_filetypes != '' && &ft =~ g:easytags_ignored_filetypes if (ft_supported && !ft_ignored) || a:filter_invalid_tags let start = xolox#timer#start() let tagsfile = easytags#get_tagsfile() - let filename = s:resolve(expand('%:p')) let command = [g:easytags_cmd, '-f', shellescape(tagsfile), '--fields=+l'] if filereadable(tagsfile) call add(command, '-a') - let lines = readfile(tagsfile) - call s:update_tagged_files(lines) - let filters = [] - if ft_supported && !ft_ignored - let filename_pattern = '\t' . xolox#escape#pattern(filename) . '\t' - call add(filters, 'v:val !~ filename_pattern') - endif - if a:filter_invalid_tags - call add(filters, 'filereadable(get(split(v:val, "\t"), 1))') - endif - let filter = 'v:val =~ "^!_TAG_" || (' . join(filters, ' && ') . ')' - let filtered = filter(copy(lines), filter) - if len(lines) != len(filtered) - if writefile(filtered, tagsfile) != 0 - throw "Failed to write filtered tags file!" + let filter_file_tags = easytags#file_has_tags(filename) + if a:filter_invalid_tags || filter_file_tags + let [header, entries] = easytags#read_tagsfile(tagsfile) + let num_entries = len(entries) + call s:set_tagged_files(entries) + let filters = [] + if ft_supported && !ft_ignored && filter_file_tags + let filename_pattern = '\t' . xolox#escape#pattern(filename) . '\t' + call add(filters, 'v:val !~ filename_pattern') + endif + if a:filter_invalid_tags + call add(filters, 'filereadable(get(split(v:val, "\t"), 1))') + endif + call filter(entries, join(filters, ' && ')) + if len(entries) != num_entries + if !easytags#write_tagsfile(tagsfile, header, entries) + throw "Failed to write filtered tags file!" + endif endif endif endif @@ -77,21 +82,7 @@ function! easytags#update_cmd(filter_invalid_tags) " {{{1 endtry endfunction -function! easytags#supported_filetypes() " {{{1 - if !exists('s:supported_filetypes') - let start = xolox#timer#start() - let listing = system(g:easytags_cmd . ' --list-languages') - if v:shell_error - throw "Failed to get Exuberant Ctags language mappings!" - endif - let s:supported_filetypes = split(listing, '\n') - call map(s:supported_filetypes, 'easytags#to_vim_ft(v:val)') - call xolox#timer#stop(start, "easytags.vim: Parsed language mappings in %s second(s)") - endif - return s:supported_filetypes -endfunction - -function! easytags#highlight_cmd() " {{{1 +function! easytags#highlight_cmd() " {{{2 try if exists('g:syntax_on') && has_key(s:tagkinds, &ft) let start = xolox#timer#start() @@ -124,7 +115,62 @@ function! easytags#highlight_cmd() " {{{1 endtry endfunction -function! easytags#get_tagsfile() " {{{1 +" Public supporting functions (might be useful to others). {{{1 + +function! easytags#supported_filetypes() " {{{2 + if !exists('s:supported_filetypes') + let start = xolox#timer#start() + let listing = system(g:easytags_cmd . ' --list-languages') + if v:shell_error + throw "Failed to get Exuberant Ctags language mappings!" + endif + let s:supported_filetypes = split(listing, '\n') + call map(s:supported_filetypes, 'easytags#to_vim_ft(v:val)') + call xolox#timer#stop(start, "easytags.vim: Parsed language mappings in %s second(s)") + endif + return s:supported_filetypes +endfunction + +function! easytags#read_tagsfile(tagsfile) " {{{2 + let lines = readfile(a:tagsfile) + let header = [] + while lines != [] && lines[0] =~# '^!_TAG_' + call insert(header, remove(lines, 0)) + endwhile + while lines != [] && lines[-1] == '' + call remove(lines, -1) + endwhile + return [header, lines] +endfunction + +function! easytags#write_tagsfile(tagsfile, header, entries) " {{{2 + let lines = [] + if has('win32') || has('win64') + for line in a:header + call add(lines, line . "\r") + endfor + for entry in a:entries + call add(lines, entry . "\r") + endfor + else + call extend(lines, a:header) + call extend(lines, a:entries) + endif + return writefile(lines, a:tagsfile) == 0 +endfunction + +function! easytags#file_has_tags(filename) " {{{2 + call s:cache_tagged_files() + return has_key(s:tagged_files, s:resolve(a:filename)) +endfunction + +function! easytags#add_tagged_file(filename) " {{{2 + call s:cache_tagged_files() + let filename = s:resolve(a:filename) + let s:tagged_files[filename] = 1 +endfunction + +function! easytags#get_tagsfile() " {{{2 let tagsfile = expand(g:easytags_file) if filereadable(tagsfile) && filewritable(tagsfile) != 1 let message = "The tags file isn't writable! (%s)" @@ -133,7 +179,9 @@ function! easytags#get_tagsfile() " {{{1 return tagsfile endfunction -function! easytags#define_tagkind(object) " {{{1 +" Public API for file-type specific dynamic syntax highlighting. {{{1 + +function! easytags#define_tagkind(object) " {{{2 if !has_key(a:object, 'pattern_prefix') let a:object.pattern_prefix = '\C\<' endif @@ -146,12 +194,12 @@ function! easytags#define_tagkind(object) " {{{1 call add(s:tagkinds[a:object.filetype], a:object) endfunction -function! easytags#map_filetypes(vim_ft, ctags_ft) " {{{1 +function! easytags#map_filetypes(vim_ft, ctags_ft) " {{{2 call add(s:vim_filetypes, a:vim_ft) call add(s:ctags_filetypes, a:ctags_ft) endfunction -function! easytags#alias_filetypes(...) " {{{1 +function! easytags#alias_filetypes(...) " {{{2 for type in a:000 if !has_key(s:aliases, type) let s:aliases[type] = {} @@ -173,13 +221,13 @@ function! easytags#alias_filetypes(...) " {{{1 endfor endfunction -function! easytags#to_vim_ft(ctags_ft) " {{{1 +function! easytags#to_vim_ft(ctags_ft) " {{{2 let type = tolower(a:ctags_ft) let index = index(s:ctags_filetypes, type) return index >= 0 ? s:vim_filetypes[index] : type endfunction -function! easytags#to_ctags_ft(vim_ft) " {{{1 +function! easytags#to_ctags_ft(vim_ft) " {{{2 let type = tolower(a:vim_ft) let index = index(s:vim_filetypes, type) return index >= 0 ? s:ctags_filetypes[index] : type @@ -187,173 +235,165 @@ endfunction " Miscellaneous script-local functions. {{{1 -function! s:resolve(pathname) " {{{2 +function! s:resolve(filename) " {{{2 if g:easytags_resolve_links - return resolve(a:pathname) + return resolve(a:filename) else - return a:pathname + return a:filename endif endfunction function! s:cache_tagged_files() " {{{2 if !exists('s:tagged_files') let tagsfile = easytags#get_tagsfile() - call s:update_tagged_files(readfile(tagsfile)) + let [header, entries] = easytags#read_tagsfile(tagsfile) + call s:set_tagged_files(entries) endif endfunction -function! easytags#file_has_tags(pathname) " {{{2 - call s:cache_tagged_files() - return has_key(s:tagged_files, s:resolve(a:pathname)) -endfunction - -function! easytags#add_tagged_file(pathname) " {{{2 - call s:cache_tagged_files() - let pathname = s:resolve(a:pathname) - let s:tagged_files[pathname] = 1 -endfunction - -function! s:update_tagged_files(lines) " {{{2 - " Update the dictionary of +function! s:set_tagged_files(entries) " {{{2 let s:tagged_files = {} - for line in a:lines - if line !~ '^!_TAG_' - let pathname = matchstr(line, '^[^\t]\+\t\zs[^\t]\+') - if pathname != '' - let pathname = s:resolve(pathname) - let s:tagged_files[pathname] = 1 - endif + for entry in a:entries + let filename = matchstr(entry, '^[^\t]\+\t\zs[^\t]\+') + if filename != '' + let filename = s:resolve(filename) + let s:tagged_files[filename] = 1 endif endfor endfunction " Built-in file type & tag kind definitions. {{{1 -if !exists('s:tagkinds') +" Don't bother redefining everything below when this script is sourced again. +if exists('s:tagkinds') + finish +endif - let s:vim_filetypes = [] - let s:ctags_filetypes = [] - call easytags#map_filetypes('cpp', 'c++') - call easytags#map_filetypes('cs', 'c#') - call easytags#map_filetypes(exists('filetype_asp') ? filetype_asp : 'aspvbs', 'asp') +let s:tagkinds = {} - let s:aliases = {} - call easytags#alias_filetypes('c', 'cpp', 'objc', 'objcpp') +" Define the built-in Vim <=> Ctags file-type mappings. +let s:vim_filetypes = [] +let s:ctags_filetypes = [] +call easytags#map_filetypes('cpp', 'c++') +call easytags#map_filetypes('cs', 'c#') +call easytags#map_filetypes(exists('filetype_asp') ? filetype_asp : 'aspvbs', 'asp') - let s:tagkinds = {} +" Define the Vim file-types that are aliased by default. +let s:aliases = {} +call easytags#alias_filetypes('c', 'cpp', 'objc', 'objcpp') - " Enable line continuation. - let s:cpo_save = &cpo - set cpo&vim +" Enable line continuation. +let s:cpo_save = &cpo +set cpo&vim - " Lua. {{{2 +" Lua. {{{2 - call easytags#define_tagkind({ - \ 'filetype': 'lua', - \ 'hlgroup': 'luaFunc', - \ 'filter': 'get(v:val, "kind") ==# "f"'}) +call easytags#define_tagkind({ + \ 'filetype': 'lua', + \ 'hlgroup': 'luaFunc', + \ 'filter': 'get(v:val, "kind") ==# "f"'}) - " C. {{{2 +" C. {{{2 - call easytags#define_tagkind({ - \ 'filetype': 'c', - \ 'hlgroup': 'cType', - \ 'filter': 'get(v:val, "kind") =~# "[cgstu]"'}) +call easytags#define_tagkind({ + \ 'filetype': 'c', + \ 'hlgroup': 'cType', + \ 'filter': 'get(v:val, "kind") =~# "[cgstu]"'}) - call easytags#define_tagkind({ - \ 'filetype': 'c', - \ 'hlgroup': 'cPreProc', - \ 'filter': 'get(v:val, "kind") ==# "d"'}) +call easytags#define_tagkind({ + \ 'filetype': 'c', + \ 'hlgroup': 'cPreProc', + \ 'filter': 'get(v:val, "kind") ==# "d"'}) - call easytags#define_tagkind({ - \ 'filetype': 'c', - \ 'hlgroup': 'cFunction', - \ 'filter': 'get(v:val, "kind") =~# "[fp]"'}) +call easytags#define_tagkind({ + \ 'filetype': 'c', + \ 'hlgroup': 'cFunction', + \ 'filter': 'get(v:val, "kind") =~# "[fp]"'}) - highlight def link cFunction Function +highlight def link cFunction Function - " PHP. {{{2 +" PHP. {{{2 - call easytags#define_tagkind({ - \ 'filetype': 'php', - \ 'hlgroup': 'phpFunctions', - \ 'filter': 'get(v:val, "kind") ==# "f"'}) +call easytags#define_tagkind({ + \ 'filetype': 'php', + \ 'hlgroup': 'phpFunctions', + \ 'filter': 'get(v:val, "kind") ==# "f"'}) - call easytags#define_tagkind({ - \ 'filetype': 'php', - \ 'hlgroup': 'phpClasses', - \ 'filter': 'get(v:val, "kind") ==# "c"'}) +call easytags#define_tagkind({ + \ 'filetype': 'php', + \ 'hlgroup': 'phpClasses', + \ 'filter': 'get(v:val, "kind") ==# "c"'}) - " Vim script. {{{2 +" Vim script. {{{2 - call easytags#define_tagkind({ - \ 'filetype': 'vim', - \ 'hlgroup': 'vimAutoGroup', - \ 'filter': 'get(v:val, "kind") ==# "a"'}) +call easytags#define_tagkind({ + \ 'filetype': 'vim', + \ 'hlgroup': 'vimAutoGroup', + \ 'filter': 'get(v:val, "kind") ==# "a"'}) - highlight def link vimAutoGroup vimAutoEvent +highlight def link vimAutoGroup vimAutoEvent - call easytags#define_tagkind({ - \ 'filetype': 'vim', - \ 'hlgroup': 'vimCommand', - \ 'filter': 'get(v:val, "kind") ==# "c"', - \ 'pattern_prefix': '\(\(^\|\s\):\?\)\@<=', - \ 'pattern_suffix': '\(!\?\(\s\|$\)\)\@='}) +call easytags#define_tagkind({ + \ 'filetype': 'vim', + \ 'hlgroup': 'vimCommand', + \ 'filter': 'get(v:val, "kind") ==# "c"', + \ 'pattern_prefix': '\(\(^\|\s\):\?\)\@<=', + \ 'pattern_suffix': '\(!\?\(\s\|$\)\)\@='}) - " Exuberant Ctags doesn't mark script local functions in Vim scripts as - " "static". When your tags file contains search patterns this plug-in can use - " those search patterns to check which Vim script functions are defined - " globally and which script local. +" Exuberant Ctags doesn't mark script local functions in Vim scripts as +" "static". When your tags file contains search patterns this plug-in can use +" those search patterns to check which Vim script functions are defined +" globally and which script local. - call easytags#define_tagkind({ - \ 'filetype': 'vim', - \ 'hlgroup': 'vimFuncName', - \ 'filter': 'get(v:val, "kind") ==# "f" && get(v:val, "cmd") !~? ''<sid>\w\|\<s:\w''', - \ 'pattern_prefix': '\C\%(\<s:\|<[sS][iI][dD]>\)\@<!\<'}) +call easytags#define_tagkind({ + \ 'filetype': 'vim', + \ 'hlgroup': 'vimFuncName', + \ 'filter': 'get(v:val, "kind") ==# "f" && get(v:val, "cmd") !~? ''<sid>\w\|\<s:\w''', + \ 'pattern_prefix': '\C\%(\<s:\|<[sS][iI][dD]>\)\@<!\<'}) - call easytags#define_tagkind({ - \ 'filetype': 'vim', - \ 'hlgroup': 'vimScriptFuncName', - \ 'filter': 'get(v:val, "kind") ==# "f" && get(v:val, "cmd") =~? ''<sid>\w\|\<s:\w''', - \ 'pattern_prefix': '\C\%(\<s:\|<[sS][iI][dD]>\)'}) +call easytags#define_tagkind({ + \ 'filetype': 'vim', + \ 'hlgroup': 'vimScriptFuncName', + \ 'filter': 'get(v:val, "kind") ==# "f" && get(v:val, "cmd") =~? ''<sid>\w\|\<s:\w''', + \ 'pattern_prefix': '\C\%(\<s:\|<[sS][iI][dD]>\)'}) - highlight def link vimScriptFuncName vimFuncName +highlight def link vimScriptFuncName vimFuncName - " Python. {{{2 +" Python. {{{2 - call easytags#define_tagkind({ - \ 'filetype': 'python', - \ 'hlgroup': 'pythonFunction', - \ 'filter': 'get(v:val, "kind") ==# "f"', - \ 'pattern_prefix': '\%(\<def\s\+\)\@<!\<'}) +call easytags#define_tagkind({ + \ 'filetype': 'python', + \ 'hlgroup': 'pythonFunction', + \ 'filter': 'get(v:val, "kind") ==# "f"', + \ 'pattern_prefix': '\%(\<def\s\+\)\@<!\<'}) - call easytags#define_tagkind({ - \ 'filetype': 'python', - \ 'hlgroup': 'pythonMethod', - \ 'filter': 'get(v:val, "kind") ==# "m"', - \ 'pattern_prefix': '\.\@<='}) +call easytags#define_tagkind({ + \ 'filetype': 'python', + \ 'hlgroup': 'pythonMethod', + \ 'filter': 'get(v:val, "kind") ==# "m"', + \ 'pattern_prefix': '\.\@<='}) - highlight def link pythonMethodTag pythonFunction +highlight def link pythonMethodTag pythonFunction - " Java. {{{2 +" Java. {{{2 - call easytags#define_tagkind({ - \ 'filetype': 'java', - \ 'hlgroup': 'javaClass', - \ 'filter': 'get(v:val, "kind") ==# "c"'}) +call easytags#define_tagkind({ + \ 'filetype': 'java', + \ 'hlgroup': 'javaClass', + \ 'filter': 'get(v:val, "kind") ==# "c"'}) - call easytags#define_tagkind({ - \ 'filetype': 'java', - \ 'hlgroup': 'javaMethod', - \ 'filter': 'get(v:val, "kind") ==# "m"'}) +call easytags#define_tagkind({ + \ 'filetype': 'java', + \ 'hlgroup': 'javaMethod', + \ 'filter': 'get(v:val, "kind") ==# "m"'}) - highlight def link javaClass Identifier - highlight def link javaMethod Function +highlight def link javaClass Identifier +highlight def link javaMethod Function - " Restore "cpoptions". - let &cpo = s:cpo_save - unlet s:cpo_save +" }}} -endif +" Restore "cpoptions". +let &cpo = s:cpo_save +unlet s:cpo_save " vim: ts=2 sw=2 et diff --git a/easytags.vim b/easytags.vim index af4ea01..fc6ab77 100644 --- a/easytags.vim +++ b/easytags.vim @@ -1,10 +1,10 @@ " Vim plug-in " Maintainer: Peter Odding <peter@peterodding.com> -" Last Change: June 11, 2010 +" Last Change: June 13, 2010 " URL: http://peterodding.com/code/vim/easytags " Requires: Exuberant Ctags (http://ctags.sf.net) " License: MIT -" Version: 1.8 +" Version: 1.9 " Support for automatic update using the GLVS plug-in. " GetLatestVimScripts: 3114 1 :AutoInstall: easytags.zip |