aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Odding <peter@peterodding.com>2010-06-13 02:02:42 +0200
committerPeter Odding <peter@peterodding.com>2010-06-13 02:02:42 +0200
commitad3bd15a76acaeb8bd5c92e104ab95a7b55f6fee (patch)
tree563aae675432b6556ad00de5c6d5e50a327bd963
parentdcbed282e236484adfd7bca593f8fc2bb0503e35 (diff)
downloadvim-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.vim358
-rw-r--r--easytags.vim4
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