From 615dbc99fc60c08aa7993872e71a61b5f35e5017 Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Thu, 23 May 2013 20:08:26 +0200 Subject: Release 3.3.5 --- autoload/xolox/easytags.vim | 152 ++++++++--------- autoload/xolox/easytags/misc/buffer.vim | 86 ++++++++++ autoload/xolox/easytags/misc/complete.vim | 28 ++++ autoload/xolox/easytags/misc/escape.vim | 62 +++++++ autoload/xolox/easytags/misc/list.vim | 63 +++++++ autoload/xolox/easytags/misc/msg.vim | 97 +++++++++++ autoload/xolox/easytags/misc/open.vim | 98 +++++++++++ autoload/xolox/easytags/misc/option.vim | 121 ++++++++++++++ autoload/xolox/easytags/misc/os.vim | 194 ++++++++++++++++++++++ autoload/xolox/easytags/misc/path.vim | 262 ++++++++++++++++++++++++++++++ autoload/xolox/easytags/misc/str.vim | 24 +++ autoload/xolox/easytags/misc/timer.vim | 109 +++++++++++++ plugin/easytags.vim | 16 +- 13 files changed, 1234 insertions(+), 78 deletions(-) create mode 100644 autoload/xolox/easytags/misc/buffer.vim create mode 100644 autoload/xolox/easytags/misc/complete.vim create mode 100644 autoload/xolox/easytags/misc/escape.vim create mode 100644 autoload/xolox/easytags/misc/list.vim create mode 100644 autoload/xolox/easytags/misc/msg.vim create mode 100644 autoload/xolox/easytags/misc/open.vim create mode 100644 autoload/xolox/easytags/misc/option.vim create mode 100644 autoload/xolox/easytags/misc/os.vim create mode 100644 autoload/xolox/easytags/misc/path.vim create mode 100644 autoload/xolox/easytags/misc/str.vim create mode 100644 autoload/xolox/easytags/misc/timer.vim diff --git a/autoload/xolox/easytags.vim b/autoload/xolox/easytags.vim index 1372f2c..90c495b 100644 --- a/autoload/xolox/easytags.vim +++ b/autoload/xolox/easytags.vim @@ -1,3 +1,9 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + " Vim script " Author: Peter Odding " Last Change: May 23, 2013 @@ -10,11 +16,11 @@ let g:xolox#easytags#version = '3.3.5' function! xolox#easytags#register(global) " {{{2 " Parse the &tags option and get a list of all tags files *including " non-existing files* (this is why we can't just call tagfiles()). - let tagfiles = xolox#misc#option#split_tags(&tags) + let tagfiles = xolox#easytags#misc#option#split_tags(&tags) let expanded = map(copy(tagfiles), 'resolve(expand(v:val))') " Add the filename to the &tags option when the user hasn't done so already. let tagsfile = a:global ? g:easytags_file : xolox#easytags#get_tagsfile() - if index(expanded, xolox#misc#path#absolute(tagsfile)) == -1 + if index(expanded, xolox#easytags#misc#path#absolute(tagsfile)) == -1 " This is a real mess because of bugs in Vim?! :let &tags = '...' doesn't " work on UNIX and Windows, :set tags=... doesn't work on Windows. What I " mean with "doesn't work" is that tagfiles() == [] after the :let/:set @@ -23,9 +29,9 @@ function! xolox#easytags#register(global) " {{{2 " . Now you entered the exact same value that the code below also did " but suddenly Vim sees the tags file and tagfiles() != [] :-S call add(tagfiles, tagsfile) - let value = xolox#misc#option#join_tags(tagfiles) + let value = xolox#easytags#misc#option#join_tags(tagfiles) let cmd = (a:global ? 'set' : 'setl') . ' tags=' . escape(value, '\ ') - if xolox#misc#os#is_win() && v:version < 703 + if xolox#easytags#misc#os#is_win() && v:version < 703 " TODO How to clear the expression from Vim's status line? call feedkeys(":" . cmd . "|let &ro=&ro\", 'n') else @@ -39,8 +45,8 @@ let s:last_automatic_run = 0 function! xolox#easytags#autoload(event) " {{{2 try - let do_update = xolox#misc#option#get('easytags_auto_update', 1) - let do_highlight = xolox#misc#option#get('easytags_auto_highlight', 1) && &eventignore !~? '\' + let do_update = xolox#easytags#misc#option#get('easytags_auto_update', 1) + let do_highlight = xolox#easytags#misc#option#get('easytags_auto_highlight', 1) && &eventignore !~? '\' " Don't execute this function for unsupported file types (doesn't load " the list of file types if updates and highlighting are both disabled). if (do_update || do_highlight) && !empty(xolox#easytags#select_supported_filetypes(&ft)) @@ -48,23 +54,23 @@ function! xolox#easytags#autoload(event) " {{{2 " 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. - let updatetime_min = xolox#misc#option#get('easytags_updatetime_min', 4000) + let updatetime_min = xolox#easytags#misc#option#get('easytags_updatetime_min', 4000) if &updatetime < updatetime_min if s:last_automatic_run == 0 " Warn once about the low &updatetime value? - if xolox#misc#option#get('easytags_updatetime_warn', 1) - 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) + if xolox#easytags#misc#option#get('easytags_updatetime_warn', 1) + call xolox#easytags#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) endif let s:last_automatic_run = localtime() else 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) + call xolox#easytags#misc#msg#debug("easytags.vim %s: Skipping this beat of 'updatetime' to compensate for low value.", g:xolox#easytags#version) " Shortcut to break out of xolox#easytags#autoload(). return else - call xolox#misc#msg#debug("easytags.vim %s: This is our beat of 'updatetime'!", g:xolox#easytags#version) + call xolox#easytags#misc#msg#debug("easytags.vim %s: This is our beat of 'updatetime'!", g:xolox#easytags#version) let s:last_automatic_run = localtime() endif endif @@ -96,7 +102,7 @@ function! xolox#easytags#autoload(event) " {{{2 endif endif catch - call xolox#misc#msg#warn("easytags.vim %s: %s (at %s)", g:xolox#easytags#version, v:exception, v:throwpoint) + call xolox#easytags#misc#msg#warn("easytags.vim %s: %s (at %s)", g:xolox#easytags#version, v:exception, v:throwpoint) endtry endfunction @@ -104,7 +110,7 @@ function! xolox#easytags#update(silent, filter_tags, filenames) " {{{2 try let context = s:create_context() let have_args = !empty(a:filenames) - let starttime = xolox#misc#timer#start() + let starttime = xolox#easytags#misc#timer#start() let cfile = s:check_cfile(a:silent, a:filter_tags, have_args) let tagsfile = xolox#easytags#get_tagsfile() let firstrun = !filereadable(tagsfile) @@ -122,23 +128,23 @@ function! xolox#easytags#update(silent, filter_tags, filenames) " {{{2 endif if cfile != '' let msg = "easytags.vim %s: Updated tags for %s in %s." - call xolox#misc#timer#stop(msg, g:xolox#easytags#version, expand('%:p:~'), starttime) + call xolox#easytags#misc#timer#stop(msg, g:xolox#easytags#version, expand('%:p:~'), starttime) elseif have_args let msg = "easytags.vim %s: Updated tags in %s." - call xolox#misc#timer#stop(msg, g:xolox#easytags#version, starttime) + call xolox#easytags#misc#timer#stop(msg, g:xolox#easytags#version, starttime) else let msg = "easytags.vim %s: Filtered %i invalid tags in %s." - call xolox#misc#timer#stop(msg, g:xolox#easytags#version, num_filtered, starttime) + call xolox#easytags#misc#timer#stop(msg, g:xolox#easytags#version, num_filtered, starttime) endif endif " When :UpdateTags was executed manually we'll refresh the dynamic " syntax highlighting so that new tags are immediately visible. - if !a:silent && xolox#misc#option#get('easytags_auto_highlight', 1) + if !a:silent && xolox#easytags#misc#option#get('easytags_auto_highlight', 1) HighlightTags endif return 1 catch - call xolox#misc#msg#warn("easytags.vim %s: %s (at %s)", g:xolox#easytags#version, v:exception, v:throwpoint) + call xolox#easytags#misc#msg#warn("easytags.vim %s: %s (at %s)", g:xolox#easytags#version, v:exception, v:throwpoint) endtry endfunction @@ -147,7 +153,7 @@ function! s:check_cfile(silent, filter_tags, have_args) " {{{3 return '' endif let silent = a:silent || a:filter_tags - if xolox#misc#option#get('easytags_autorecurse', 0) + if xolox#easytags#misc#option#get('easytags_autorecurse', 0) let cdir = s:resolve(expand('%:p:h')) if !isdirectory(cdir) if silent | return '' | endif @@ -170,49 +176,49 @@ function! s:check_cfile(silent, filter_tags, have_args) " {{{3 endfunction function! s:prep_cmdline(cfile, tagsfile, firstrun, arguments, context) " {{{3 - let languages = xolox#misc#option#get('easytags_languages', {}) + let languages = xolox#easytags#misc#option#get('easytags_languages', {}) let applicable_filetypes = xolox#easytags#select_supported_filetypes(&ft) let ctags_language_name = xolox#easytags#to_ctags_ft(applicable_filetypes[0]) let language = get(languages, ctags_language_name, {}) if empty(language) - let program = xolox#misc#option#get('easytags_cmd') + let program = xolox#easytags#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, xolox#easytags#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) + if xolox#easytags#misc#option#get('easytags_include_members', 0) call add(cmdline, '--extra=+q') endif else - let program = get(language, 'cmd', xolox#misc#option#get('easytags_cmd')) + let program = get(language, 'cmd', xolox#easytags#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) + call xolox#easytags#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)) + call add(cmdline, xolox#easytags#misc#escape#shell(get(language, 'fileoutput_opt', '-f') . a:tagsfile)) else - call add(cmdline, xolox#misc#escape#shell(get(language, 'stdout_opt', '-f-'))) + call add(cmdline, xolox#easytags#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, empty(language) ? '-R' : xolox#misc#escape#shell(get(language, 'recurse_flag', '-R'))) - call add(cmdline, xolox#misc#escape#shell(a:cfile)) + if xolox#easytags#misc#option#get('easytags_autorecurse', 0) + call add(cmdline, empty(language) ? '-R' : xolox#easytags#misc#escape#shell(get(language, 'recurse_flag', '-R'))) + call add(cmdline, xolox#easytags#misc#escape#shell(a:cfile)) else 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(applicable_filetypes[0]) - call add(cmdline, xolox#misc#escape#shell('--language-force=' . filetype)) + call add(cmdline, xolox#easytags#misc#escape#shell('--language-force=' . filetype)) endif - call add(cmdline, xolox#misc#escape#shell(a:cfile)) + call add(cmdline, xolox#easytags#misc#escape#shell(a:cfile)) endif let have_args = 1 else @@ -223,7 +229,7 @@ function! s:prep_cmdline(cfile, tagsfile, firstrun, arguments, context) " {{{3 else let matches = split(expand(arg), "\n") if !empty(matches) - call map(matches, 'xolox#misc#escape#shell(s:canonicalize(v:val, a:context))') + call map(matches, 'xolox#easytags#misc#escape#shell(s:canonicalize(v:val, a:context))') call extend(cmdline, matches) let have_args = 1 endif @@ -238,14 +244,14 @@ 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) - let lines = xolox#misc#os#exec({'command': a:cmdline})['stdout'] + call xolox#easytags#misc#msg#debug("easytags.vim %s: Executing %s.", g:xolox#easytags#version, a:cmdline) + let lines = xolox#easytags#misc#os#exec({'command': a:cmdline})['stdout'] let has_updates = a:firstrun || s:has_updates(a:cfile, join(lines, "\n")) if a:firstrun if a:cfile != '' - call xolox#misc#timer#stop("easytags.vim %s: Created tags for %s in %s.", g:xolox#easytags#version, expand('%:p:~'), a:starttime) + call xolox#easytags#misc#timer#stop("easytags.vim %s: Created tags for %s in %s.", g:xolox#easytags#version, expand('%:p:~'), a:starttime) else - call xolox#misc#timer#stop("easytags.vim %s: Created tags in %s.", g:xolox#easytags#version, a:starttime) + call xolox#easytags#misc#timer#stop("easytags.vim %s: Created tags in %s.", g:xolox#easytags#version, a:starttime) endif return [[], 0] endif @@ -266,9 +272,9 @@ function! s:has_updates(cfile, output) 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)) + call xolox#easytags#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) + call xolox#easytags#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 @@ -344,7 +350,7 @@ function! xolox#easytags#highlight() " {{{2 let filetype = get(s:canonical_aliases, &ft, &ft) let tagkinds = get(s:tagkinds, filetype, []) if exists('g:syntax_on') && !empty(tagkinds) && !exists('b:easytags_nohl') - let starttime = xolox#misc#timer#start() + let starttime = xolox#easytags#misc#timer#start() let used_python = 0 for tagkind in tagkinds let hlgroup_tagged = tagkind.hlgroup . 'Tag' @@ -380,16 +386,16 @@ function! xolox#easytags#highlight() " {{{2 let matches = filter(copy(taglist), filter) if matches != [] " Convert matched tags to :syntax command and execute it. - let matches = xolox#misc#list#unique(map(matches, 'xolox#misc#escape#pattern(get(v:val, "name"))')) + let matches = xolox#easytags#misc#list#unique(map(matches, 'xolox#easytags#misc#escape#pattern(get(v:val, "name"))')) let pattern = tagkind.pattern_prefix . '\%(' . join(matches, '\|') . '\)' . tagkind.pattern_suffix let template = 'syntax match %s /%s/ containedin=ALLBUT,%s' - let command = printf(template, hlgroup_tagged, escape(pattern, '/'), xolox#misc#option#get('easytags_ignored_syntax_groups')) - call xolox#misc#msg#debug("easytags.vim %s: Executing command '%s'.", g:xolox#easytags#version, command) + let command = printf(template, hlgroup_tagged, escape(pattern, '/'), xolox#easytags#misc#option#get('easytags_ignored_syntax_groups')) + call xolox#easytags#misc#msg#debug("easytags.vim %s: Executing command '%s'.", g:xolox#easytags#version, command) try execute command catch /^Vim\%((\a\+)\)\=:E339/ let msg = "easytags.vim %s: Failed to highlight %i %s tags because pattern is too big! (%i KB)" - call xolox#misc#msg#warn(msg, g:xolox#easytags#version, len(matches), tagkind.hlgroup, len(pattern) / 1024) + call xolox#easytags#misc#msg#warn(msg, g:xolox#easytags#version, len(matches), tagkind.hlgroup, len(pattern) / 1024) endtry endif endif @@ -400,11 +406,11 @@ function! xolox#easytags#highlight() " {{{2 let bufname = 'unnamed buffer #' . bufnr('%') endif let msg = "easytags.vim %s: Highlighted tags in %s in %s%s." - call xolox#misc#timer#stop(msg, g:xolox#easytags#version, bufname, starttime, used_python ? " (using Python)" : "") + call xolox#easytags#misc#timer#stop(msg, g:xolox#easytags#version, bufname, starttime, used_python ? " (using Python)" : "") return 1 endif catch - call xolox#misc#msg#warn("easytags.vim %s: %s (at %s)", g:xolox#easytags#version, v:exception, v:throwpoint) + call xolox#easytags#misc#msg#warn("easytags.vim %s: %s (at %s)", g:xolox#easytags#version, v:exception, v:throwpoint) endtry endfunction @@ -421,7 +427,7 @@ function! xolox#easytags#by_filetype(undo) " {{{2 call s:save_by_filetype(0, headers, entries, context) call rename(global_tagsfile, disabled_tagsfile) let msg = "easytags.vim %s: Finished copying tags from %s to %s! Note that your old tags file has been renamed to %s instead of deleting it, should you want to restore it." - call xolox#misc#msg#info(msg, g:xolox#easytags#version, g:easytags_file, g:easytags_by_filetype, disabled_tagsfile) + call xolox#easytags#misc#msg#info(msg, g:xolox#easytags#version, g:easytags_file, g:easytags_by_filetype, disabled_tagsfile) else let headers = [] let all_entries = [] @@ -430,10 +436,10 @@ function! xolox#easytags#by_filetype(undo) " {{{2 call extend(all_entries, entries) endfor call xolox#easytags#write_tagsfile(global_tagsfile, headers, all_entries) - call xolox#misc#msg#info("easytags.vim %s: Finished copying tags from %s to %s!", g:xolox#easytags#version, g:easytags_by_filetype, g:easytags_file) + call xolox#easytags#misc#msg#info("easytags.vim %s: Finished copying tags from %s to %s!", g:xolox#easytags#version, g:easytags_by_filetype, g:easytags_file) endif catch - call xolox#misc#msg#warn("easytags.vim %s: %s (at %s)", g:xolox#easytags#version, v:exception, v:throwpoint) + call xolox#easytags#misc#msg#warn("easytags.vim %s: %s (at %s)", g:xolox#easytags#version, v:exception, v:throwpoint) endtry endfunction @@ -446,7 +452,7 @@ function! s:save_by_filetype(filter_tags, headers, entries, context) " TODO This triggers on entries where the pattern contains tabs. The interesting thing is that Vim reads these entries fine... Fix it in xolox#easytags#read_tagsfile()? let num_invalid += 1 if &vbs >= 1 - call xolox#misc#msg#debug("easytags.vim %s: Skipping tag without 'language:' field: %s", + call xolox#easytags#misc#msg#debug("easytags.vim %s: Skipping tag without 'language:' field: %s", \ g:xolox#easytags#version, string(entry)) endif else @@ -458,13 +464,13 @@ function! s:save_by_filetype(filter_tags, headers, entries, context) endif endfor if num_invalid > 0 - call xolox#misc#msg#warn("easytags.vim %s: Skipped %i lines without 'language:' tag!", g:xolox#easytags#version, num_invalid) + call xolox#easytags#misc#msg#warn("easytags.vim %s: Skipped %i lines without 'language:' tag!", g:xolox#easytags#version, num_invalid) endif - let directory = xolox#misc#path#absolute(g:easytags_by_filetype) + let directory = xolox#easytags#misc#path#absolute(g:easytags_by_filetype) for vim_ft in keys(filetypes) - let tagsfile = xolox#misc#path#merge(directory, vim_ft) + let tagsfile = xolox#easytags#misc#path#merge(directory, vim_ft) let existing = filereadable(tagsfile) - call xolox#misc#msg#debug("easytags.vim %s: Writing %s tags to %s tags file %s.", + call xolox#easytags#misc#msg#debug("easytags.vim %s: Writing %s tags to %s tags file %s.", \ g:xolox#easytags#version, len(filetypes[vim_ft]), \ existing ? "existing" : "new", tagsfile) if !existing @@ -479,15 +485,15 @@ endfunction function! xolox#easytags#supported_filetypes() " {{{2 if !exists('s:supported_filetypes') - let starttime = xolox#misc#timer#start() + let starttime = xolox#easytags#misc#timer#start() let listing = [] if !empty(g:easytags_cmd) let command = g:easytags_cmd . ' --list-languages' - let listing = xolox#misc#os#exec({'command': command})['stdout'] + let listing = xolox#easytags#misc#os#exec({'command': command})['stdout'] endif - let s:supported_filetypes = map(copy(listing) + keys(xolox#misc#option#get('easytags_languages', {})), 's:check_filetype(listing, v:val)') + let s:supported_filetypes = map(copy(listing) + keys(xolox#easytags#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) + call xolox#easytags#misc#timer#stop(msg, g:xolox#easytags#version, len(s:supported_filetypes), starttime) endif return s:supported_filetypes endfunction @@ -533,7 +539,7 @@ function! xolox#easytags#read_tagsfile(tagsfile) " {{{2 endif endfor if num_invalid > 0 - call xolox#misc#msg#warn("easytags.vim %s: Ignored %i invalid line(s) in %s!", g:xolox#easytags#version, num_invalid, a:tagsfile) + call xolox#easytags#misc#msg#warn("easytags.vim %s: Ignored %i invalid line(s) in %s!", g:xolox#easytags#version, num_invalid, a:tagsfile) endif return [headers, entries] endfunction @@ -563,7 +569,7 @@ function! xolox#easytags#write_tagsfile(tagsfile, headers, entries) " {{{2 call sort(a:entries, function('s:foldcase_compare')) endif let lines = [] - if xolox#misc#os#is_win() + if xolox#easytags#misc#os#is_win() " Exuberant Ctags on Windows requires \r\n but Vim's writefile() doesn't add them! for line in a:headers call add(lines, line . "\r") @@ -609,10 +615,10 @@ function! s:cache_tagged_files(context) " {{{3 " Initialize the cache of tagged files on first use. After initialization " we'll only update the cache when we're reading a tags file from disk for " other purposes anyway (so the cache doesn't introduce too much overhead). - let starttime = xolox#misc#timer#start() + let starttime = xolox#easytags#misc#timer#start() for tagsfile in tagfiles() if !filereadable(tagsfile) - call xolox#misc#msg#warn("easytags.vim %s: Skipping unreadable tags file %s!", g:xolox#easytags#version, tagsfile) + call xolox#easytags#misc#msg#warn("easytags.vim %s: Skipping unreadable tags file %s!", g:xolox#easytags#version, tagsfile) else let fname = s:canonicalize(tagsfile, a:context) let ftime = getftime(fname) @@ -622,7 +628,7 @@ function! s:cache_tagged_files(context) " {{{3 endif endif endfor - call xolox#misc#timer#stop("easytags.vim %s: Initialized cache of tagged files in %s.", g:xolox#easytags#version, starttime) + call xolox#easytags#misc#timer#stop("easytags.vim %s: Initialized cache of tagged files in %s.", g:xolox#easytags#version, starttime) endif endfunction @@ -639,28 +645,28 @@ endfunction function! xolox#easytags#get_tagsfile() " {{{2 let tagsfile = '' " Look for a suitable project specific tags file? - let dynamic_files = xolox#misc#option#get('easytags_dynamic_files', 0) + let dynamic_files = xolox#easytags#misc#option#get('easytags_dynamic_files', 0) if dynamic_files == 1 let tagsfile = get(tagfiles(), 0, '') elseif dynamic_files == 2 - let tagsfile = xolox#misc#option#eval_tags(&tags, 1) + let tagsfile = xolox#easytags#misc#option#eval_tags(&tags, 1) let directory = fnamemodify(tagsfile, ':h') if filewritable(directory) != 2 " If the directory of the dynamic tags file is not writable, we fall " back to a file type specific tags file or the global tags file. - call xolox#misc#msg#warn("easytags.vim %s: Dynamic tags files enabled but %s not writable so falling back.", g:xolox#easytags#version, directory) + call xolox#easytags#misc#msg#warn("easytags.vim %s: Dynamic tags files enabled but %s not writable so falling back.", g:xolox#easytags#version, directory) let tagsfile = '' endif endif " Check if a file type specific tags file is useful? let applicable_filetypes = xolox#easytags#select_supported_filetypes(&ft) if empty(tagsfile) && !empty(g:easytags_by_filetype) && !empty(applicable_filetypes) - let directory = xolox#misc#path#absolute(g:easytags_by_filetype) - let tagsfile = xolox#misc#path#merge(directory, applicable_filetypes[0]) + let directory = xolox#easytags#misc#path#absolute(g:easytags_by_filetype) + let tagsfile = xolox#easytags#misc#path#merge(directory, applicable_filetypes[0]) endif " Default to the global tags file? if empty(tagsfile) - let tagsfile = expand(xolox#misc#option#get('easytags_file')) + let tagsfile = expand(xolox#easytags#misc#option#get('easytags_file')) endif " If the tags file exists, make sure it is writable! if filereadable(tagsfile) && filewritable(tagsfile) != 1 @@ -733,7 +739,7 @@ function! s:create_context() " {{{2 endfunction function! s:resolve(filename) " {{{2 - if xolox#misc#option#get('easytags_resolve_links', 0) + if xolox#easytags#misc#option#get('easytags_resolve_links', 0) return resolve(a:filename) else return a:filename @@ -769,7 +775,7 @@ function! s:python_available() " {{{2 endfunction function! s:highlight_with_python(syntax_group, tagkind) " {{{2 - if xolox#misc#option#get('easytags_python_enabled', 1) && s:python_available() + if xolox#easytags#misc#option#get('easytags_python_enabled', 1) && s:python_available() " Gather arguments for Python function. let context = {} let context['tagsfiles'] = tagfiles() @@ -780,7 +786,7 @@ function! s:highlight_with_python(syntax_group, tagkind) " {{{2 let context['prefix'] = get(a:tagkind, 'pattern_prefix', '') let context['suffix'] = get(a:tagkind, 'pattern_suffix', '') let context['filters'] = get(a:tagkind, 'python_filter', {}) - let context['ignoresyntax'] = xolox#misc#option#get('easytags_ignored_syntax_groups') + let context['ignoresyntax'] = xolox#easytags#misc#option#get('easytags_ignored_syntax_groups') " Call the Python function and intercept the output. try redir => commands @@ -856,7 +862,7 @@ call xolox#easytags#define_tagkind({ highlight def link cEnum Identifier highlight def link cFunction Function -if xolox#misc#option#get('easytags_include_members', 0) +if xolox#easytags#misc#option#get('easytags_include_members', 0) call xolox#easytags#define_tagkind({ \ 'filetype': 'c', \ 'hlgroup': 'cMember', diff --git a/autoload/xolox/easytags/misc/buffer.vim b/autoload/xolox/easytags/misc/buffer.vim new file mode 100644 index 0000000..7fbaff8 --- /dev/null +++ b/autoload/xolox/easytags/misc/buffer.vim @@ -0,0 +1,86 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + +" Handling of special buffers +" +" Author: Peter Odding +" Last Change: May 19, 2013 +" URL: http://peterodding.com/code/vim/misc/ +" +" The functions defined here make it easier to deal with special Vim buffers +" that contain text generated by a Vim plug-in. For example my [vim-notes +" plug-in] [vim-notes] generates several such buffers: +" +" - [:RecentNotes] [RecentNotes] lists recently modified notes +" - [:ShowTaggedNotes] [ShowTaggedNotes] lists notes grouped by tags +" - etc. +" +" Because the text in these buffers is generated, Vim shouldn't bother with +" swap files and it should never prompt the user whether to save changes to +" the generated text. +" +" [vim-notes]: http://peterodding.com/code/vim/notes/ +" [RecentNotes]: http://peterodding.com/code/vim/notes/#recentnotes_command +" [ShowTaggedNotes]: http://peterodding.com/code/vim/notes/#showtaggednotes_command + +function! xolox#easytags#misc#buffer#is_empty() " {{{1 + " Checks if the current buffer is an empty, unchanged buffer which can be + " reused. Returns 1 if an empty buffer is found, 0 otherwise. + return !&modified && expand('%') == '' && line('$') <= 1 && getline(1) == '' +endfunction + +function! xolox#easytags#misc#buffer#prepare(...) " {{{1 + " Open a special buffer, i.e. a buffer that will hold generated contents, + " not directly edited by the user. The buffer can be customized by passing a + " dictionary with the following key/value pairs as the first argument: + " + " - **name** (required): The base name of the buffer (i.e. the base name of + " the file loaded in the buffer, even though it isn't really a file and + " nothing is really 'loaded' :-) + " - **path** (required): The pathname of the buffer. May be relevant if + " [:lcd] [lcd] or ['autochdir'] [acd] is being used. + " + " [lcd]: http://vimdoc.sourceforge.net/htmldoc/editing.html#:lcd + " [acd]: http://vimdoc.sourceforge.net/htmldoc/options.html#'autochdir' + 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#easytags#misc#path#equals(options['path'], bufname(bufnr)) + execute winnr . 'wincmd w' + let found = 1 + break + else + let winnr += 1 + endif + endfor + if !(found || xolox#easytags#misc#buffer#is_empty()) + vsplit + endif + silent execute 'edit' fnameescape(options['path']) + lcd " clear working directory + setlocal buftype=nofile bufhidden=hide noswapfile + let &l:statusline = '[' . options['name'] . ']' + call xolox#easytags#misc#buffer#unlock() + silent %delete +endfunction + +function! xolox#easytags#misc#buffer#lock() " {{{1 + " Lock a special buffer so that its contents can no longer be edited. + setlocal readonly nomodifiable nomodified +endfunction + +function! xolox#easytags#misc#buffer#unlock() " {{{1 + " Unlock a special buffer so that its content can be updated. + setlocal noreadonly modifiable +endfunction diff --git a/autoload/xolox/easytags/misc/complete.vim b/autoload/xolox/easytags/misc/complete.vim new file mode 100644 index 0000000..d85e4ab --- /dev/null +++ b/autoload/xolox/easytags/misc/complete.vim @@ -0,0 +1,28 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + +" Tab completion for user defined commands. +" +" Author: Peter Odding +" Last Change: May 19, 2013 +" URL: http://peterodding.com/code/vim/misc/ + +function! xolox#easytags#misc#complete#keywords(arglead, cmdline, cursorpos) + " This function can be used to perform keyword completion for user defined + " Vim commands based on the contents of the current buffer. Here's an + " example of how you would use it: + " + " :command -nargs=* -complete=customlist,xolox#easytags#misc#complete#keywords MyCmd call s:MyCmd() + let words = {} + for line in getline(1, '$') + for word in split(line, '\W\+') + let words[word] = 1 + endfor + endfor + return sort(keys(filter(words, 'v:key =~# a:arglead'))) +endfunction + +" vim: ts=2 sw=2 et diff --git a/autoload/xolox/easytags/misc/escape.vim b/autoload/xolox/easytags/misc/escape.vim new file mode 100644 index 0000000..26839c8 --- /dev/null +++ b/autoload/xolox/easytags/misc/escape.vim @@ -0,0 +1,62 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + +" String escaping functions. +" +" Author: Peter Odding +" Last Change: May 19, 2013 +" URL: http://peterodding.com/code/vim/misc/ + +function! xolox#easytags#misc#escape#pattern(string) " {{{1 + " Takes a single string argument and converts it into a [:substitute] + " [subcmd] / [substitute()] [subfun] pattern string that matches the given + " string literally. + " + " [subfun]: http://vimdoc.sourceforge.net/htmldoc/eval.html#substitute() + " [subcmd]: http://vimdoc.sourceforge.net/htmldoc/change.html#:substitute + if type(a:string) == type('') + let string = escape(a:string, '^$.*\~[]') + return substitute(string, '\n', '\\n', 'g') + endif + return '' +endfunction + +function! xolox#easytags#misc#escape#substitute(string) " {{{1 + " Takes a single string argument and converts it into a [:substitute] + " [subcmd] / [substitute()] [subfun] replacement string that inserts the + " given string literally. + if type(a:string) == type('') + let string = escape(a:string, '\&~%') + return substitute(string, '\n', '\\r', 'g') + endif + return '' +endfunction + +function! xolox#easytags#misc#escape#shell(string) " {{{1 + " Takes a single string argument and converts it into a quoted command line + " argument. + " + " I was going to add a long rant here about Vim's ['shellslash' option] + " [shellslash], but really, it won't make any difference. Let's just suffice + " to say that I have yet to encounter a single person out there who uses + " this option for its intended purpose (running a UNIX style shell on + " Microsoft Windows). + " + " [shellslash]: http://vimdoc.sourceforge.net/htmldoc/options.html#'shellslash' + if xolox#easytags#misc#os#is_win() + try + let ssl_save = &shellslash + set noshellslash + return shellescape(a:string) + finally + let &shellslash = ssl_save + endtry + else + return shellescape(a:string) + endif +endfunction + +" vim: ts=2 sw=2 et diff --git a/autoload/xolox/easytags/misc/list.vim b/autoload/xolox/easytags/misc/list.vim new file mode 100644 index 0000000..04bb6a8 --- /dev/null +++ b/autoload/xolox/easytags/misc/list.vim @@ -0,0 +1,63 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + +" List handling functions. +" +" Author: Peter Odding +" Last Change: May 19, 2013 +" URL: http://peterodding.com/code/vim/misc/ + +function! xolox#easytags#misc#list#unique(list) " {{{1 + " Remove duplicate values from the given list in-place (preserves order). + call reverse(a:list) + call filter(a:list, 'count(a:list, v:val) == 1') + return reverse(a:list) +endfunction + +function! xolox#easytags#misc#list#binsert(list, value, ...) " {{{1 + " Performs in-place binary insertion, which depending on your use case can + " be more efficient than calling Vim's [sort()] [sort] function after each + " insertion (in cases where a single, final sort is not an option). Expects + " three arguments: + " + " 1. A list + " 2. A value to insert + " 3. 1 (true) when case should be ignored, 0 (false) otherwise + " + " [sort]: http://vimdoc.sourceforge.net/htmldoc/eval.html#sort() + let idx = s:binsert_r(a:list, 0, len(a:list), a:value, exists('a:1') && a:1) + return insert(a:list, a:value, idx) +endfunction + +function! s:binsert_r(list, low, high, value, ignorecase) + let mid = a:low + (a:high - a:low) / 2 + if a:low == a:high + return a:low + elseif a:ignorecase ? a:value >? a:list[mid] : a:value > a:list[mid] + return s:binsert_r(a:list, mid + 1, a:high, a:value, a:ignorecase) + elseif a:ignorecase ? a:value +" Last Change: May 20, 2013 +" URL: http://peterodding.com/code/vim/misc/ + +if !exists('g:xolox_message_buffer') + " For when I lose my :messages history :-\ + let g:xolox_message_buffer = 100 +endif + +if !exists('g:xolox_messages') + let g:xolox_messages = [] +endif + +function! xolox#easytags#misc#msg#info(...) " {{{1 + " Show a formatted informational message to the user. This function has the + " same argument handling as Vim's [printf()] [printf] function. + " + " [printf]: http://vimdoc.sourceforge.net/htmldoc/eval.html#printf() + call s:show_message('title', a:000) +endfunction + +function! xolox#easytags#misc#msg#warn(...) " {{{1 + " Show a formatted warning message to the user. This function has the same + " argument handling as Vim's [printf()] [printf] function. + call s:show_message('warningmsg', a:000) +endfunction + +function! xolox#easytags#misc#msg#debug(...) " {{{1 + " Show a formatted debugging message to the user, if the user has enabled + " increased verbosity by setting Vim's ['verbose'] [verbose] option to one + " (1) or higher. This function has the same argument handling as Vim's + " [printf()] [printf] function. + if &vbs >= 1 + call s:show_message('question', a:000) + endif +endfunction + +function! s:show_message(hlgroup, args) " {{{1 + " The implementation of info() and warn(). + let nargs = len(a:args) + if nargs == 1 + let message = a:args[0] + elseif nargs >= 2 + let message = call('printf', a:args) + endif + if exists('message') + try + " Temporarily disable Vim's |hit-enter| prompt and mode display. + if !exists('s:more_save') + let s:more_save = &more + let s:ruler_save = &ruler + let s:smd_save = &showmode + endif + set nomore noshowmode + if winnr('$') == 1 | set noruler | endif + augroup PluginXoloxHideMode + autocmd! CursorHold,CursorHoldI * call s:clear_message() + augroup END + execute 'echohl' a:hlgroup + " Redraw to avoid |hit-enter| prompt. + redraw + for line in split(message, "\n") + echomsg line + endfor + if g:xolox_message_buffer > 0 + call add(g:xolox_messages, message) + if len(g:xolox_messages) > g:xolox_message_buffer + call remove(g:xolox_messages, 0) + endif + endif + finally + " Always clear message highlighting, even when interrupted by Ctrl-C. + echohl none + endtry + endif +endfunction + +function! s:clear_message() " {{{1 + " Callback to clear message after some time has passed. + echo '' + let &more = s:more_save + let &showmode = s:smd_save + let &ruler = s:ruler_save + unlet s:more_save s:ruler_save s:smd_save + autocmd! PluginXoloxHideMode + augroup! PluginXoloxHideMode +endfunction + +" vim: ts=2 sw=2 et diff --git a/autoload/xolox/easytags/misc/open.vim b/autoload/xolox/easytags/misc/open.vim new file mode 100644 index 0000000..254dc61 --- /dev/null +++ b/autoload/xolox/easytags/misc/open.vim @@ -0,0 +1,98 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + +" Integration between Vim and its environment. +" +" Author: Peter Odding +" Last Change: May 19, 2013 +" URL: http://peterodding.com/code/vim/misc/ + +if !exists('s:version') + let s:version = '1.1' + let s:enoimpl = "open.vim %s: %s() hasn't been implemented for your platform! If you have suggestions, please contact peter@peterodding.com." + let s:handlers = ['gnome-open', 'kde-open', 'exo-open', 'xdg-open'] +endif + +function! xolox#easytags#misc#open#file(path, ...) " {{{1 + " Given a pathname as the first argument, this opens the file with the + " program associated with the file type. So for example a text file might + " open in Vim, an `*.html` file would probably open in your web browser and + " a media file would open in a media player. + " + " This should work on Windows, Mac OS X and most Linux distributions. If + " this fails to find a file association, you can pass one or more external + " commands to try as additional arguments. For example: + " + " :call xolox#easytags#misc#open#file('/path/to/my/file', 'firefox', 'google-chrome') + " + " This generally shouldn't be necessary but it might come in handy now and + " then. + if xolox#easytags#misc#os#is_win() + try + call xolox#shell#open_with_windows_shell(a:path) + catch /^Vim\%((\a\+)\)\=:E117/ + let command = '!start CMD /C START "" %s' + silent execute printf(command, xolox#easytags#misc#escape#shell(a:path)) + endtry + return + elseif has('macunix') + let cmd = 'open ' . shellescape(a:path) . ' 2>&1' + call s:handle_error(cmd, system(cmd)) + return + else + for handler in s:handlers + a:000 + if executable(handler) + call xolox#easytags#misc#msg#debug("open.vim %s: Using '%s' to open '%s'.", s:version, handler, a:path) + let cmd = shellescape(handler) . ' ' . shellescape(a:path) . ' 2>&1' + call s:handle_error(cmd, system(cmd)) + return + endif + endfor + endif + throw printf(s:enoimpl, s:script, 'xolox#easytags#misc#open#file') +endfunction + +function! xolox#easytags#misc#open#url(url) " {{{1 + " Given a URL as the first argument, this opens the URL in your preferred or + " best available web browser: + " + " - In GUI environments a graphical web browser will open (or a new tab will + " be created in an existing window) + " - In console Vim without a GUI environment, when you have any of `lynx`, + " `links` or `w3m` installed it will launch a command line web browser in + " front of Vim (temporarily suspending Vim) + let url = a:url + if url !~ '^\w\+://' + if url !~ '@' + let url = 'http://' . url + elseif url !~ '^mailto:' + let url = 'mailto:' . url + endif + endif + if has('unix') && !has('gui_running') && $DISPLAY == '' + for browser in ['lynx', 'links', 'w3m'] + if executable(browser) + execute '!' . browser fnameescape(url) + call s:handle_error(browser . ' ' . url, '') + return + endif + endfor + endif + call xolox#easytags#misc#open#file(url, 'firefox', 'google-chrome') +endfunction + +function! s:handle_error(cmd, output) " {{{1 + if v:shell_error + let message = "open.vim %s: Failed to execute program! (command line: %s%s)" + let output = strtrans(xolox#easytags#misc#str#trim(a:output)) + if output != '' + let output = ", output: " . string(output) + endif + throw printf(message, s:version, a:cmd, output) + endif +endfunction + +" vim: et ts=2 sw=2 fdm=marker diff --git a/autoload/xolox/easytags/misc/option.vim b/autoload/xolox/easytags/misc/option.vim new file mode 100644 index 0000000..3d49486 --- /dev/null +++ b/autoload/xolox/easytags/misc/option.vim @@ -0,0 +1,121 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + +" Vim and plug-in option handling. +" +" Author: Peter Odding +" Last Change: May 19, 2013 +" URL: http://peterodding.com/code/vim/misc/ + +function! xolox#easytags#misc#option#get(name, ...) " {{{1 + " Expects one or two arguments: 1. The name of a variable and 2. the default + " value if the variable does not exist. + " + " Returns the value of the variable from a buffer local variable, global + " variable or the default value, depending on which is defined. + " + " This is used by some of my Vim plug-ins for option handling, so that users + " can customize options for specific buffers. + if exists('b:' . a:name) + " Buffer local variable. + return eval('b:' . a:name) + elseif exists('g:' . a:name) + " Global variable. + return eval('g:' . a:name) + elseif exists('a:1') + " Default value. + return a:1 + endif +endfunction + +function! xolox#easytags#misc#option#split(value) " {{{1 + " Given a multi-value Vim option like ['runtimepath'] [rtp] this returns a + " list of strings. For example: + " + " :echo xolox#easytags#misc#option#split(&runtimepath) + " ['/home/peter/Projects/Vim/misc', + " '/home/peter/Projects/Vim/colorscheme-switcher', + " '/home/peter/Projects/Vim/easytags', + " ...] + " + " [rtp]: http://vimdoc.sourceforge.net/htmldoc/options.html#'runtimepath' + let values = split(a:value, '[^\\]\zs,') + return map(values, 's:unescape(v:val)') +endfunction + +function! s:unescape(s) + return substitute(a:s, '\\\([\\,]\)', '\1', 'g') +endfunction + +function! xolox#easytags#misc#option#join(values) " {{{1 + " Given a list of strings like the ones returned by + " `xolox#easytags#misc#option#split()`, this joins the strings together into a + " single value that can be used to set a Vim option. + let values = copy(a:values) + call map(values, 's:escape(v:val)') + return join(values, ',') +endfunction + +function! s:escape(s) + return escape(a:s, ',\') +endfunction + +function! xolox#easytags#misc#option#split_tags(value) " {{{1 + " Customized version of `xolox#easytags#misc#option#split()` with specialized + " handling for Vim's ['tags' option] [tags]. + " + " [tags]: http://vimdoc.sourceforge.net/htmldoc/options.html#'tags' + let values = split(a:value, '[^\\]\zs,') + return map(values, 's:unescape_tags(v:val)') +endfunction + +function! s:unescape_tags(s) + return substitute(a:s, '\\\([\\, ]\)', '\1', 'g') +endfunction + +function! xolox#easytags#misc#option#join_tags(values) " {{{1 + " Customized version of `xolox#easytags#misc#option#join()` with specialized + " handling for Vim's ['tags' option] [tags]. + let values = copy(a:values) + call map(values, 's:escape_tags(v:val)') + return join(values, ',') +endfunction + +function! s:escape_tags(s) + return escape(a:s, ', ') +endfunction + +function! xolox#easytags#misc#option#eval_tags(value, ...) " {{{1 + " Evaluate Vim's ['tags' option] [tags] without looking at the file + " system, i.e. this will report tags files that don't exist yet. Expects + " the value of the ['tags' option] [tags] as the first argument. If the + " optional second argument is 1 (true) only the first match is returned, + " otherwise (so by default) a list with all matches is returned. + let pathnames = [] + let first_only = exists('a:1') ? a:1 : 0 + for pattern in xolox#easytags#misc#option#split_tags(a:value) + " Make buffer relative pathnames absolute. + if pattern =~ '^\./' + let directory = xolox#easytags#misc#escape#substitute(expand('%:p:h')) + let pattern = substitute(pattern, '^.\ze/', directory, '') + endif + " Make working directory relative pathnames absolute. + if xolox#easytags#misc#path#is_relative(pattern) + let pattern = xolox#easytags#misc#path#merge(getcwd(), pattern) + endif + " Ignore the trailing `;' for recursive upwards searching because we + " always want the most specific pathname available. + let pattern = substitute(pattern, ';$', '', '') + " Expand the pattern. + call extend(pathnames, split(expand(pattern), "\n")) + if first_only && !empty(pathnames) + return pathnames[0] + endif + endfor + return first_only ? '' : pathnames +endfunction + +" vim: ts=2 sw=2 et diff --git a/autoload/xolox/easytags/misc/os.vim b/autoload/xolox/easytags/misc/os.vim new file mode 100644 index 0000000..c2ef4f4 --- /dev/null +++ b/autoload/xolox/easytags/misc/os.vim @@ -0,0 +1,194 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + +" Operating system interfaces. +" +" Author: Peter Odding +" Last Change: May 20, 2013 +" URL: http://peterodding.com/code/vim/misc/ + +let g:xolox#easytags#misc#os#version = '0.5' + +function! xolox#easytags#misc#os#is_win() " {{{1 + " Returns 1 (true) when on Microsoft Windows, 0 (false) otherwise. + return has('win16') || has('win32') || has('win64') +endfunction + +function! xolox#easytags#misc#os#find_vim() " {{{1 + " Returns the program name of Vim as a string. On Windows and UNIX this + " simply returns [v:progname] [progname] while on Mac OS X there is some + " special magic to find MacVim's executable even though it's usually not on + " the executable search path. + " + " [progname]: http://vimdoc.sourceforge.net/htmldoc/eval.html#v:progname + let progname = '' + if has('macunix') + " Special handling for Mac OS X where MacVim is usually not on the $PATH. + call xolox#easytags#misc#msg#debug("os.vim %s: Trying MacVim workaround to find Vim executable ..", g:xolox#easytags#misc#os#version) + let segments = xolox#easytags#misc#path#split($VIMRUNTIME) + if segments[-3:] == ['Resources', 'vim', 'runtime'] + let progname = xolox#easytags#misc#path#join(segments[0:-4] + ['MacOS', 'Vim']) + call xolox#easytags#misc#msg#debug("os.vim %s: The MacVim workaround resulted in the Vim executable %s.", g:xolox#easytags#misc#os#version, string(progname)) + endif + endif + if empty(progname) + call xolox#easytags#misc#msg#debug("os.vim %s: Looking for Vim executable named %s on search path ..", g:xolox#easytags#misc#os#version, string(v:progname)) + let candidates = xolox#easytags#misc#path#which(v:progname) + if !empty(candidates) + call xolox#easytags#misc#msg#debug("os.vim %s: Found %i candidate(s) on search path: %s.", g:xolox#easytags#misc#os#version, len(candidates), string(candidates)) + let progname = candidates[0] + endif + endif + call xolox#easytags#misc#msg#debug("os.vim %s: Reporting Vim executable %s.", g:xolox#easytags#misc#os#version, string(progname)) + return progname +endfunction + +function! xolox#easytags#misc#os#exec(options) " {{{1 + " Execute an external command (hiding the console on Microsoft Windows when + " my [vim-shell plug-in] [vim-shell] is installed). + " + " Expects a dictionary with the following key/value pairs as the first + " argument: + " + " - **command** (required): The command line to execute + " - **async** (optional): set this to 1 (true) to execute the command in the + " background (asynchronously) + " - **stdin** (optional): a string or list of strings with the input for the + " external command + " - **check** (optional): set this to 0 (false) to disable checking of the + " exit code of the external command (by default an exception will be + " raised when the command fails) + " + " Returns a dictionary with one or more of the following key/value pairs: + " + " - **command** (always available): the generated command line that was used + " to run the external command + " - **exit_code** (only in synchronous mode): the exit status of the + " external command (an integer, zero on success) + " - **stdout** (only in synchronous mode): the output of the command on the + " standard output stream (a list of strings, one for each line) + " - **stderr** (only in synchronous mode): the output of the command on the + " standard error stream (as a list of strings, one for each line) + " + " [vim-shell]: http://peterodding.com/code/vim/shell/ + try + + " Unpack the options. + let cmd = a:options['command'] + let async = get(a:options, 'async', 0) + + " Write the input for the external command to a temporary file? + if has_key(a:options, 'stdin') + let tempin = tempname() + if type(a:options['stdin']) == type([]) + let lines = a:options['stdin'] + else + let lines = split(a:options['stdin'], "\n") + endif + call writefile(lines, tempin) + let cmd .= ' < ' . xolox#easytags#misc#escape#shell(tempin) + endif + + " Redirect the standard output and standard error streams of the external + " process to temporary files? (only in synchronous mode, which is the + " default). + if !async + let tempout = tempname() + let temperr = tempname() + let cmd = printf('(%s) 1>%s 2>%s', cmd, xolox#easytags#misc#escape#shell(tempout), xolox#easytags#misc#escape#shell(temperr)) + endif + + " If A) we're on Windows, B) the vim-shell plug-in is installed and C) the + " compiled DLL works, we'll use that because it's the most user friendly + " method. If the plug-in is not installed Vim will raise the exception + " "E117: Unknown function" which is caught and handled below. + try + if xolox#shell#can_use_dll() + " Let the user know what's happening (in case they're interested). + call xolox#easytags#misc#msg#debug("os.vim %s: Executing external command using compiled DLL: %s", g:xolox#easytags#misc#os#version, cmd) + let exit_code = xolox#shell#execute_with_dll({'command': cmd, 'async': async}) + endif + catch /^Vim\%((\a\+)\)\=:E117/ + call xolox#easytags#misc#msg#debug("os.vim %s: The vim-shell plug-in is not installed, falling back to system() function.", g:xolox#easytags#misc#os#version) + endtry + + " If we cannot use the DLL, we fall back to the default and generic + " implementation using Vim's system() function. + if !exists('exit_code') + + " Enable asynchronous mode (very platform specific). + if async + if xolox#easytags#misc#os#is_win() + let cmd = 'start /b ' . cmd + elseif has('unix') + let cmd = '(' . cmd . ') &' + else + call xolox#easytags#misc#msg#warn("os.vim %s: I don't know how to run commands asynchronously on your platform! Falling back to synchronous mode.", g:xolox#easytags#misc#os#version) + endif + endif + + " Execute the command line using 'sh' instead of the default shell, + " because we assume that standard output and standard error can be + " redirected separately, but (t)csh does not support this. + if has('unix') + call xolox#easytags#misc#msg#debug("os.vim %s: Generated shell expression: %s", g:xolox#easytags#misc#os#version, cmd) + let cmd = printf('sh -c %s', xolox#easytags#misc#escape#shell(cmd)) + endif + + " Let the user know what's happening (in case they're interested). + call xolox#easytags#misc#msg#debug("os.vim %s: Executing external command using system() function: %s", g:xolox#easytags#misc#os#version, cmd) + call system(cmd) + let exit_code = v:shell_error + + endif + + " Return the results as a dictionary with one or more key/value pairs. + let result = {'command': cmd} + if !async + let result['exit_code'] = exit_code + let result['stdout'] = s:readfile(tempout) + let result['stderr'] = s:readfile(temperr) + " If we just executed a synchronous command and the caller didn't + " specifically ask us *not* to check the exit code of the external + " command, we'll do so now. + if get(a:options, 'check', 1) && exit_code != 0 + " Prepare an error message with enough details so the user can investigate. + let msg = printf("os.vim %s: External command failed with exit code %d!", g:xolox#easytags#misc#os#version, result['exit_code']) + let msg .= printf("\nCommand line: %s", result['command']) + " If the external command reported an error, we'll include it in our message. + if !empty(result['stderr']) + " This is where we would normally expect to find an error message. + let msg .= printf("\nOutput on standard output stream:\n%s", join(result['stderr'], "\n")) + elseif !empty(result['stdout']) + " Exuberant Ctags on Windows XP reports errors on standard output :-x. + let msg .= printf("\nOutput on standard error stream:\n%s", join(result['stdout'], "\n")) + endif + throw msg + endif + endif + return result + + finally + " Cleanup any temporary files we created. + for name in ['tempin', 'tempout', 'temperr'] + if exists(name) + call delete({name}) + endif + endfor + endtry + +endfunction + +function! s:readfile(fname) " {{{1 + " readfile() that swallows errors. + try + return readfile(a:fname) + catch + return [] + endtry +endfunction + +" vim: ts=2 sw=2 et diff --git a/autoload/xolox/easytags/misc/path.vim b/autoload/xolox/easytags/misc/path.vim new file mode 100644 index 0000000..f4a774d --- /dev/null +++ b/autoload/xolox/easytags/misc/path.vim @@ -0,0 +1,262 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + +" Pathname manipulation functions. +" +" Author: Peter Odding +" Last Change: May 20, 2013 +" URL: http://peterodding.com/code/vim/misc/ + +let s:windows_compatible = xolox#easytags#misc#os#is_win() +let s:mac_os_x_compatible = has('macunix') + +function! xolox#easytags#misc#path#which(...) " {{{1 + " Scan the executable search path (`$PATH`) for one or more external + " programs. Expects one or more string arguments with program names. Returns + " a list with the absolute pathnames of all found programs. Here's an + " example: + " + " :echo xolox#easytags#misc#path#which('gvim', 'vim') + " ['/usr/local/bin/gvim', + " '/usr/bin/gvim', + " '/usr/local/bin/vim', + " '/usr/bin/vim'] + let extensions = [''] + if s:windows_compatible + call extend(extensions, split($PATHEXT, ';')) + endif + let matches = [] + let checked = {} + for program in a:000 + for extension in extensions + for directory in split($PATH, s:windows_compatible ? ';' : ':') + let directory = xolox#easytags#misc#path#absolute(directory) + if isdirectory(directory) + let path = xolox#easytags#misc#path#merge(directory, program . extension) + if executable(path) + call add(matches, path) + endif + endif + endfor + endfor + endfor + return matches +endfunction + +function! xolox#easytags#misc#path#split(path) " {{{1 + " Split a pathname (the first and only argument) into a list of pathname + " components. + " + " On Windows, pathnames starting with two slashes or backslashes are UNC + " paths where the leading slashes are significant... In this case we split + " like this: + " + " - Input: `'//server/share/directory'` + " - Result: `['//server', 'share', 'directory']` + " + " Everything except Windows is treated like UNIX until someone has a better + " suggestion :-). In this case we split like this: + " + " - Input: `'/foo/bar/baz'` + " - Result: `['/', 'foo', 'bar', 'baz']` + " + " To join a list of pathname components back into a single pathname string, + " use the `xolox#easytags#misc#path#join()` function. + if type(a:path) == type('') + if s:windows_compatible + if a:path =~ '^[\/][\/]' + " UNC pathname. + return split(a:path, '\%>2c[\/]\+') + else + " If it's not a UNC path we can simply split on slashes & backslashes. + return split(a:path, '[\/]\+') + endif + else + " Everything else is treated as UNIX. + let absolute = (a:path =~ '^/') + let segments = split(a:path, '/\+') + return absolute ? insert(segments, '/') : segments + endif + endif + return [] +endfunction + +function! xolox#easytags#misc#path#join(parts) " {{{1 + " Join a list of pathname components (the first and only argument) into a + " single pathname string. This is the counterpart to the + " `xolox#easytags#misc#path#split()` function and it expects a list of pathname + " components as returned by `xolox#easytags#misc#path#split()`. + if type(a:parts) == type([]) + if s:windows_compatible + return join(a:parts, xolox#easytags#misc#path#directory_separator()) + elseif a:parts[0] == '/' + " Absolute path on UNIX (non-Windows). + return '/' . join(a:parts[1:], '/') + else + " Relative path on UNIX (non-Windows). + return join(a:parts, '/') + endif + endif + return '' +endfunction + +function! xolox#easytags#misc#path#directory_separator() " {{{1 + " Find the preferred directory separator for the platform and settings. + return exists('+shellslash') && &shellslash ? '/' : '\' +endfunction + +function! xolox#easytags#misc#path#absolute(path) " {{{1 + " Canonicalize and resolve a pathname, *regardless of whether it exists*. + " This is intended to support string comparison to determine whether two + " pathnames point to the same directory or file. + if type(a:path) == type('') + let path = a:path + " Make the pathname absolute. + if path =~ '^\~' + " Expand ~ to $HOME. + let path = $HOME . '/' . path[1:] + elseif xolox#easytags#misc#path#is_relative(path) + " Make relative pathnames absolute. + let path = getcwd() . '/' . path + endif + " Resolve symbolic links to find the canonical pathname. In my tests this + " also removes all symbolic pathname segments (`.' and `..'), even when + " the pathname does not exist. Also there used to be a bug in resolve() + " where it wouldn't resolve pathnames ending in a directory separator. + " Since it's not much trouble to work around, that's what we do. + let path = resolve(substitute(path, s:windows_compatible ? '[\/]\+$' : '/\+$', '', '')) + " Normalize directory separators (especially relevant on Windows). + let parts = xolox#easytags#misc#path#split(path) + if s:windows_compatible && parts[0] =~ '^[\/][\/]' + " Also normalize the two leading "directory separators" (I'm not + " sure what else to call them :-) in Windows UNC pathnames. + let parts[0] = repeat(xolox#easytags#misc#path#directory_separator(), 2) . parts[0][2:] + endif + return xolox#easytags#misc#path#join(parts) + endif + return '' +endfunction + +function! xolox#easytags#misc#path#relative(path, base) " {{{1 + " Make an absolute pathname (the first argument) relative to a directory + " (the second argument). + let path = xolox#easytags#misc#path#split(a:path) + let base = xolox#easytags#misc#path#split(a:base) + while path != [] && base != [] && path[0] == base[0] + call remove(path, 0) + call remove(base, 0) + endwhile + let distance = repeat(['..'], len(base)) + return xolox#easytags#misc#path#join(distance + path) +endfunction + + +function! xolox#easytags#misc#path#merge(parent, child, ...) " {{{1 + " Join a directory pathname and filename into a single pathname. + if type(a:parent) == type('') && type(a:child) == type('') + " TODO Use xolox#easytags#misc#path#is_relative()? + if s:windows_compatible + let parent = substitute(a:parent, '[\\/]\+$', '', '') + let child = substitute(a:child, '^[\\/]\+', '', '') + return parent . '\' . child + else + let parent = substitute(a:parent, '/\+$', '', '') + let child = substitute(a:child, '^/\+', '', '') + return parent . '/' . child + endif + endif + return '' +endfunction + +function! xolox#easytags#misc#path#commonprefix(paths) " {{{1 + " Find the common prefix of path components in a list of pathnames. + let common = xolox#easytags#misc#path#split(a:paths[0]) + for path in a:paths + let index = 0 + for segment in xolox#easytags#misc#path#split(path) + if len(common) <= index + break + elseif common[index] != segment + call remove(common, index, -1) + break + endif + let index += 1 + endfor + endfor + return xolox#easytags#misc#path#join(common) +endfunction + +function! xolox#easytags#misc#path#encode(path) " {{{1 + " Encode a pathname so it can be used as a filename. This uses URL encoding + " to encode special characters. + 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 + + +function! xolox#easytags#misc#path#decode(encoded_path) " {{{1 + " Decode a pathname previously encoded with `xolox#easytags#misc#path#encode()`. + return substitute(a:encoded_path, '%\(\x\x\?\)', '\=nr2char("0x" . submatch(1))', 'g') +endfunction + +" xolox#easytags#misc#path#equals(a, b) - Check whether two pathnames point to the same file. {{{1 + +if s:windows_compatible + function! xolox#easytags#misc#path#equals(a, b) + return a:a ==? a:b || xolox#easytags#misc#path#absolute(a:a) ==? xolox#easytags#misc#path#absolute(a:b) + endfunction +else + function! xolox#easytags#misc#path#equals(a, b) + return a:a ==# a:b || xolox#easytags#misc#path#absolute(a:a) ==# xolox#easytags#misc#path#absolute(a:b) + endfunction +endif + +function! xolox#easytags#misc#path#is_relative(path) " {{{1 + " Returns true (1) when the pathname given as the first argument is + " relative, false (0) otherwise. + if a:path =~ '^\w\+://' + return 0 + elseif s:windows_compatible + return a:path !~ '^\(\w:\|[\\/]\)' + else + return a:path !~ '^/' + endif +endfunction + +function! xolox#easytags#misc#path#tempdir() " {{{1 + " Create a temporary directory and return the pathname of the directory. + if !exists('s:tempdir_counter') + let s:tempdir_counter = 1 + endif + if exists('*mkdir') + if s:windows_compatible + let template = $TMP . '\vim_tempdir_' + elseif filewritable('/tmp') == 2 + let template = '/tmp/vim_tempdir_' + endif + endif + if !exists('template') + throw "xolox#easytags#misc#path#tempdir() hasn't been implemented on your platform!" + endif + while 1 + let directory = template . s:tempdir_counter + try + call mkdir(directory, '', 0700) + return directory + catch /\/ + " Keep looking for a non-existing directory. + endtry + let s:tempdir_counter += 1 + endwhile +endfunction + +" vim: ts=2 sw=2 et diff --git a/autoload/xolox/easytags/misc/str.vim b/autoload/xolox/easytags/misc/str.vim new file mode 100644 index 0000000..7eba730 --- /dev/null +++ b/autoload/xolox/easytags/misc/str.vim @@ -0,0 +1,24 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + +" String handling. +" +" Author: Peter Odding +" Last Change: May 19, 2013 +" URL: http://peterodding.com/code/vim/misc/ + +function! xolox#easytags#misc#str#compact(s) + " Compact whitespace in the string given as the first argument. + return join(split(a:s), " ") +endfunction + +function! xolox#easytags#misc#str#trim(s) + " Trim all whitespace from the start and end of the string given as the + " first argument. + return substitute(a:s, '^\_s*\(.\{-}\)\_s*$', '\1', '') +endfunction + +" vim: ts=2 sw=2 et diff --git a/autoload/xolox/easytags/misc/timer.vim b/autoload/xolox/easytags/misc/timer.vim new file mode 100644 index 0000000..0cb17cb --- /dev/null +++ b/autoload/xolox/easytags/misc/timer.vim @@ -0,0 +1,109 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + +" Timing of long during operations. +" +" Author: Peter Odding +" Last Change: May 20, 2013 +" URL: http://peterodding.com/code/vim/misc/ + +if !exists('g:timer_enabled') + let g:timer_enabled = 0 +endif + +if !exists('g:timer_verbosity') + let g:timer_verbosity = 1 +endif + +let s:has_reltime = has('reltime') + +function! xolox#easytags#misc#timer#start() " {{{1 + " Start a timer. This returns a list which can later be passed to + " `xolox#easytags#misc#timer#stop()`. + return s:has_reltime ? reltime() : [localtime()] +endfunction + +function! xolox#easytags#misc#timer#stop(...) " {{{1 + " Show a formatted debugging message to the user, if the user has enabled + " increased verbosity by setting Vim's ['verbose'] [verbose] option to one + " (1) or higher. + " + " This function has the same argument handling as Vim's [printf()] [printf] + " function with one difference: At the point where you want the elapsed time + " to be embedded, you write `%s` and you pass the list returned by + " `xolox#easytags#misc#timer#start()` as an argument. + " + " [verbose]: http://vimdoc.sourceforge.net/htmldoc/options.html#'verbose' + " [printf]: http://vimdoc.sourceforge.net/htmldoc/eval.html#printf() + if (g:timer_enabled || &verbose >= g:timer_verbosity) + call call('xolox#easytags#misc#msg#info', map(copy(a:000), 's:convert_value(v:val)')) + endif +endfunction + +function! xolox#easytags#misc#timer#force(...) " {{{1 + " Show a formatted message to the user. This function has the same argument + " handling as Vim's [printf()] [printf] function with one difference: At the + " point where you want the elapsed time to be embedded, you write `%s` and + " you pass the list returned by `xolox#easytags#misc#timer#start()` as an argument. + call call('xolox#easytags#misc#msg#info', map(copy(a:000), 's:convert_value(v:val)')) +endfunction + +function! s:convert_value(value) " {{{1 + if type(a:value) != type([]) + return a:value + elseif !empty(a:value) + if s:has_reltime + let ts = xolox#easytags#misc#str#trim(reltimestr(reltime(a:value))) + else + let ts = localtime() - a:value[0] + endif + return xolox#easytags#misc#timer#format_timespan(ts) + else + return '?' + endif +endfunction + +" Format number of seconds as human friendly description. + +let s:units = [['day', 60 * 60 * 24], ['hour', 60 * 60], ['minute', 60], ['second', 1]] + +function! xolox#easytags#misc#timer#format_timespan(ts) " {{{1 + " Format a time stamp (a string containing a formatted floating point + " number) into a human friendly format, for example 70 seconds is phrased as + " "1 minute and 10 seconds". + + " Convert timespan to integer. + let seconds = a:ts + 0 + + " Fast common case with extra precision from reltime(). + if seconds < 5 + let extract = matchstr(a:ts, '^\d\+\(\.0*[1-9][1-9]\?\)\?') + if extract =~ '[123456789]' + return extract . ' second' . (extract != '1' ? 's' : '') + endif + endif + + " Generic but slow code. + let result = [] + for [name, size] in s:units + if seconds >= size + let counter = seconds / size + let seconds = seconds % size + let suffix = counter != 1 ? 's' : '' + call add(result, printf('%i %s%s', counter, name, suffix)) + endif + endfor + + " Format the resulting text? + if len(result) == 1 + return result[0] + else + return join(result[0:-2], ', ') . ' and ' . result[-1] + endif + +endfunction + +" vim: ts=2 sw=2 et diff --git a/plugin/easytags.vim b/plugin/easytags.vim index 64361a7..dfdd63f 100644 --- a/plugin/easytags.vim +++ b/plugin/easytags.vim @@ -1,3 +1,9 @@ +" This Vim script was modified by a Python script that I use to manage the +" inclusion of miscellaneous functions in the plug-ins that I publish to Vim +" Online and GitHub. Please don't edit this file, instead make your changes on +" the 'dev' branch of the git repository (thanks!). This file was generated on +" May 23, 2013 at 20:08. + " Vim plug-in " Author: Peter Odding " Last Change: May 13, 2013 @@ -15,7 +21,7 @@ endif " Configuration defaults and initialization. {{{1 if !exists('g:easytags_file') - if xolox#misc#os#is_win() + if xolox#easytags#misc#os#is_win() let g:easytags_file = '~\_vimtags' else let g:easytags_file = '~/.vimtags' @@ -54,9 +60,9 @@ function! s:InitEasyTags(version) if exists('g:easytags_cmd') && s:CheckCtags(g:easytags_cmd, a:version) return 1 endif - if xolox#misc#os#is_win() + if xolox#easytags#misc#os#is_win() " FIXME The code below that searches the $PATH is not used on Windows at - " the moment because xolox#misc#path#which() generally produces absolute + " the moment because xolox#easytags#misc#path#which() generally produces absolute " paths and on Windows these absolute paths tend to contain spaces which " makes xolox#shell#execute_with_dll() fail. I've tried quoting the " program name with double quotes but it fails just the same (it works @@ -81,7 +87,7 @@ function! s:InitEasyTags(version) " some frustration the plug-in will search the path and consider every " possible location, meaning that as long as Exuberant Ctags is installed " in the $PATH the plug-in should find it automatically. - for program in xolox#misc#path#which('exuberant-ctags', 'ctags-exuberant', 'ctags', 'exctags') + for program in xolox#easytags#misc#path#which('exuberant-ctags', 'ctags-exuberant', 'ctags', 'exctags') if s:CheckCtags(program, a:version) let g:easytags_cmd = program return 1 @@ -96,7 +102,7 @@ function! s:CheckCtags(name, version) " --list-languages option (and more). if executable(a:name) let command = a:name . ' --version' - let result = xolox#misc#os#exec({'command': command, 'check': 0}) + let result = xolox#easytags#misc#os#exec({'command': command, 'check': 0}) if result['exit_code'] == 0 let pattern = 'Exuberant Ctags \zs\(\d\+\(\.\d\+\)*\|Development\)' let g:easytags_ctags_version = matchstr(result['stdout'][0], pattern) -- cgit v1.2.3