aboutsummaryrefslogtreecommitdiffstats
path: root/autoload
diff options
context:
space:
mode:
Diffstat (limited to 'autoload')
-rw-r--r--autoload/xolox/easytags.vim172
-rw-r--r--autoload/xolox/misc/README.md33
-rw-r--r--autoload/xolox/misc/buffer.vim42
-rw-r--r--autoload/xolox/misc/compat.vim23
-rw-r--r--autoload/xolox/misc/path.vim11
5 files changed, 213 insertions, 68 deletions
diff --git a/autoload/xolox/easytags.vim b/autoload/xolox/easytags.vim
index 9ddea30..458e270 100644
--- a/autoload/xolox/easytags.vim
+++ b/autoload/xolox/easytags.vim
@@ -1,9 +1,11 @@
" Vim script
" Author: Peter Odding <peter@peterodding.com>
-" Last Change: January 15, 2012
+" Last Change: April 21, 2013
" URL: http://peterodding.com/code/vim/easytags/
-let g:xolox#easytags#version = '2.8.1'
+let g:xolox#easytags#version = '3.1.5'
+
+call xolox#misc#compat#check('easytags', 1)
" Public interface through (automatic) commands. {{{1
@@ -34,24 +36,31 @@ function! xolox#easytags#register(global) " {{{2
endif
endfunction
+" The localtime() when the CursorHold event last fired.
+let s:last_automatic_run = 0
+
function! xolox#easytags#autoload(event) " {{{2
try
if a:event =~? 'cursorhold'
" Only for the CursorHold automatic command: check for unreasonable
" &updatetime values. The minimum value 4000 is kind of arbitrary
- " (apart from being Vim's default) so I made it configurable:
+ " (apart from being Vim's default) so I made it configurable.
let updatetime_min = xolox#misc#option#get('easytags_updatetime_min', 4000)
if &updatetime < updatetime_min
- " Other plug-ins may lower &updatetime in certain contexts, e.g.
- " insert mode in the case of the neocomplcache plug-in. The following
- " option (disabled by default unless neocomplcache is loaded) silences
- " the warning and makes the easytags plug-in skip the update and
- " highlight. When the &updatetime is restored to a reasonable value
- " the plug-in resumes.
- if xolox#misc#option#get('easytags_updatetime_autodisable', exists('g:loaded_neocomplcache'))
- return
+ if s:last_automatic_run == 0
+ " Warn once about the low &updatetime value.
+ call xolox#misc#msg#warn("easytags.vim %s: The 'updatetime' option has an unreasonably low value, so I'll start compensating (see the easytags_updatetime_min option).", g:xolox#easytags#version)
+ let s:last_automatic_run = localtime()
else
- call xolox#misc#msg#warn("easytags.vim %s: I'm being executed every %i milliseconds! Please :set updatetime=%i. To find where 'updatetime' was changed execute ':verb set ut?'", g:xolox#easytags#version, &updatetime, updatetime_min)
+ let next_scheduled_run = s:last_automatic_run + max([1, updatetime_min / 1000])
+ if localtime() < next_scheduled_run
+ " It's not our time yet; wait for the next event.
+ call xolox#misc#msg#debug("easytags.vim %s: Skipping this beat of 'updatetime' to compensate for low value.", g:xolox#easytags#version)
+ return
+ else
+ call xolox#misc#msg#debug("easytags.vim %s: This is our beat of 'updatetime'!", g:xolox#easytags#version)
+ let s:last_automatic_run = localtime()
+ endif
endif
endif
endif
@@ -99,8 +108,11 @@ function! xolox#easytags#update(silent, filter_tags, filenames) " {{{2
let tagsfile = xolox#easytags#get_tagsfile()
let firstrun = !filereadable(tagsfile)
let cmdline = s:prep_cmdline(cfile, tagsfile, firstrun, a:filenames, context)
- let output = s:run_ctags(starttime, cfile, tagsfile, firstrun, cmdline)
+ let [output, has_updates] = s:run_ctags(starttime, cfile, tagsfile, firstrun, cmdline)
if !firstrun
+ if !has_updates
+ return 1
+ endif
if have_args && !empty(g:easytags_by_filetype)
" TODO Get the headers from somewhere?!
call s:save_by_filetype(a:filter_tags, [], output, context)
@@ -120,7 +132,7 @@ function! xolox#easytags#update(silent, filter_tags, filenames) " {{{2
endif
" When :UpdateTags was executed manually we'll refresh the dynamic
" syntax highlighting so that new tags are immediately visible.
- if !a:silent
+ if !a:silent && xolox#misc#option#get('easytags_auto_highlight', 1)
HighlightTags
endif
return 1
@@ -157,28 +169,47 @@ function! s:check_cfile(silent, filter_tags, have_args) " {{{3
endfunction
function! s:prep_cmdline(cfile, tagsfile, firstrun, arguments, context) " {{{3
- let program = xolox#misc#option#get('easytags_cmd')
- let cmdline = [program, '--fields=+l', '--c-kinds=+p', '--c++-kinds=+p']
- if a:firstrun
- call add(cmdline, xolox#misc#escape#shell('-f' . a:tagsfile))
- call add(cmdline, '--sort=' . (&ic ? 'foldcase' : 'yes'))
+ let languages = xolox#misc#option#get('easytags_languages', {})
+ let ctags_language_name = xolox#easytags#to_ctags_ft(&filetype)
+ let language = get(languages, ctags_language_name, {})
+ if empty(language)
+ let program = xolox#misc#option#get('easytags_cmd')
+ let cmdline = [program, '--fields=+l', '--c-kinds=+p', '--c++-kinds=+p']
+ if a:firstrun
+ call add(cmdline, xolox#misc#escape#shell('-f' . a:tagsfile))
+ call add(cmdline, '--sort=' . (&ic ? 'foldcase' : 'yes'))
+ else
+ call add(cmdline, '--sort=no')
+ call add(cmdline, '-f-')
+ endif
+ if xolox#misc#option#get('easytags_include_members', 0)
+ call add(cmdline, '--extra=+q')
+ endif
else
- call add(cmdline, '--sort=no')
- call add(cmdline, '-f-')
- endif
- if xolox#misc#option#get('easytags_include_members', 0)
- call add(cmdline, '--extra=+q')
+ let program = get(language, 'cmd', xolox#misc#option#get('easytags_cmd'))
+ if empty(program)
+ call xolox#misc#msg#warn("easytags.vim %s: No 'cmd' defined for language '%s', and also no global default!", g:xolox#easytags#version, ctags_language_name)
+ return
+ endif
+ let cmdline = [program] + get(language, 'args', [])
+ if a:firstrun
+ call add(cmdline, xolox#misc#escape#shell(get(language, 'fileoutput_opt', '-f') . a:tagsfile))
+ else
+ call add(cmdline, xolox#misc#escape#shell(get(language, 'stdout_opt', '-f-')))
+ endif
endif
let have_args = 0
if a:cfile != ''
if xolox#misc#option#get('easytags_autorecurse', 0)
- call add(cmdline, '-R')
+ call add(cmdline, empty(language) ? '-R' : xolox#misc#escape#shell(get(language, 'recurse_flag', '-R')))
call add(cmdline, xolox#misc#escape#shell(a:cfile))
else
- " TODO Should --language-force distinguish between C and C++?
- " TODO --language-force doesn't make sense for JavaScript tags in HTML files?
- let filetype = xolox#easytags#to_ctags_ft(&filetype)
- call add(cmdline, xolox#misc#escape#shell('--language-force=' . filetype))
+ if empty(language)
+ " TODO Should --language-force distinguish between C and C++?
+ " TODO --language-force doesn't make sense for JavaScript tags in HTML files?
+ let filetype = xolox#easytags#to_ctags_ft(&filetype)
+ call add(cmdline, xolox#misc#escape#shell('--language-force=' . filetype))
+ endif
call add(cmdline, xolox#misc#escape#shell(a:cfile))
endif
let have_args = 1
@@ -203,10 +234,12 @@ endfunction
function! s:run_ctags(starttime, cfile, tagsfile, firstrun, cmdline) " {{{3
let lines = []
+ let has_updates = 1
if a:cmdline != ''
call xolox#misc#msg#debug("easytags.vim %s: Executing %s.", g:xolox#easytags#version, a:cmdline)
try
let lines = xolox#shell#execute(a:cmdline, 1)
+ let has_updates = a:firstrun || s:has_updates(a:cfile, join(lines, "\n"))
catch /^Vim\%((\a\+)\)\=:E117/
" Ignore missing shell.vim plug-in.
let output = system(a:cmdline)
@@ -215,6 +248,7 @@ function! s:run_ctags(starttime, cfile, tagsfile, firstrun, cmdline) " {{{3
throw printf(msg, fnamemodify(a:tagsfile, ':~'), strtrans(output))
endif
let lines = split(output, "\n")
+ let has_updates = a:firstrun || s:has_updates(a:cfile, output)
endtry
if a:firstrun
if a:cfile != ''
@@ -222,12 +256,50 @@ function! s:run_ctags(starttime, cfile, tagsfile, firstrun, cmdline) " {{{3
else
call xolox#misc#timer#stop("easytags.vim %s: Created tags in %s.", g:xolox#easytags#version, a:starttime)
endif
- return []
+ return [[], 0]
endif
endif
- return xolox#easytags#parse_entries(lines)
+ return [xolox#easytags#parse_entries(lines), has_updates]
endfunction
+" Vim 7.3 now has the sha256() function. We use it below to recognize when the
+" tags haven't changed from the last time we ran Exuberant Ctags on a file; in
+" this case the tags file doesn't have to be written to disk which makes the
+" plug-in much faster for a very common case.
+
+let s:fingerprints = {}
+
+function! s:has_updates(cfile, output)
+ if empty(a:cfile)
+ " The cache doesn't work when tags aren't created for the current file.
+ return 1
+ endif
+ let fingerprint = s:get_fingerprint(a:cfile, a:output)
+ call xolox#misc#msg#debug("easytags.vim %s: Fingerprint of tags in %s is %s.", g:xolox#easytags#version, a:cfile, string(fingerprint))
+ if !empty(fingerprint) && get(s:fingerprints, a:cfile, '') ==# fingerprint
+ call xolox#misc#msg#debug("easytags.vim %s: The fingerprint didn't change! We can take a shortcut :-)", g:xolox#easytags#version)
+ return 0
+ endif
+ let s:fingerprints[a:cfile] = fingerprint
+ return 1
+endfunction
+
+if exists('*sha256')
+ function! s:get_fingerprint(cfile, output)
+ return sha256(a:output)
+ endfunction
+else
+ function! s:get_fingerprint(cfile, output)
+ " Don't want to re-implement a costly hashing function in Vimscript. Just
+ " handle files that never had any tags.
+ if empty(a:output)
+ return get(s:fingerprints, a:cfile, 1)
+ else
+ return ''
+ endif
+ endfunction
+endif
+
function! s:filter_merge_tags(filter_tags, tagsfile, output, context) " {{{3
let [headers, entries] = xolox#easytags#read_tagsfile(a:tagsfile)
let filters = []
@@ -246,13 +318,14 @@ function! s:filter_merge_tags(filter_tags, tagsfile, output, context) " {{{3
call filter(entries, join(filters, ' && '))
endif
let num_filtered = num_old_entries - len(entries)
- " Merge old/new tags.
+ " Merge the old and new tags.
call extend(entries, a:output)
- " We've already read the tags file, cache the tagged files before the entries
- " get flattened by the write.
+ " Since we've already read the tags file we might as well cache the tagged
+ " files. We do so before saving the tags file so that the items in {entries}
+ " are not yet flattened by xolox#easytags#write_tagsfile().
let fname = s:canonicalize(a:tagsfile, a:context)
call s:cache_tagged_files_in(fname, getftime(fname), entries, a:context)
- " And write tags file.
+ " Now we're ready to save the tags file.
if !xolox#easytags#write_tagsfile(a:tagsfile, headers, entries)
let msg = "Failed to write filtered tags file %s!"
throw printf(msg, fnamemodify(a:tagsfile, ':~'))
@@ -416,18 +489,21 @@ endfunction
function! xolox#easytags#supported_filetypes() " {{{2
if !exists('s:supported_filetypes')
let starttime = xolox#misc#timer#start()
- let command = g:easytags_cmd . ' --list-languages'
- try
- let listing = xolox#shell#execute(command, 1)
- catch /^Vim\%((\a\+)\)\=:E117/
- " Ignore missing shell.vim plug-in.
- let listing = split(system(command), "\n")
- if v:shell_error
- let msg = "Failed to get supported languages! (output: %s)"
- throw printf(msg, strtrans(join(listing, "\n")))
- endif
- endtry
- let s:supported_filetypes = map(copy(listing), 's:check_filetype(listing, v:val)')
+ let listing = []
+ if !empty(g:easytags_cmd)
+ let command = g:easytags_cmd . ' --list-languages'
+ try
+ let listing = xolox#shell#execute(command, 1)
+ catch /^Vim\%((\a\+)\)\=:E117/
+ " Ignore missing shell.vim plug-in.
+ let listing = split(system(command), "\n")
+ if v:shell_error
+ let msg = "Failed to get supported languages! (output: %s)"
+ throw printf(msg, strtrans(join(listing, "\n")))
+ endif
+ endtry
+ endif
+ let s:supported_filetypes = map(copy(listing) + keys(xolox#misc#option#get('easytags_languages', {})), 's:check_filetype(listing, v:val)')
let msg = "easytags.vim %s: Retrieved %i supported languages in %s."
call xolox#misc#timer#stop(msg, g:xolox#easytags#version, len(s:supported_filetypes), starttime)
endif
@@ -925,7 +1001,7 @@ call xolox#easytags#define_tagkind({
\ 'filetype': 'sh',
\ 'hlgroup': 'shFunctionTag',
\ 'tagkinds': 'f',
- \ 'pattern_suffix': '\(\s*()\)\@!'})
+ \ 'pattern_suffix': '\(\w\|\s*()\)\@!'})
highlight def link shFunctionTag Operator
diff --git a/autoload/xolox/misc/README.md b/autoload/xolox/misc/README.md
index 9111126..f375fe6 100644
--- a/autoload/xolox/misc/README.md
+++ b/autoload/xolox/misc/README.md
@@ -1,24 +1,49 @@
# Miscellaneous auto-load Vim scripts
-The git repository at <http://github.com/xolox/vim-misc> contains Vim scripts that are used by most of the [Vim plug-ins I've written] [plugins] yet don't really belong with any single one. I include this repository as a subdirectory of my plug-in repositories using the following commands:
+The git repository at [github.com/xolox/vim-misc] [repository] contains Vim scripts that are used by most of the [Vim plug-ins I've written] [plugins] yet don't really belong with any single one. I include this repository as a subdirectory of my plug-in repositories using the following commands:
$ git remote add -f vim-misc https://github.com/xolox/vim-misc.git
$ git merge -s ours --no-commit vim-misc/master
$ git read-tree --prefix=autoload/xolox/misc/ -u vim-misc/master
$ git commit -m "Merge vim-misc repository as subdirectory"
-To update a plug-in repository to the latest versions of the miscellaneous auto-load scripts I execute the following command:
+The above trick is called the [subtree merge strategy] [merge-strategy]. To update a plug-in repository to the latest version of the miscellaneous auto-load scripts I execute the following command:
$ git pull -s subtree vim-misc master
+## Why make things so complex?
+
+I came up with this solution after multiple years of back and forth between Vim Online users, the GitHub crowd and my own sanity:
+
+1. When I started publishing my first Vim plug-ins I would prepare ZIP archives for Vim Online using makefiles. The makefiles would make sure the miscellaneous scripts were included in the uploaded distributions. This had two disadvantages: It lost git history and the repositories on GitHub were not usable out of the box, so [I got complaints from GitHub (Pathogen) users] [github-complaints].
+
+2. My second attempt to solve the problem used git submodules which seemed like the ideal solution until I actually started doing it. Submodules are not initialized during a normal `git clone`, you need to use `git clone --recursive` instead but Vim plug-in managers like [Pathogen] [pathogen] and [Vundle] [vundle] don't do this (at least [they didn't when I tried] [vundle-discussion]) so people would end up with broken checkouts.
+
+3. After finding out that git submodules were not going to solve my problems I searched for other inclusion strategies supported by git. After a while I came upon the [subtree merge strategy] [merge-strategy] which I have been using for more than two years now.
+
+## Compatibility issues
+
+Regardless of the inclusion strategies discussed above, my current scheme has a flaw: If more than one of my plug-ins are installed in a Vim profile using [Pathogen] [pathogen] or [Vundle] [vundle], the miscellaneous autoload scripts will all be loaded from the subdirectory of one single plug-in.
+
+This means that when I break compatibility in the miscellaneous scripts, I have to make sure to merge the changes into all of my plug-ins. Even then, if a user has more than one of my plug-ins installed but updates only one of them, the other plug-ins (that are not yet up to date) can break (because of the backwards incompatible change).
+
+The `xolox#misc#compat#check()` function makes sure that incompatibilities are detected early so that the user knows which plug-in to update if incompatibilities arise.
+
## Contact
If you have questions, bug reports, suggestions, etc. the author can be contacted at <peter@peterodding.com>. The latest version is available at <http://peterodding.com/code/vim/misc> and <http://github.com/xolox/vim-misc>.
## License
-This software is licensed under the [MIT license](http://en.wikipedia.org/wiki/MIT_License).
-© 2011 Peter Odding &lt;<peter@peterodding.com>&gt;.
+This software is licensed under the [MIT license] [mit].
+© 2013 Peter Odding &lt;<peter@peterodding.com>&gt;.
+[github-complaints]: https://github.com/xolox/vim-easytags/issues/1
+[merge-strategy]: http://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html
+[mit]: http://en.wikipedia.org/wiki/MIT_License
+[pathogen]: http://www.vim.org/scripts/script.php?script_id=2332
[plugins]: http://peterodding.com/code/vim/
+[repository]: https://github.com/xolox/vim-misc
+[vundle-discussion]: https://github.com/gmarik/vundle/pull/41
+[vundle]: https://github.com/gmarik/vundle
diff --git a/autoload/xolox/misc/buffer.vim b/autoload/xolox/misc/buffer.vim
index e4472e6..3597cc2 100644
--- a/autoload/xolox/misc/buffer.vim
+++ b/autoload/xolox/misc/buffer.vim
@@ -1,37 +1,51 @@
" Vim auto-load script
" Author: Peter Odding <peter@peterodding.com>
-" Last Change: September 4, 2011
+" Last Change: April 18, 2013
" URL: http://peterodding.com/code/vim/misc/
-function! xolox#misc#buffer#is_empty()
+function! xolox#misc#buffer#is_empty() " {{{1
" Check if the current buffer is an empty, unchanged buffer which can be reused.
return !&modified && expand('%') == '' && line('$') <= 1 && getline(1) == ''
endfunction
-function! xolox#misc#buffer#prepare(bufname)
- let bufname = '[' . a:bufname . ']'
- let buffers = tabpagebuflist()
- call map(buffers, 'fnamemodify(bufname(v:val), ":t:r")')
- let idx = index(buffers, bufname)
- if idx >= 0
- execute (idx + 1) . 'wincmd w'
- elseif !(xolox#misc#buffer#is_empty() || expand('%:t') == bufname)
+function! xolox#misc#buffer#prepare(...) " {{{1
+ " Open a special buffer (with generated contents, not directly edited by the user).
+ if a:0 == 1 && type(a:1) == type('')
+ " Backwards compatibility with old interface.
+ let options = {'name': a:1, 'path': a:1}
+ elseif type(a:1) == type({})
+ let options = a:1
+ else
+ throw "Invalid arguments"
+ endif
+ let winnr = 1
+ let found = 0
+ for bufnr in tabpagebuflist()
+ if xolox#misc#path#equals(options['path'], bufname(bufnr))
+ execute winnr . 'wincmd w'
+ let found = 1
+ break
+ else
+ let winnr += 1
+ endif
+ endfor
+ if !(found || xolox#misc#buffer#is_empty())
vsplit
endif
- silent execute 'edit' fnameescape(bufname)
+ silent execute 'edit' fnameescape(options['path'])
lcd " clear working directory
setlocal buftype=nofile bufhidden=hide noswapfile
- let &l:statusline = bufname
+ let &l:statusline = '[' . options['name'] . ']'
call xolox#misc#buffer#unlock()
silent %delete
endfunction
-function! xolox#misc#buffer#lock()
+function! xolox#misc#buffer#lock() " {{{1
" Lock a special buffer so it can no longer be edited.
setlocal readonly nomodifiable nomodified
endfunction
-function! xolox#misc#buffer#unlock()
+function! xolox#misc#buffer#unlock() " {{{1
" Unlock a special buffer so that its content can be updated.
setlocal noreadonly modifiable
endfunction
diff --git a/autoload/xolox/misc/compat.vim b/autoload/xolox/misc/compat.vim
new file mode 100644
index 0000000..83d00a0
--- /dev/null
+++ b/autoload/xolox/misc/compat.vim
@@ -0,0 +1,23 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: April 20, 2013
+" URL: http://peterodding.com/code/vim/misc/
+
+" The following integer will be bumped whenever a change in the miscellaneous
+" scripts breaks backwards compatibility. This enables my Vim plug-ins to fail
+" early when they detect an incompatible version, instead of breaking at the
+" worst possible moments :-).
+let g:xolox#misc#compat#version = 1
+
+" Remember the directory where the miscellaneous scripts are loaded from
+" so the user knows which plug-in to update if incompatibilities arise.
+let s:misc_directory = fnamemodify(expand('<sfile>'), ':p:h')
+
+function! xolox#misc#compat#check(plugin_name, required_version)
+ if a:required_version != g:xolox#misc#compat#version
+ let msg = "The %s plug-in requires version %i of the miscellaneous scripts, however version %i was loaded from %s!"
+ throw printf(msg, a:plugin_name, a:required_version, g:xolox#misc#compat#version, s:misc_directory)
+ endif
+endfunction
+
+" vim: ts=2 sw=2 et
diff --git a/autoload/xolox/misc/path.vim b/autoload/xolox/misc/path.vim
index efb6340..6f8fe44 100644
--- a/autoload/xolox/misc/path.vim
+++ b/autoload/xolox/misc/path.vim
@@ -1,9 +1,10 @@
" Vim auto-load script
" Author: Peter Odding <peter@peterodding.com>
-" Last Change: September 26, 2011
+" Last Change: April 18, 2013
" URL: http://peterodding.com/code/vim/misc/
let s:windows_compatible = has('win32') || has('win64')
+let s:mac_os_x_compatible = has('macunix')
function! xolox#misc#path#which(...)
let extensions = s:windows_compatible ? split($PATHEXT, ';') : ['']
@@ -129,7 +130,13 @@ endfunction
" Encode a pathname so it can be used as a filename.
function! xolox#misc#path#encode(path)
- let mask = s:windows_compatible ? '[*|\\/:"<>?%]' : '[\\/%]'
+ if s:windows_compatible
+ let mask = '[*|\\/:"<>?%]'
+ elseif s:mac_os_x_compatible
+ let mask = '[\\/%:]'
+ else
+ let mask = '[\\/%]'
+ endif
return substitute(a:path, mask, '\=printf("%%%x", char2nr(submatch(0)))', 'g')
endfunction