From a7ed49ed589cfe5f84bfeda317d03a874002e1a9 Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sun, 28 Apr 2013 15:08:19 +0200 Subject: Change the repository layout to that of a proper Vim plug-in --- README.md | 39 ++++++-- autoload/xolox/misc/buffer.vim | 51 ++++++++++ autoload/xolox/misc/compat.vim | 23 +++++ autoload/xolox/misc/complete.vim | 18 ++++ autoload/xolox/misc/escape.vim | 46 +++++++++ autoload/xolox/misc/list.vim | 49 ++++++++++ autoload/xolox/misc/msg.vim | 83 ++++++++++++++++ autoload/xolox/misc/open.vim | 70 ++++++++++++++ autoload/xolox/misc/option.vim | 84 ++++++++++++++++ autoload/xolox/misc/os.vim | 30 ++++++ autoload/xolox/misc/path.vim | 197 ++++++++++++++++++++++++++++++++++++++ autoload/xolox/misc/str.vim | 12 +++ autoload/xolox/misc/timer.vim | 85 +++++++++++++++++ buffer.vim | 51 ---------- compat.vim | 23 ----- complete.vim | 18 ---- escape.vim | 46 --------- list.vim | 49 ---------- msg.vim | 83 ---------------- open.vim | 70 -------------- option.vim | 84 ---------------- os.vim | 30 ------ path.vim | 201 --------------------------------------- str.vim | 12 --- timer.vim | 85 ----------------- 25 files changed, 777 insertions(+), 762 deletions(-) create mode 100644 autoload/xolox/misc/buffer.vim create mode 100644 autoload/xolox/misc/compat.vim create mode 100644 autoload/xolox/misc/complete.vim create mode 100644 autoload/xolox/misc/escape.vim create mode 100644 autoload/xolox/misc/list.vim create mode 100644 autoload/xolox/misc/msg.vim create mode 100644 autoload/xolox/misc/open.vim create mode 100644 autoload/xolox/misc/option.vim create mode 100644 autoload/xolox/misc/os.vim create mode 100644 autoload/xolox/misc/path.vim create mode 100644 autoload/xolox/misc/str.vim create mode 100644 autoload/xolox/misc/timer.vim delete mode 100644 buffer.vim delete mode 100644 compat.vim delete mode 100644 complete.vim delete mode 100644 escape.vim delete mode 100644 list.vim delete mode 100644 msg.vim delete mode 100644 open.vim delete mode 100644 option.vim delete mode 100644 os.vim delete mode 100644 path.vim delete mode 100644 str.vim delete mode 100644 timer.vim diff --git a/README.md b/README.md index f375fe6..685d9c6 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,41 @@ # Miscellaneous auto-load Vim scripts -The git repository at [github.com/xolox/vim-misc] [repository] contains Vim scripts that are used by most of the [Vim plug-ins I've written] [plugins] yet don't really belong with any single one. I include this repository as a subdirectory of my plug-in repositories using the following commands: +The git repository at [github.com/xolox/vim-misc] [repository] contains Vim scripts that are used by most of the [Vim plug-ins I've written] [plugins] yet don't really belong with any single one of the plug-ins. Basically it's an extended standard library of Vim script functions that I wrote during the development of my Vim plug-ins. - $ git remote add -f vim-misc https://github.com/xolox/vim-misc.git - $ git merge -s ours --no-commit vim-misc/master - $ git read-tree --prefix=autoload/xolox/misc/ -u vim-misc/master - $ git commit -m "Merge vim-misc repository as subdirectory" +The miscellaneous scripts are bundled with each of my plug-ins using git merges, so that a repository checkout of a plug-in contains everything that's needed to get started. This means the git repository of the miscellaneous scripts is only used to track changes in a central, public place. -The above trick is called the [subtree merge strategy] [merge-strategy]. To update a plug-in repository to the latest version of the miscellaneous auto-load scripts I execute the following command: +## How does it work? - $ git pull -s subtree vim-misc master +Here's how I merge the miscellaneous scripts into a Vim plug-in repository: + +1. Let git know about the `vim-misc` repository by adding the remote GitHub repository: + + git remote add -f vim-misc https://github.com/xolox/vim-misc.git + +2. Merge the two directory trees without clobbering the `README.md` and/or `.gitignore` files, thanks to the selected merge strategy and options: + + git checkout master + git merge --no-commit -s recursive -X ours vim-misc/master + git commit -m "Merge vim-misc repository as overlay" + +3. While steps 1 and 2 need to be done only once for a given repository, the following commands are needed every time I want to pull and merge the latest changes: + + git checkout master + git fetch vim-misc master + git merge --no-commit -s recursive -X ours vim-misc/master + git commit -m "Merged changes to miscellaneous scripts" ## Why make things so complex? I came up with this solution after multiple years of back and forth between Vim Online users, the GitHub crowd and my own sanity: -1. When I started publishing my first Vim plug-ins I would prepare ZIP archives for Vim Online using makefiles. The makefiles would make sure the miscellaneous scripts were included in the uploaded distributions. This had two disadvantages: It lost git history and the repositories on GitHub were not usable out of the box, so [I got complaints from GitHub (Pathogen) users] [github-complaints]. +1. When I started publishing my first Vim plug-ins (in June 2010) I would prepare ZIP archives for Vim Online using makefiles. The makefiles would make sure the miscellaneous scripts were included in the uploaded distributions. This had two disadvantages: It lost git history and the repositories on GitHub were not usable out of the box, so [I got complaints from GitHub (Pathogen) users] [github-complaints]. + +2. My second attempt to solve the problem used git submodules which seemed like the ideal solution until I actually started using them in March 2011: Submodules are not initialized during a normal `git clone`, you need to use `git clone --recursive` instead but Vim plug-in managers like [Pathogen] [pathogen] and [Vundle] [vundle] don't do this (at least [they didn't when I tried] [vundle-discussion]) so people would end up with broken checkouts. -2. My second attempt to solve the problem used git submodules which seemed like the ideal solution until I actually started doing it. Submodules are not initialized during a normal `git clone`, you need to use `git clone --recursive` instead but Vim plug-in managers like [Pathogen] [pathogen] and [Vundle] [vundle] don't do this (at least [they didn't when I tried] [vundle-discussion]) so people would end up with broken checkouts. +3. After finding out that git submodules were not going to solve my problems I searched for other inclusion strategies supported by git. After a while I came upon the [subtree merge strategy] [merge-strategy] which I started using in May 2011 and stuck with for more than two years (because it generally worked fine and seemed quite robust). -3. After finding out that git submodules were not going to solve my problems I searched for other inclusion strategies supported by git. After a while I came upon the [subtree merge strategy] [merge-strategy] which I have been using for more than two years now. +4. In April 2013 the flat layout of the repository started bothering me because it broke my personal workflow, so I changed it to the proper directory layout of a Vim plug-in. Why did it break my workflow? Because I couldn't get my [vim-reload] [reload] plug-in to properly reload miscellaneous scripts without nasty hacks. Note to self: [Dropbox does not respect symbolic links] [dropbox-vote-350] and Vim doesn't like them either ([E746] [E746]). ## Compatibility issues @@ -39,11 +55,14 @@ This software is licensed under the [MIT license] [mit]. © 2013 Peter Odding <>. +[dropbox-vote-350]: https://www.dropbox.com/votebox/350/preserve-implement-symlink-behaviour +[E746]: http://vimdoc.sourceforge.net/htmldoc/eval.html#E746 [github-complaints]: https://github.com/xolox/vim-easytags/issues/1 [merge-strategy]: http://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html [mit]: http://en.wikipedia.org/wiki/MIT_License [pathogen]: http://www.vim.org/scripts/script.php?script_id=2332 [plugins]: http://peterodding.com/code/vim/ +[reload]: http://peterodding.com/code/vim/reload [repository]: https://github.com/xolox/vim-misc [vundle-discussion]: https://github.com/gmarik/vundle/pull/41 [vundle]: https://github.com/gmarik/vundle diff --git a/autoload/xolox/misc/buffer.vim b/autoload/xolox/misc/buffer.vim 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 +" 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 +" 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(''), ':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 +" 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 +" 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 +" 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 +" 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 +" 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 +" 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 +" 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 +" 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 /\/ + " 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 +" 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 +" 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 diff --git a/buffer.vim b/buffer.vim deleted file mode 100644 index 3597cc2..0000000 --- a/buffer.vim +++ /dev/null @@ -1,51 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" 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/compat.vim b/compat.vim deleted file mode 100644 index 83d00a0..0000000 --- a/compat.vim +++ /dev/null @@ -1,23 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" 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(''), ':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/complete.vim b/complete.vim deleted file mode 100644 index 2ada676..0000000 --- a/complete.vim +++ /dev/null @@ -1,18 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" 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/escape.vim b/escape.vim deleted file mode 100644 index 1dd1838..0000000 --- a/escape.vim +++ /dev/null @@ -1,46 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" 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/list.vim b/list.vim deleted file mode 100644 index ee243d4..0000000 --- a/list.vim +++ /dev/null @@ -1,49 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" 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 -" 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/open.vim b/open.vim deleted file mode 100644 index 1fb24e0..0000000 --- a/open.vim +++ /dev/null @@ -1,70 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" 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/option.vim b/option.vim deleted file mode 100644 index efaf1bc..0000000 --- a/option.vim +++ /dev/null @@ -1,84 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" 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/os.vim b/os.vim deleted file mode 100644 index 451ca57..0000000 --- a/os.vim +++ /dev/null @@ -1,30 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" 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/path.vim b/path.vim deleted file mode 100644 index 6f8fe44..0000000 --- a/path.vim +++ /dev/null @@ -1,201 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" Last Change: April 18, 2013 -" URL: http://peterodding.com/code/vim/misc/ - -let s:windows_compatible = has('win32') || has('win64') -let s:mac_os_x_compatible = has('macunix') - -function! xolox#misc#path#which(...) - let extensions = s:windows_compatible ? split($PATHEXT, ';') : [''] - 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 - -" Split a pathname into a list of path components. - -function! xolox#misc#path#split(path) - 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 - -" Join a list of path components into a pathname. - -function! xolox#misc#path#join(parts) - 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 - -" Canonicalize and resolve a pathname. - -function! xolox#misc#path#absolute(path) - 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 - -" Make an absolute pathname relative. - -function! xolox#misc#path#relative(path, base) - 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 - -" Join a directory and filename into a single pathname. - -function! xolox#misc#path#merge(parent, child, ...) - " 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 - -" Find the common prefix of path components in a list of pathnames. - -function! xolox#misc#path#commonprefix(paths) - 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 - -" Encode a pathname so it can be used as a filename. - -function! xolox#misc#path#encode(path) - 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 - -" Decode a pathname previously encoded with xolox#misc#path#encode(). - -function! xolox#misc#path#decode(encoded_path) - return substitute(a:encoded_path, '%\(\x\x\?\)', '\=nr2char("0x" . submatch(1))', 'g') -endfunction - -" 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 - -" Check whether a path is relative. - -function! xolox#misc#path#is_relative(path) - if a:path =~ '^\w\+://' - return 0 - elseif s:windows_compatible - return a:path !~ '^\(\w:\|[\\/]\)' - else - return a:path !~ '^/' - endif -endfunction - -" Create a temporary directory and return the path. - -function! xolox#misc#path#tempdir() - 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 /\/ - " Keep looking for a non-existing directory. - endtry - let s:tempdir_counter += 1 - endwhile -endfunction - -" vim: ts=2 sw=2 et diff --git a/str.vim b/str.vim deleted file mode 100644 index 74a05aa..0000000 --- a/str.vim +++ /dev/null @@ -1,12 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" 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/timer.vim b/timer.vim deleted file mode 100644 index 151972d..0000000 --- a/timer.vim +++ /dev/null @@ -1,85 +0,0 @@ -" Vim auto-load script -" Author: Peter Odding -" 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 -- cgit v1.2.3