aboutsummaryrefslogtreecommitdiffstats
path: root/autoload
diff options
context:
space:
mode:
Diffstat (limited to 'autoload')
-rw-r--r--autoload/xolox/misc/buffer.vim51
-rw-r--r--autoload/xolox/misc/compat.vim23
-rw-r--r--autoload/xolox/misc/complete.vim18
-rw-r--r--autoload/xolox/misc/escape.vim46
-rw-r--r--autoload/xolox/misc/list.vim49
-rw-r--r--autoload/xolox/misc/msg.vim83
-rw-r--r--autoload/xolox/misc/open.vim70
-rw-r--r--autoload/xolox/misc/option.vim84
-rw-r--r--autoload/xolox/misc/os.vim30
-rw-r--r--autoload/xolox/misc/path.vim197
-rw-r--r--autoload/xolox/misc/str.vim12
-rw-r--r--autoload/xolox/misc/timer.vim85
12 files changed, 748 insertions, 0 deletions
diff --git a/autoload/xolox/misc/buffer.vim b/autoload/xolox/misc/buffer.vim
new file mode 100644
index 0000000..3597cc2
--- /dev/null
+++ b/autoload/xolox/misc/buffer.vim
@@ -0,0 +1,51 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: April 18, 2013
+" URL: http://peterodding.com/code/vim/misc/
+
+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(...) " {{{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(options['path'])
+ lcd " clear working directory
+ setlocal buftype=nofile bufhidden=hide noswapfile
+ let &l:statusline = '[' . options['name'] . ']'
+ call xolox#misc#buffer#unlock()
+ silent %delete
+endfunction
+
+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() " {{{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/complete.vim b/autoload/xolox/misc/complete.vim
new file mode 100644
index 0000000..2ada676
--- /dev/null
+++ b/autoload/xolox/misc/complete.vim
@@ -0,0 +1,18 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: March 15, 2011
+" URL: http://peterodding.com/code/vim/misc/
+
+" Keyword completion from the current buffer for user defined commands.
+
+function! xolox#misc#complete#keywords(arglead, cmdline, cursorpos)
+ 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/misc/escape.vim b/autoload/xolox/misc/escape.vim
new file mode 100644
index 0000000..1dd1838
--- /dev/null
+++ b/autoload/xolox/misc/escape.vim
@@ -0,0 +1,46 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: November 21, 2011
+" URL: http://peterodding.com/code/vim/misc/
+
+" Convert a string into a :substitute pattern that matches the string literally.
+
+function! xolox#misc#escape#pattern(string)
+ if type(a:string) == type('')
+ let string = escape(a:string, '^$.*\~[]')
+ return substitute(string, '\n', '\\n', 'g')
+ endif
+ return ''
+endfunction
+
+" Convert a string into a :substitute replacement that inserts the string literally.
+
+function! xolox#misc#escape#substitute(string)
+ if type(a:string) == type('')
+ let string = escape(a:string, '\&~%')
+ return substitute(string, '\n', '\\r', 'g')
+ endif
+ return ''
+endfunction
+
+" Convert a string into a quoted command line argument. I was going to add a
+" long rant here about &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 Windows).
+
+function! xolox#misc#escape#shell(string)
+ if xolox#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/misc/list.vim b/autoload/xolox/misc/list.vim
new file mode 100644
index 0000000..ee243d4
--- /dev/null
+++ b/autoload/xolox/misc/list.vim
@@ -0,0 +1,49 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: August 31, 2011
+" URL: http://peterodding.com/code/vim/misc/
+
+" Remove duplicate values from {list} in-place (preserves order).
+
+function! xolox#misc#list#unique(list)
+ call reverse(a:list)
+ call filter(a:list, 'count(a:list, v:val) == 1')
+ return reverse(a:list)
+endfunction
+
+" Binary insertion (more efficient than calling sort() after each insertion).
+
+function! xolox#misc#list#binsert(list, value, ...)
+ 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 <? a:list[mid] : a:value < a:list[mid]
+ return s:binsert_r(a:list, a:low, mid, a:value, a:ignorecase)
+ else
+ return mid
+ endif
+endfunction
+
+if 0
+ " Tests for xolox#misc#list#binsert().
+ let s:list = ['a', 'B', 'e']
+ function! s:test(value, expected)
+ call xolox#misc#list#binsert(s:list, a:value, 1)
+ if s:list != a:expected
+ call xolox#misc#msg#warn("list.vim: Test failed! Expected %s, got %s",
+ \ string(a:expected), string(s:list))
+ endif
+ endfunction
+ call s:test('c', ['a', 'B', 'c', 'e'])
+ call s:test('D', ['a', 'B', 'c', 'D', 'e'])
+ call s:test('f', ['a', 'B', 'c', 'D', 'e', 'f'])
+endif
+
+" vim: ts=2 sw=2 et
diff --git a/autoload/xolox/misc/msg.vim b/autoload/xolox/misc/msg.vim
new file mode 100644
index 0000000..9ba2b7c
--- /dev/null
+++ b/autoload/xolox/misc/msg.vim
@@ -0,0 +1,83 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: March 15, 2011
+" 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
+
+" Show a formatted informational message to the user.
+
+function! xolox#misc#msg#info(...)
+ call s:show_message('title', a:000)
+endfunction
+
+" Show a formatted warning message to the user.
+
+function! xolox#misc#msg#warn(...)
+ call s:show_message('warningmsg', a:000)
+endfunction
+
+" Show a formatted debugging message to the user?
+
+function! xolox#misc#msg#debug(...)
+ if &vbs >= 1
+ call s:show_message('question', a:000)
+ endif
+endfunction
+
+" The implementation of info() and warn().
+
+function! s:show_message(hlgroup, args)
+ 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 | echomsg message
+ 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()
+ 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/misc/open.vim b/autoload/xolox/misc/open.vim
new file mode 100644
index 0000000..1fb24e0
--- /dev/null
+++ b/autoload/xolox/misc/open.vim
@@ -0,0 +1,70 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: November 21, 2011
+" 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#misc#open#file(path, ...)
+ if xolox#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#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#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#misc#open#file')
+endfunction
+
+function! xolox#misc#open#url(url)
+ 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#misc#open#file(url, 'firefox', 'google-chrome')
+endfunction
+
+function! s:handle_error(cmd, output)
+ if v:shell_error
+ let message = "open.vim %s: Failed to execute program! (command line: %s%s)"
+ let output = strtrans(xolox#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/misc/option.vim b/autoload/xolox/misc/option.vim
new file mode 100644
index 0000000..efaf1bc
--- /dev/null
+++ b/autoload/xolox/misc/option.vim
@@ -0,0 +1,84 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: August 31, 2011
+" URL: http://peterodding.com/code/vim/misc/
+
+function! xolox#misc#option#get(name, ...)
+ 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
+
+" Functions to parse multi-valued Vim options like &tags and &runtimepath.
+
+function! xolox#misc#option#split(value)
+ 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#misc#option#join(values)
+ 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#misc#option#split_tags(value)
+ 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#misc#option#join_tags(values)
+ 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#misc#option#eval_tags(value, ...)
+ let pathnames = []
+ let first_only = exists('a:1') && a:1
+ for pattern in xolox#misc#option#split_tags(a:value)
+ " Make buffer relative pathnames absolute.
+ if pattern =~ '^\./'
+ let directory = xolox#misc#escape#substitute(expand('%:p:h'))
+ let pattern = substitute(pattern, '^.\ze/', directory, '')
+ endif
+ " Make working directory relative pathnames absolute.
+ if xolox#misc#path#is_relative(pattern)
+ let pattern = xolox#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 firstonly ? '' : pathnames
+endfunction
+
+" vim: ts=2 sw=2 et
diff --git a/autoload/xolox/misc/os.vim b/autoload/xolox/misc/os.vim
new file mode 100644
index 0000000..451ca57
--- /dev/null
+++ b/autoload/xolox/misc/os.vim
@@ -0,0 +1,30 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: November 24, 2011
+" URL: http://peterodding.com/code/vim/misc/
+
+let g:xolox#misc#os#version = '0.1'
+
+" Check whether Vim is running on Microsoft Windows.
+
+function! xolox#misc#os#is_win()
+ return has('win16') || has('win32') || has('win64')
+endfunction
+
+" Execute an external command (hiding the console on Windows when possible).
+
+function! xolox#misc#os#exec(cmdline, ...)
+ try
+ " Try using my shell.vim plug-in.
+ return call('xolox#shell#execute', [a:cmdline, 1] + a:000)
+ catch /^Vim\%((\a\+)\)\=:E117/
+ " Fall back to system() when we get an "unknown function" error.
+ let output = call('system', [a:cmdline] + a:000)
+ if v:shell_error
+ throw printf("os.vim %s: Command %s failed: %s", g:xolox#misc#os#version, a:cmdline, xolox#misc#str#trim(output))
+ endif
+ return split(output, "\n")
+ endtry
+endfunction
+
+" vim: ts=2 sw=2 et
diff --git a/autoload/xolox/misc/path.vim b/autoload/xolox/misc/path.vim
new file mode 100644
index 0000000..67ef8d8
--- /dev/null
+++ b/autoload/xolox/misc/path.vim
@@ -0,0 +1,197 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: April 22, 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(...) " {{{1
+ " Scan the executable search path for programs.
+ let extensions = s:windows_compatible ? split($PATHEXT, ';') : ['']
+ let matches = []
+ let checked = {}
+ for directory in split($PATH, s:windows_compatible ? ';' : ':')
+ let directory = xolox#misc#path#absolute(directory)
+ if !has_key(checked, directory)
+ if isdirectory(directory)
+ for program in a:000
+ for extension in extensions
+ let path = xolox#misc#path#merge(directory, program . extension)
+ if executable(path)
+ call add(matches, path)
+ endif
+ endfor
+ endfor
+ endif
+ let checked[directory] = 1
+ endif
+ endfor
+ return matches
+endfunction
+
+function! xolox#misc#path#split(path) " {{{1
+ " Split a pathname into a list of path components.
+ if type(a:path) == type('')
+ if s:windows_compatible
+ return split(a:path, '[\/]\+')
+ else
+ let absolute = (a:path =~ '^/')
+ let segments = split(a:path, '/\+')
+ return absolute ? insert(segments, '/') : segments
+ endif
+ endif
+ return []
+endfunction
+
+function! xolox#misc#path#join(parts) " {{{1
+ " Join a list of path components into a pathname.
+ if type(a:parts) == type([])
+ if !s:windows_compatible && a:parts[0] == '/'
+ return join(a:parts, '/')[1 : -1]
+ else
+ return join(a:parts, '/')
+ endif
+ endif
+ return ''
+endfunction
+
+function! xolox#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 = fnamemodify(a:path, ':p')
+ " resolve() doesn't work when there's a trailing path separator.
+ if path =~ '/$'
+ let stripped_slash = 1
+ let path = substitute(path, '/$', '', '')
+ endif
+ let path = resolve(path)
+ " Restore the path separator after calling resolve().
+ if exists('stripped_slash') && path !~ '/$'
+ let path .= '/'
+ endif
+ return path
+ endif
+ return ''
+endfunction
+
+function! xolox#misc#path#relative(path, base) " {{{1
+ " Make an absolute pathname relative.
+ let path = xolox#misc#path#split(a:path)
+ let base = xolox#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#misc#path#join(distance + path)
+endfunction
+
+
+function! xolox#misc#path#merge(parent, child, ...) " {{{1
+ " Join a directory and filename into a single pathname.
+ " TODO Use isabs()!
+ if type(a:parent) == type('') && type(a:child) == type('')
+ 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#misc#path#commonprefix(paths) " {{{1
+ " Find the common prefix of path components in a list of pathnames.
+ let common = xolox#misc#path#split(a:paths[0])
+ for path in a:paths
+ let index = 0
+ for segment in xolox#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#misc#path#join(common)
+endfunction
+
+function! xolox#misc#path#encode(path) " {{{1
+ " Encode a pathname so it can be used as a filename.
+ 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#misc#path#decode(encoded_path) " {{{1
+ " Decode a pathname previously encoded with xolox#misc#path#encode().
+ return substitute(a:encoded_path, '%\(\x\x\?\)', '\=nr2char("0x" . submatch(1))', 'g')
+endfunction
+
+" xolox#misc#path#equals(a, b) {{{1
+" Check whether two pathnames point to the same file.
+
+if s:windows_compatible
+ function! xolox#misc#path#equals(a, b)
+ return a:a ==? a:b || xolox#misc#path#absolute(a:a) ==? xolox#misc#path#absolute(a:b)
+ endfunction
+else
+ function! xolox#misc#path#equals(a, b)
+ return a:a ==# a:b || xolox#misc#path#absolute(a:a) ==# xolox#misc#path#absolute(a:b)
+ endfunction
+endif
+
+function! xolox#misc#path#is_relative(path) " {{{1
+ " Check whether a path is relative.
+ if a:path =~ '^\w\+://'
+ return 0
+ elseif s:windows_compatible
+ return a:path !~ '^\(\w:\|[\\/]\)'
+ else
+ return a:path !~ '^/'
+ endif
+endfunction
+
+function! xolox#misc#path#tempdir() " {{{1
+ " Create a temporary directory and return the path.
+ 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#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 /\<E739\>/
+ " 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/misc/str.vim b/autoload/xolox/misc/str.vim
new file mode 100644
index 0000000..74a05aa
--- /dev/null
+++ b/autoload/xolox/misc/str.vim
@@ -0,0 +1,12 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: June 14, 2011
+" URL: http://peterodding.com/code/vim/misc/
+
+" Trim whitespace from start and end of string.
+
+function! xolox#misc#str#trim(s)
+ return substitute(a:s, '^\_s*\(.\{-}\)\_s*$', '\1', '')
+endfunction
+
+" vim: ts=2 sw=2 et
diff --git a/autoload/xolox/misc/timer.vim b/autoload/xolox/misc/timer.vim
new file mode 100644
index 0000000..151972d
--- /dev/null
+++ b/autoload/xolox/misc/timer.vim
@@ -0,0 +1,85 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: March 15, 2011
+" 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')
+
+" Start a timer.
+
+function! xolox#misc#timer#start()
+ if g:timer_enabled || &verbose >= g:timer_verbosity
+ return s:has_reltime ? reltime() : [localtime()]
+ endif
+ return []
+endfunction
+
+" Stop a timer and print the elapsed time (only if the user is interested).
+
+function! xolox#misc#timer#stop(...)
+ if (g:timer_enabled || &verbose >= g:timer_verbosity)
+ call call('xolox#misc#msg#info', map(copy(a:000), 's:convert_value(v:val)'))
+ endif
+endfunction
+
+function! s:convert_value(value)
+ if type(a:value) != type([])
+ return a:value
+ elseif !empty(a:value)
+ if s:has_reltime
+ let ts = xolox#misc#str#trim(reltimestr(reltime(a:value)))
+ else
+ let ts = localtime() - a:value[0]
+ endif
+ return xolox#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#misc#timer#format_timespan(ts)
+
+ " 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