[nvim] update minpac

This commit is contained in:
Julien Rabier 2020-11-22 12:45:18 +01:00
parent fe7f4bf07f
commit 112992ebec
23 changed files with 1112 additions and 552 deletions

View File

@ -1,4 +1,3 @@
dist: trusty
language: generic
sudo: false
@ -15,12 +14,16 @@ env:
matrix:
include:
- os: linux
dist: focal
env: VIM=vim VIMPROG=$OPT/bin/$VIM
- os: linux
dist: focal
env: VIM=nvim VIMPROG=$VIM
- os: osx
osx_image: xcode12
env: VIM=vim PACKAGE=vim VIMPROG=$VIM
- os: osx
osx_image: xcode12
env: VIM=nvim PACKAGE=neovim VIMPROG=$VIM

View File

@ -38,10 +38,16 @@ Plugins installed under `pack/*/start/` are automatically added to the `'runtime
### Windows
Vim:
```cmd
cd /d %USERPROFILE%
git clone https://github.com/k-takata/minpac.git ^
vimfiles\pack\minpac\opt\minpac
git clone https://github.com/k-takata/minpac.git %USERPROFILE%\vimfiles\pack\minpac\opt\minpac
```
Neovim:
```cmd
git clone https://github.com/k-takata/minpac.git %LOCALAPPDATA%\nvim\pack\minpac\opt\minpac
```
### Linux, macOS
@ -49,15 +55,13 @@ git clone https://github.com/k-takata/minpac.git ^
Vim:
```sh
git clone https://github.com/k-takata/minpac.git \
~/.vim/pack/minpac/opt/minpac
git clone https://github.com/k-takata/minpac.git ~/.vim/pack/minpac/opt/minpac
```
Neovim (use `$XDG_CONFIG_HOME` in place of `~/.config` if set on your system):
```sh
git clone https://github.com/k-takata/minpac.git \
~/.config/nvim/pack/minpac/opt/minpac
git clone https://github.com/k-takata/minpac.git ~/.config/nvim/pack/minpac/opt/minpac
```
### Sample .vimrc
@ -65,6 +69,15 @@ git clone https://github.com/k-takata/minpac.git \
#### Basic sample
```vim
" Normally this if-block is not needed, because `:set nocp` is done
" automatically when .vimrc is found. However, this might be useful
" when you execute `vim -u .vimrc` from the command line.
if &compatible
" `:set nocp` has many side effects. Therefore this should be done
" only when 'compatible' is set.
set nocompatible
endif
packadd minpac
call minpac#init()
@ -80,6 +93,8 @@ call minpac#add('vim-jp/syntax-vim-ex')
"packloadall
```
Minpac itself requires 'compatible' to be unset. However, the `if &compatible`-block is optional.
#### Customizing 'packpath'
If you want to use `.vim` directory instead of `vimfiles` even on Windows,
@ -101,7 +116,7 @@ You can write a .vimrc which can be also used even if minpac is not installed.
" Try to load minpac.
packadd minpac
if !exists('*minpac#init')
if !exists('g:loaded_minpac')
" minpac is not available.
" Settings for plugin-less environment.
@ -124,49 +139,9 @@ endif
#### Load minpac on demand
Very interestingly, minpac doesn't need to be loaded every time. Unlike other plugin managers, it is needed only when updating, installing or cleaning the plugins. This is because minpac itself doesn't handle the runtime path.
Very interestingly, minpac doesn't need to be loaded every time when you execute Vim. Unlike other plugin managers, it is needed only when updating, installing or cleaning the plugins. This is because minpac itself doesn't handle the runtime path.
You can define a user command to load minpac, reload .vimrc to register the information of plugins, then call `minpac#update()`, `minpac#clean()` or `minpac#status()`.
```vim
" For a paranoia.
" Normally `:set nocp` is not needed, because it is done automatically
" when .vimrc is found.
if &compatible
" `:set nocp` has many side effects. Therefore this should be done
" only when 'compatible' is set.
set nocompatible
endif
if exists('*minpac#init')
" minpac is loaded.
call minpac#init()
call minpac#add('k-takata/minpac', {'type': 'opt'})
" Additional plugins here.
call minpac#add('vim-jp/syntax-vim-ex')
...
endif
" Plugin settings here.
...
" Define user commands for updating/cleaning the plugins.
" Each of them loads minpac, reloads .vimrc to register the
" information of plugins, then performs the task.
command! PackUpdate packadd minpac | source $MYVIMRC | call minpac#update('', {'do': 'call minpac#status()'})
command! PackClean packadd minpac | source $MYVIMRC | call minpac#clean()
command! PackStatus packadd minpac | source $MYVIMRC | call minpac#status()
```
Note that your .vimrc must be reloadable to use this. E.g.:
* `:set nocompatible` should not be executed twice to avoid side effects.
* `:function!` should be used to define a user function.
* `:command!` should be used to define a user command.
* `:augroup!` should be used properly to avoid the same autogroups are defined twice.
Another way is defining a function to load minpac and register the information of plugins.
You can define user commands to load minpac, register the information of plugins, then call `minpac#update()`, `minpac#clean()` or `minpac#status()`.
```vim
function! PackInit() abort
@ -187,13 +162,25 @@ endfunction
" Define user commands for updating/cleaning the plugins.
" Each of them calls PackInit() to load minpac and register
" the information of plugins, then performs the task.
command! PackUpdate call PackInit() | call minpac#update('', {'do': 'call minpac#status()'})
command! PackUpdate call PackInit() | call minpac#update()
command! PackClean call PackInit() | call minpac#clean()
command! PackStatus call PackInit() | call minpac#status()
command! PackStatus packadd minpac | call minpac#status()
```
This doesn't reload .vimrc, so the .vimrc doesn't need to be reloadable.
However, if you make it reloadable, you can apply the changes to the .vimrc immediately by executing `:so $MYVIMRC | PackUpdate`.
If you make your .vimrc reloadable, you can reflect the setting of the .vimrc immediately after you edit it by executing `:so $MYVIMRC | PackUpdate`. Or you can define the commands like this:
```vim
command! PackUpdate source $MYVIMRC | call PackInit() | call minpac#update()
command! PackClean source $MYVIMRC | call PackInit() | call minpac#clean()
command! PackStatus packadd minpac | call minpac#status()
```
To make your .vimrc reloadable:
* `:set nocompatible` should not be executed twice to avoid side effects.
* `:function!` should be used to define a user function.
* `:command!` should be used to define a user command.
* `:augroup!` should be used properly to avoid the same autogroups are defined twice.
Sometimes, you may want to open a shell at the directory where a plugin is installed. The following example defines a command to open a terminal window at the directory of a specified plugin. (Requires Vim 8.0.902 or later.)
@ -242,6 +229,8 @@ call minpac#clean()
call minpac#status()
```
Or define commands by yourself as described in the previous section.
### Functions
@ -259,7 +248,10 @@ Initialize minpac.
| `'depth'` | Default clone depth. Default: 1 |
| `'jobs'` | Maximum job numbers. If <= 0, unlimited. Default: 8 |
| `'verbose'` | Verbosity level (0 to 4).<br/>0: Show only important messages.<br/>1: Show the result of each plugin.<br/>2: Show error messages from external commands.<br/>3: Show start/end messages for each plugin.<br/>4: Show debug messages.<br/>Default: 2 |
| `'status_open'` | Default setting for the open option of `minpac#status()`. Default: `'vertical'` |
| `'confirm'` | Show interactive confirmation prompts, such as in `minpac#clean()`.<br/>Default: TRUE |
| `'progress_open'` | Specify how to show the progress of `minpac#update()`.<br/>`'none'`: Do not open the progress window. (Compatible with minpac v2.0.x or earlier.)<br/>`'horizontal'`: Open the progress window by splitting horizontally.<br/>`'vertical'`: Open the progress window by splitting vertically.<br/>`'tab'`: Open the progress window in a new tab.<br/>Default: `'horizontal'` |
| `'status_open'` | Default setting for the open option of `minpac#status()`. Default: `'horizontal'` |
| `'status_auto'` | Specify whether the status window will open automatically after `minpac#update()` is finished.<br/>TRUE: Open the status window automatically, when one or more plugins are updated or installed.<br/>FALSE: Do not open the status window automatically.<br/>Default: FALSE |
All plugins will be installed under the following directories:
@ -284,11 +276,13 @@ Note: Unlike Vundle, a short form without `<github-account>/` is not supported.
|------------|-------------|
| `'name'` | Unique name of the plugin (`plugin_name`). Also used as a local directory name. Default: derived from the repository name. |
| `'type'` | Type of the plugin. `'start'` or `'opt'`. Default: `'start'` |
| `'frozen'` | If 1, the plugin will not be updated automatically. Default: 0 |
| `'frozen'` | If TRUE, the plugin will not be updated automatically. Default: FALSE |
| `'depth'` | If >= 1, it is used as a depth to be cloned. Only effective when install the plugin newly. Default: 1 or specified value by `minpac#init()`. |
| `'branch'` | Used as a branch name to be cloned. Only effective when install the plugin newly. Default: empty |
| `'rev'` | Commit ID, branch name or tag name to be checked out. If this is specified, `'depth'` will be ignored. Default: empty |
| `'do'` | Post-update hook. See [Post-update hooks](#post-update-hooks). Default: empty |
| `'subdir'` | Subdirectory that contains Vim plugin. Default: empty |
| `'pullmethod'` | Specify how to update the plugin.<br/>Empty: Update with `--ff-only` option.<br/>`'autostash'`: Update with `--rebase --autostash` options.<br/>Default: empty |
The `'branch'` and `'rev'` options are slightly different.
The `'branch'` option is used only when the plugin is newly installed. It clones the plugin by `git clone <URL> --depth=<DEPTH> -b <BRANCH>`. This is faster at the installation, but it can be slow if you want to change the branch (by the `'rev'` option) later. This cannot specify a commit ID.
@ -297,6 +291,14 @@ So, if you want to change the branch frequently or want to specify a commit ID,
If you include `*` in `'rev'`, minpac tries to checkout the latest tag name which matches the `'rev'`.
When `'subdir'` is specified, the plugin will be installed as usual (e.g. in `pack/minpac/start/pluginname`), however, another directory is created and a symlink (or a junction on Windows) will be created in it. E.g.:
```
ln -s pack/minpac/start/pluginname/subdir pack/minpac-sub/start/pluginname
```
This way, Vim can load the plugin from its subdirectory.
#### minpac#update([{name}[, {config}]])
@ -323,12 +325,12 @@ Note: This resets the 'more' option temporarily to avoid jobs being interrupted.
Remove all plugins which are not registered, or remove the specified plugin.
`{name}` is a name of a plugin. It can be a unique plugin name (`plugin_name`) or a plugin name with wildcards (`*` and `?` are supported).
`{name}` is a name of a plugin. It can be a unique plugin name (`plugin_name`) or a plugin name with wildcards (`*` and `?` are supported). It can also be a list of plugin names.
If `{name}` is omitted, all plugins under the `minpac` directory will be checked. If unregistered plugins are found, they are listed and a prompt is shown. If you type `y`, they will be removed.
If `{name}` is specified, matched plugins are listed (even they are registered with `minpac#add()`) and a prompt is shown. If you type `y`, they will be removed.
`{name}` can also be a list of plugin names.
When called, matched plugins are listed (even they are registered with `minpac#add()`) and a prompt is shown. If you type `y`, they will be removed.
`{name}` can also be a list of plugin names. If the `'confirm'` option is not |TRUE|, the prompt will not be shown.
#### minpac#getpluginfo({name})
@ -342,7 +344,8 @@ A dictionary with following items will be returned:
| `'name'` | Name of the plugin. |
| `'url'` | URL of the plugin repository. |
| `'dir'` | Local directory of the plugin. |
| `'frozen'` | If 1, the plugin is frozen. |
| `'subdir'` | Subdirectory that contains Vim plugin. |
| `'frozen'` | If TRUE, the plugin is frozen. |
| `'type'` | Type of the plugin. |
| `'depth'` | Depth to be cloned. |
| `'branch'` | Branch name to be cloned. |
@ -367,7 +370,7 @@ If `"NONE"` is specified, package directories are listed instead of plugin direc
`{plugname}` specifies a plugin name. Wildcards can be used. If omitted or an empty string is specified, `"*"` is used.
If `{nameonly}` is 1, plugin (or package) names are listed instead of the direcotries. Default is 0.
If `{nameonly}` is TRUE, plugin (or package) names are listed instead of the direcotries. Default is FALSE.
E.g.:
@ -398,7 +401,7 @@ Otherwise, shows the status of the plugin and commits of last update (if any).
| option | description |
|----------|-------------|
| `'open'` | Specify how to open the status window.<br/>`'vertical'`: Open in vertical split.<br/>`'horizontal'`: Open in horizontal split.<br/>`'tab'`: Open in a new tab.<br/>Default: `'vertical'` or specified value by `minpac#init()`. |
| `'open'` | Specify how to open the status window.<br/>`'vertical'`: Open in vertical split.<br/>`'horizontal'`: Open in horizontal split.<br/>`'tab'`: Open in a new tab.<br/>Default: `'horizontal'` or specified value by `minpac#init()`. |
### Hooks
@ -467,6 +470,13 @@ call minpac#update('', {'do': 'quit'})
### Mappings
List of mappings available only in progress window.
| mapping | description |
|---------|-------------|
|`s` | Open the status window. |
|`q` | Exit the progress window. |
List of mappings available only in status window.
| mapping | description |

View File

@ -3,7 +3,7 @@ version: '1.0.{build}'
shallow_clone: true
environment:
VIMPROG: '%APPVEYOR_BUILD_FOLDER%\vim-kaoriya-win64\gvim.exe'
VIMPROG: '%APPVEYOR_BUILD_FOLDER%\vim-kt-win64\gvim.exe'
AUTH_TOKEN: # for GitHub
secure: wdTzzL05DoG4BZIgqlc3y/Ff50ZOTjfaqMazhdMLcXmxYYbmeCsI9PN01TJCQMaw
API_TOKEN: # for AppVeyor

View File

@ -0,0 +1,147 @@
" ---------------------------------------------------------------------
" minpac: A minimal package manager for Vim 8 (and Neovim)
"
" Maintainer: Ken Takata
" Last Change: 2020-08-22
" License: VIM License
" URL: https://github.com/k-takata/minpac
" ---------------------------------------------------------------------
" Get a list of package/plugin directories.
function! minpac#getpackages(...)
return call("minpac#impl#getpackages", a:000)
endfunction
function! s:ensure_initialization() abort
if !exists('g:minpac#opt')
echohl WarningMsg
echom 'Minpac has not been initialized. Use the default values.'
echohl None
call minpac#init()
endif
endfunction
" Initialize minpac.
function! minpac#init(...) abort
let l:opt = extend(copy(get(a:000, 0, {})),
\ {'dir': '', 'package_name': 'minpac', 'git': 'git', 'depth': 1,
\ 'jobs': 8, 'verbose': 2, 'confirm': v:true,
\ 'progress_open': 'horizontal', 'status_open': 'horizontal',
\ 'status_auto': v:false}, 'keep')
let g:minpac#opt = l:opt
let g:minpac#pluglist = {}
let l:packdir = l:opt.dir
if l:packdir ==# ''
" If 'dir' is not specified, the first directory of 'packpath' is used.
let l:packdir = split(&packpath, ',')[0]
endif
let l:opt.minpac_dir = l:packdir . '/pack/' . l:opt.package_name
let l:opt.minpac_start_dir = l:opt.minpac_dir . '/start'
let l:opt.minpac_opt_dir = l:opt.minpac_dir . '/opt'
" directories for 'subdir'
let l:opt.minpac_dir_sub = l:packdir . '/pack/' . l:opt.package_name . '-sub'
let l:opt.minpac_start_dir_sub = l:opt.minpac_dir_sub . '/start'
let l:opt.minpac_opt_dir_sub = l:opt.minpac_dir_sub . '/opt'
if !isdirectory(l:packdir)
echoerr 'Pack directory not available: ' . l:packdir
return
endif
if !isdirectory(l:opt.minpac_start_dir)
call mkdir(l:opt.minpac_start_dir, 'p')
endif
if !isdirectory(l:opt.minpac_opt_dir)
call mkdir(l:opt.minpac_opt_dir, 'p')
endif
endfunction
" Register the specified plugin.
function! minpac#add(plugname, ...) abort
call s:ensure_initialization()
let l:opt = extend(copy(get(a:000, 0, {})),
\ {'name': '', 'type': 'start', 'depth': g:minpac#opt.depth,
\ 'frozen': v:false, 'branch': '', 'rev': '', 'do': '', 'subdir': '',
\ 'pullmethod': ''
\ }, 'keep')
" URL
if a:plugname =~? '^[-._0-9a-z]\+\/[-._0-9a-z]\+$'
let l:opt.url = 'https://github.com/' . a:plugname . '.git'
else
let l:opt.url = a:plugname
endif
" Name of the plugin
if l:opt.name ==# ''
let l:opt.name = matchstr(l:opt.url, '[/\\]\zs[^/\\]\+$')
let l:opt.name = substitute(l:opt.name, '\C\.git$', '', '')
endif
if l:opt.name ==# ''
echoerr 'Cannot extract the plugin name. (' . a:plugname . ')'
return
endif
" Loading type / Local directory
if l:opt.type ==# 'start'
let l:opt.dir = g:minpac#opt.minpac_start_dir . '/' . l:opt.name
elseif l:opt.type ==# 'opt'
let l:opt.dir = g:minpac#opt.minpac_opt_dir . '/' . l:opt.name
else
echoerr a:plugname . ": Wrong type (must be 'start' or 'opt'): " . l:opt.type
return
endif
" Check pullmethod
if l:opt.pullmethod !=# '' && l:opt.pullmethod !=# 'autostash'
echoerr a:plugname . ": Wrong pullmethod (must be empty or 'autostash'): " . l:opt.pullmethod
return
endif
" Initialize the status
let l:opt.stat = {'errcode': 0, 'lines': [], 'prev_rev': '', 'installed': -1}
" Add to pluglist
let g:minpac#pluglist[l:opt.name] = l:opt
endfunction
" Update all or specified plugin(s).
function! minpac#update(...)
call s:ensure_initialization()
return call("minpac#impl#update", a:000)
endfunction
" Remove plugins that are not registered.
function! minpac#clean(...)
call s:ensure_initialization()
return call("minpac#impl#clean", a:000)
endfunction
function! minpac#status(...)
call s:ensure_initialization()
let l:opt = extend(copy(get(a:000, 0, {})),
\ {'open': g:minpac#opt.status_open}, 'keep')
return minpac#status#get(l:opt)
endfunction
" Get information of specified plugin. Mainly for debugging.
function! minpac#getpluginfo(name)
call s:ensure_initialization()
return g:minpac#pluglist[a:name]
endfunction
" Get a list of plugin information. Mainly for debugging.
function! minpac#getpluglist()
return g:minpac#pluglist
endfunction
" vim: set ts=8 sw=2 et:

View File

@ -0,0 +1,75 @@
" ---------------------------------------------------------------------
" minpac: A minimal package manager for Vim 8 (and Neovim)
"
" Maintainer: Ken Takata
" Last Change: 2020-02-01
" License: VIM License
" URL: https://github.com/k-takata/minpac
" ---------------------------------------------------------------------
function! s:isabsolute(dir) abort
return a:dir =~# '^/' || (has('win32') && a:dir =~? '^\%(\\\|[A-Z]:\)')
endfunction
function! s:get_gitdir(dir) abort
let l:gitdir = a:dir . '/.git'
if isdirectory(l:gitdir)
return l:gitdir
endif
try
let l:line = readfile(l:gitdir)[0]
if l:line =~# '^gitdir: '
let l:gitdir = l:line[8:]
if !s:isabsolute(l:gitdir)
let l:gitdir = a:dir . '/' . l:gitdir
endif
if isdirectory(l:gitdir)
return l:gitdir
endif
endif
catch
endtry
return ''
endfunction
function! minpac#git#get_revision(dir) abort
let l:gitdir = s:get_gitdir(a:dir)
if l:gitdir ==# ''
return v:null
endif
try
let l:line = readfile(l:gitdir . '/HEAD')[0]
if l:line =~# '^ref: '
let l:ref = l:line[5:]
if filereadable(l:gitdir . '/' . l:ref)
return readfile(l:gitdir . '/' . l:ref)[0]
endif
for l:line in readfile(l:gitdir . '/packed-refs')
if l:line =~# ' ' . l:ref
return substitute(l:line, '^\([0-9a-f]*\) ', '\1', '')
endif
endfor
endif
return l:line
catch
endtry
return v:null
endfunction
function! minpac#git#get_branch(dir) abort
let l:gitdir = s:get_gitdir(a:dir)
if l:gitdir ==# ''
return v:null
endif
try
let l:line = readfile(l:gitdir . '/HEAD')[0]
if l:line =~# '^ref: refs/heads/'
return l:line[16:]
endif
return ''
catch
return v:null
endtry
endfunction
" vim: set ts=8 sw=2 et:

View File

@ -2,7 +2,7 @@
" minpac: A minimal package manager for Vim 8 (and Neovim)
"
" Maintainer: Ken Takata
" Last Change: 2018-09-01
" Last Change: 2020-08-22
" License: VIM License
" URL: https://github.com/k-takata/minpac
" ---------------------------------------------------------------------
@ -15,7 +15,7 @@ function! minpac#impl#getpackages(...) abort
let l:packname = get(a:000, 0, '')
let l:packtype = get(a:000, 1, '')
let l:plugname = get(a:000, 2, '')
let l:nameonly = get(a:000, 3, 0)
let l:nameonly = get(a:000, 3, v:false)
if l:packname ==# '' | let l:packname = '*' | endif
if l:packtype ==# '' | let l:packtype = '*' | endif
@ -35,25 +35,42 @@ function! minpac#impl#getpackages(...) abort
endfunction
function! s:echo_verbose(level, msg) abort
function! s:echox_verbose(level, echocmd, type, msg) abort
if g:minpac#opt.verbose >= a:level
echo a:msg
if g:minpac#opt.progress_open ==# 'none'
if a:type ==# 'warning'
echohl WarningMsg
elseif a:type ==# 'error'
echohl ErrorMsg
endif
exec a:echocmd . " '" . substitute(a:msg, "'", "''", "g") . "'"
echohl None
else
call minpac#progress#add_msg(a:type, a:msg)
endif
endif
endfunction
function! s:echom_verbose(level, msg) abort
if g:minpac#opt.verbose >= a:level
echom a:msg
endif
function! s:echo_verbose(level, type, msg) abort
call s:echox_verbose(a:level, 'echo', a:type, a:msg)
endfunction
function! s:echom_verbose(level, type, msg) abort
call s:echox_verbose(a:level, 'echom', a:type, a:msg)
endfunction
function! s:echoerr_verbose(level, msg) abort
call s:echox_verbose(a:level, 'echoerr', 'error', a:msg)
endfunction
if has('win32')
function! s:quote_cmds(cmds) abort
" If space is found, surround the argument with "".
" If space (or brace) is found, surround the argument with "".
" Assuming double quotations are not used elsewhere.
" (Brace needs to be quoted for msys2/git.)
return join(map(a:cmds,
\ {-> (v:val =~# ' ') ? '"' . v:val . '"' : v:val}), ' ')
\ {-> (v:val =~# '[ {]') ? '"' . v:val . '"' : v:val}), ' ')
endfunction
else
function! s:quote_cmds(cmds) abort
@ -67,7 +84,7 @@ function! minpac#impl#system(cmds) abort
let l:out = []
let l:ret = -1
let l:quote_cmds = s:quote_cmds(a:cmds)
call s:echom_verbose(4, 'system: cmds=' . string(l:quote_cmds))
call s:echom_verbose(4, '', 'system: cmds=' . string(l:quote_cmds))
let l:job = minpac#job#start(l:quote_cmds,
\ {'on_stdout': {id, mes, ev -> extend(l:out, mes)}})
if l:job > 0
@ -84,7 +101,7 @@ function! s:exec_plugin_cmd(name, cmd, mes) abort
let l:dir = l:pluginfo.dir
let l:res = minpac#impl#system([g:minpac#opt.git, '-C', l:dir] + a:cmd)
if l:res[0] == 0 && len(l:res[1]) > 0
call s:echom_verbose(4, a:mes . ': ' . l:res[1][0])
call s:echom_verbose(4, '', a:mes . ': ' . l:res[1][0])
return l:res[1][0]
else
" Error
@ -94,6 +111,11 @@ endfunction
" Get the revision of the specified plugin.
function! minpac#impl#get_plugin_revision(name) abort
let l:rev = minpac#git#get_revision(g:minpac#pluglist[a:name].dir)
if l:rev != v:null
call s:echom_verbose(4, '', 'revision: ' . l:rev)
return l:rev
endif
return s:exec_plugin_cmd(a:name, ['rev-parse', 'HEAD'], 'revision')
endfunction
@ -109,6 +131,11 @@ endfunction
" Get the branch name of the specified plugin.
function! s:get_plugin_branch(name) abort
let l:branch = minpac#git#get_branch(g:minpac#pluglist[a:name].dir)
if l:branch != v:null
call s:echom_verbose(4, '', 'branch: ' . l:branch)
return l:branch
endif
return s:exec_plugin_cmd(a:name, ['symbolic-ref', '--short', 'HEAD'], 'branch')
endfunction
@ -125,16 +152,29 @@ function! s:decrement_job_count() abort
endif
" Show the status.
if s:error_plugins != 0
echohl WarningMsg
echom 'Error plugins: ' . s:error_plugins
echohl None
if s:error_plugins + s:updated_plugins + s:installed_plugins > 0
if g:minpac#opt.progress_open !=# 'none'
call s:echom_verbose(1, '', '') " empty line
endif
endif
if s:error_plugins > 0
call s:echom_verbose(1, 'warning', 'Error plugins: ' . s:error_plugins)
else
let l:mes = 'All plugins are up to date.'
if s:updated_plugins > 0 || s:installed_plugins > 0
if s:updated_plugins + s:installed_plugins > 0
let l:mes .= ' (Updated: ' . s:updated_plugins . ', Newly installed: ' . s:installed_plugins . ')'
endif
echom l:mes
call s:echom_verbose(1, '', l:mes)
endif
if g:minpac#opt.progress_open !=# 'none'
call s:echom_verbose(1, '', '(Type "q" to close this window. Type "s" to open the status window.)')
endif
" Open the status window.
if s:updated_plugins + s:installed_plugins > 0
if g:minpac#opt.status_auto
call minpac#status()
endif
endif
" Restore the pager.
@ -177,10 +217,8 @@ function! s:invoke_hook(hooktype, args, hook) abort
execute a:hook
endif
catch
echohl ErrorMsg
echom v:throwpoint
echom v:exception
echohl None
call s:echom_verbose(1, 'error', v:throwpoint)
call s:echom_verbose(1, 'error', v:exception)
finally
if a:hooktype ==# 'post-update'
noautocmd call s:chdir(l:pwd)
@ -211,6 +249,41 @@ function! s:add_rtp(dir) abort
endif
endfunction
if has('win32')
function! s:create_link(target, link) abort
if isdirectory(a:target)
call delete(a:target)
endif
call minpac#impl#system(['cmd.exe', '/c', 'mklink', '/J',
\ substitute(a:link, '/', '\', 'g'),
\ substitute(a:target, '/', '\', 'g')])
endfunction
else
function! s:create_link(target, link) abort
call minpac#impl#system(['ln', '-sf', a:target, a:link])
endfunction
endif
function! s:handle_subdir(pluginfo) abort
if a:pluginfo.type ==# 'start'
let l:workdir = g:minpac#opt.minpac_start_dir_sub
else
let l:workdir = g:minpac#opt.minpac_opt_dir_sub
endif
if !isdirectory(l:workdir)
call mkdir(l:workdir, 'p')
endif
noautocmd let l:pwd = s:chdir(l:workdir)
try
if !isdirectory(a:pluginfo.name)
call s:create_link(a:pluginfo.dir . '/' . a:pluginfo.subdir,
\ a:pluginfo.name)
endif
finally
noautocmd call s:chdir(l:pwd)
endtry
endfunction
function! s:job_exit_cb(id, errcode, event) dict abort
call filter(s:joblist, {-> v:val != a:id})
@ -243,16 +316,14 @@ function! s:job_exit_cb(id, errcode, event) dict abort
let l:rev = s:get_plugin_latest_tag(self.name, l:rev)
if l:rev ==# ''
let s:error_plugins += 1
echohl ErrorMsg
call s:echom_verbose(1, 'Error while updating "' . self.name . '". No tags found.')
echohl None
call s:echom_verbose(1, 'error', 'Error while updating "' . self.name . '". No tags found.')
call s:decrement_job_count()
return
endif
endif
let l:cmd = [g:minpac#opt.git, '-C', l:dir, 'checkout',
\ l:rev, '--']
call s:echom_verbose(3, 'Checking out the revison: ' . self.name
call s:echom_verbose(3, '', 'Checking out the revison: ' . self.name
\ . ': ' . l:rev)
call s:start_job(l:cmd, self.name, self.seq + 1)
return
@ -261,7 +332,7 @@ function! s:job_exit_cb(id, errcode, event) dict abort
" Checked out the branch. Update to the upstream.
let l:cmd = [g:minpac#opt.git, '-C', l:dir, 'merge', '--quiet',
\ '--ff-only', '@{u}']
call s:echom_verbose(3, 'Update to the upstream: ' . self.name)
call s:echom_verbose(3, '', 'Update to the upstream: ' . self.name)
call s:start_job(l:cmd, self.name, self.seq + 1)
return
endif
@ -272,7 +343,7 @@ function! s:job_exit_cb(id, errcode, event) dict abort
" Update git submodule.
let l:cmd = [g:minpac#opt.git, '-C', l:dir, 'submodule', '--quiet',
\ 'update', '--init', '--recursive']
call s:echom_verbose(3, 'Updating submodules: ' . self.name)
call s:echom_verbose(3, '', 'Updating submodules: ' . self.name)
call s:start_job(l:cmd, self.name, self.seq + 1)
return
endif
@ -280,6 +351,10 @@ function! s:job_exit_cb(id, errcode, event) dict abort
call s:generate_helptags(l:dir)
if l:pluginfo.subdir !=# ''
call s:handle_subdir(l:pluginfo)
endif
if has('nvim') && isdirectory(l:dir . '/rplugin')
" Required for :UpdateRemotePlugins.
call s:add_rtp(l:dir)
@ -294,29 +369,26 @@ function! s:job_exit_cb(id, errcode, event) dict abort
if l:pluginfo.stat.installed
if l:updated
let s:updated_plugins += 1
call s:echom_verbose(1, 'Updated: ' . self.name)
call s:echom_verbose(1, '', 'Updated: ' . self.name)
else
call s:echom_verbose(3, 'Already up-to-date: ' . self.name)
call s:echom_verbose(3, '', 'Already up-to-date: ' . self.name)
endif
else
let s:installed_plugins += 1
call s:echom_verbose(1, 'Installed: ' . self.name)
call s:echom_verbose(1, '', 'Installed: ' . self.name)
endif
let l:err = 0
endif
endif
if l:err
let s:error_plugins += 1
echohl ErrorMsg
call s:echom_verbose(1, 'Error while updating "' . self.name . '". Error code: ' . a:errcode)
echohl None
call s:echom_verbose(1, 'error', 'Error while updating "' . self.name . '". Error code: ' . a:errcode)
endif
call s:decrement_job_count()
endfunction
function! s:job_err_cb(id, message, event) dict abort
echohl WarningMsg
let l:mes = copy(a:message)
if len(l:mes) > 0 && l:mes[-1] ==# ''
" Remove the last empty line. It is redundant.
@ -325,9 +397,8 @@ function! s:job_err_cb(id, message, event) dict abort
for l:line in l:mes
let l:line = substitute(l:line, "\t", ' ', 'g')
call add(g:minpac#pluglist[self.name].stat.lines, l:line)
call s:echom_verbose(2, self.name . ': ' . l:line)
call s:echom_verbose(2, 'warning', self.name . ': ' . l:line)
endfor
echohl None
endfunction
function! s:start_job(cmds, name, seq) abort
@ -341,7 +412,7 @@ function! s:start_job(cmds, name, seq) abort
endif
let l:quote_cmds = s:quote_cmds(a:cmds)
call s:echom_verbose(4, 'start_job: cmds=' . string(l:quote_cmds))
call s:echom_verbose(4, '', 'start_job: cmds=' . string(l:quote_cmds))
let l:job = minpac#job#start(l:quote_cmds, {
\ 'on_stderr': function('s:job_err_cb'),
\ 'on_exit': function('s:job_exit_cb'),
@ -350,9 +421,7 @@ function! s:start_job(cmds, name, seq) abort
if l:job > 0
" It worked!
else
echohl ErrorMsg
echom 'Fail to execute: ' . a:cmds[0]
echohl None
call s:echom_verbose(1, 'error', 'Fail to execute: ' . a:cmds[0])
call s:decrement_job_count()
return 1
endif
@ -401,10 +470,43 @@ function! s:check_plugin_status(name) abort
return 2
endfunction
" Check whether the type was changed. If it was changed, rename the directory.
function! s:prepare_plugin_dir(pluginfo) abort
let l:dir = a:pluginfo.dir
if !isdirectory(l:dir)
if a:pluginfo.type ==# 'start'
let l:dirtmp = substitute(l:dir, '/start/\ze[^/]\+$', '/opt/', '')
else
let l:dirtmp = substitute(l:dir, '/opt/\ze[^/]\+$', '/start/', '')
endif
if isdirectory(l:dirtmp)
" The type was changed (start <-> opt).
call rename(l:dirtmp, l:dir)
endif
endif
" Check subdir.
if a:pluginfo.subdir !=# ''
let l:name = a:pluginfo.name
if a:pluginfo.type ==# 'start'
let l:subdir = g:minpac#opt.minpac_start_dir_sub . '/' . l:name
let l:otherdir = g:minpac#opt.minpac_opt_dir_sub . '/' . l:name
else
let l:subdir = g:minpac#opt.minpac_opt_dir_sub . '/' . l:name
let l:otherdir = g:minpac#opt.minpac_start_dir_sub . '/' . l:name
endif
if isdirectory(l:otherdir) && !isdirectory(l:subdir)
" The type was changed (start <-> opt).
call delete(l:otherdir)
call s:handle_subdir(a:pluginfo)
endif
endif
endfunction
" Update a single plugin.
function! s:update_single_plugin(name, force) abort
if !has_key(g:minpac#pluglist, a:name)
echoerr 'Plugin not registered: ' . a:name
call s:echoerr_verbose(1, 'Plugin not registered: ' . a:name)
call s:decrement_job_count()
return 1
endif
@ -417,41 +519,11 @@ function! s:update_single_plugin(name, force) abort
let l:pluginfo.stat.prev_rev = ''
let l:pluginfo.stat.submod = 0
if !isdirectory(l:dir)
if g:minpac#pluglist[a:name].type ==# 'start'
let l:dirtmp = substitute(l:dir, '/start/\ze[^/]\+$', '/opt/', '')
else
let l:dirtmp = substitute(l:dir, '/opt/\ze[^/]\+$', '/start/', '')
endif
if !isdirectory(l:dirtmp)
let l:pluginfo.stat.installed = 0
if l:pluginfo.rev ==# ''
let l:pluginfo.stat.upd_method = 1
else
let l:pluginfo.stat.upd_method = 2
endif
call s:echo_verbose(3, 'Cloning ' . a:name)
let l:cmd = [g:minpac#opt.git, 'clone', '--quiet', l:url, l:dir, '--no-single-branch']
if l:pluginfo.depth > 0 && l:pluginfo.rev ==# ''
let l:cmd += ['--depth=' . l:pluginfo.depth]
endif
if l:pluginfo.branch !=# ''
let l:cmd += ['--branch=' . l:pluginfo.branch]
endif
else
" The type was changed (start <-> opt).
call rename(l:dirtmp, l:dir)
let l:pluginfo.stat.installed = 1
endif
else
call s:prepare_plugin_dir(l:pluginfo)
if isdirectory(l:dir)
let l:pluginfo.stat.installed = 1
endif
if l:pluginfo.stat.installed == 1
if l:pluginfo.frozen && !a:force
call s:echom_verbose(3, 'Skipped: ' . a:name)
call s:echom_verbose(3, '', 'Skipped: ' . a:name)
call s:decrement_job_count()
return 0
endif
@ -460,24 +532,54 @@ function! s:update_single_plugin(name, force) abort
let l:pluginfo.stat.upd_method = l:ret
if l:ret == 0
" No need to update.
call s:echom_verbose(3, 'Already up-to-date: ' . a:name)
call s:echom_verbose(3, '', 'Already up-to-date: ' . a:name)
call s:decrement_job_count()
return 0
elseif l:ret == 1
" Same branch. Update by pull.
call s:echo_verbose(3, 'Updating (pull): ' . a:name)
let l:cmd = [g:minpac#opt.git, '-C', l:dir, 'pull', '--quiet', '--ff-only', '--rebase=false']
call s:echo_verbose(3, '', 'Updating (pull): ' . a:name)
let l:cmd = [g:minpac#opt.git, '-C', l:dir, 'pull', '--quiet']
if l:pluginfo.pullmethod ==# 'autostash'
let l:cmd += ['--rebase', '--autostash']
else
let l:cmd += ['--ff-only', '--rebase=false']
endif
elseif l:ret == 2
" Different branch. Update by fetch & checkout.
call s:echo_verbose(3, 'Updating (fetch): ' . a:name)
call s:echo_verbose(3, '', 'Updating (fetch): ' . a:name)
let l:cmd = [g:minpac#opt.git, '-C', l:dir, 'fetch', '--depth', '999999']
endif
else
let l:pluginfo.stat.installed = 0
if l:pluginfo.rev ==# ''
let l:pluginfo.stat.upd_method = 1
else
let l:pluginfo.stat.upd_method = 2
endif
call s:echo_verbose(3, '', 'Cloning ' . a:name)
let l:cmd = [g:minpac#opt.git, 'clone', '--quiet', l:url, l:dir, '--no-single-branch']
if l:pluginfo.depth > 0 && l:pluginfo.rev ==# ''
let l:cmd += ['--depth=' . l:pluginfo.depth]
endif
if l:pluginfo.branch !=# ''
let l:cmd += ['--branch=' . l:pluginfo.branch]
endif
endif
return s:start_job(l:cmd, a:name, 0)
endfunction
function! s:start_update(names, force, id) abort
for l:name in a:names
call s:update_single_plugin(l:name, a:force)
endfor
endfunction
" Update all or specified plugin(s).
function! minpac#impl#update(...) abort
if g:minpac#opt.progress_open !=# 'none'
call minpac#progress#open(['## minpac update progress ##', ''])
endif
let l:opt = extend(copy(get(a:000, 1, {})),
\ {'do': ''}, 'keep')
@ -491,12 +593,12 @@ function! minpac#impl#update(...) abort
let l:names = a:1
let l:force = 1
else
echoerr 'Wrong parameter type. Must be a String or a List of Strings.'
call s:echoerr_verbose(1, 'Wrong parameter type. Must be a String or a List of Strings.')
return
endif
if s:remain_jobs > 0
echom 'Previous update has not been finished.'
call s:echom_verbose(1, '', 'Previous update has not been finished.')
return
endif
let s:remain_jobs = len(l:names)
@ -505,15 +607,15 @@ function! minpac#impl#update(...) abort
let s:installed_plugins = 0
let s:finish_update_hook = l:opt.do
" Disable the pager temporarily to avoid jobs being interrupted.
if !exists('s:save_more')
let s:save_more = &more
if g:minpac#opt.progress_open ==# 'none'
" Disable the pager temporarily to avoid jobs being interrupted.
if !exists('s:save_more')
let s:save_more = &more
endif
set nomore
endif
set nomore
for l:name in l:names
let ret = s:update_single_plugin(l:name, l:force)
endfor
call timer_start(1, function('s:start_update', [l:names, l:force]))
endfunction
@ -524,9 +626,9 @@ function! s:match_plugin(dir, packname, plugnames) abort
let l:plugname = substitute(l:plugname, '\*', '.*', 'g')
let l:plugname = substitute(l:plugname, '?', '.', 'g')
if l:plugname =~# '/'
let l:pat = '/pack/' . a:packname . '/' . l:plugname . '$'
let l:pat = '/pack/' . a:packname . '\%(-sub\)\?' . '/' . l:plugname . '$'
else
let l:pat = '/pack/' . a:packname . '/\%(start\|opt\)/' . l:plugname . '$'
let l:pat = '/pack/' . a:packname . '\%(-sub\)\?' . '/\%(start\|opt\)/' . l:plugname . '$'
endif
if has('win32')
let l:pat = substitute(l:pat, '/', '[/\\\\]', 'g')
@ -541,6 +643,7 @@ endfunction
" Remove plugins that are not registered.
function! minpac#impl#clean(...) abort
let l:plugin_dirs = minpac#getpackages(g:minpac#opt.package_name)
\ + minpac#getpackages(g:minpac#opt.package_name . '-sub')
if a:0 > 0
" Going to remove only specified plugins.
@ -574,7 +677,8 @@ function! minpac#impl#clean(...) abort
endfor
let l:dir = (len(l:to_remove) > 1) ? 'directories' : 'directory'
if input('Removing the above ' . l:dir . '. [y/N]? ') =~? '^y'
if !g:minpac#opt.confirm || input('Removing the above ' . l:dir . '. [y/N]? ') =~? '^y'
echo "\n"
let err = 0
for l:item in l:to_remove

View File

@ -0,0 +1,74 @@
" ---------------------------------------------------------------------
" minpac: A minimal package manager for Vim 8 (and Neovim)
"
" Maintainer: Ken Takata
" Last Change: 2020-01-28
" License: VIM License
" URL: https://github.com/k-takata/minpac
" ---------------------------------------------------------------------
let s:winid = 0
let s:bufnr = 0
" Add a message to the minpac progress window
function! minpac#progress#add_msg(type, msg) abort
" Goes to the minpac progress window.
if !win_gotoid(s:winid)
echom 'warning: minpac progress window not found.'
return
endif
setlocal modifiable
let l:markers = {'': ' ', 'warning': 'W:', 'error': 'E:'}
call append(line('$') - 1, l:markers[a:type] . ' ' . a:msg)
setlocal nomodifiable
endfunction
" Open the minpac progress window
function! minpac#progress#open(msg) abort
let l:bufname = '[minpac progress]'
if s:bufnr != 0
exec "silent! bwipe" s:bufnr
endif
if g:minpac#opt.progress_open ==# 'vertical'
vertical topleft new
elseif g:minpac#opt.progress_open ==# 'horizontal'
topleft new
elseif g:minpac#opt.progress_open ==# 'tab'
tabnew
endif
let s:winid = win_getid()
call append(0, a:msg)
setf minpacprgs
call s:syntax()
call s:mappings()
setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nomodifiable nospell
silent file `=l:bufname`
let s:bufnr = bufnr('')
endfunction
function! s:syntax() abort
syntax clear
syn match minpacPrgsTitle /^## .* ##/
syn match minpacPrgsError /^E: .*/
syn match minpacPrgsWarning /^W: .*/
syn match minpacPrgsInstalled /^ Installed:/
syn match minpacPrgsUpdated /^ Updated:/
syn match minpacPrgsUptodate /^ Already up-to-date:/
syn region minpacPrgsString start='"' end='"'
hi def link minpacPrgsTitle Title
hi def link minpacPrgsError ErrorMsg
hi def link minpacPrgsWarning WarningMsg
hi def link minpacPrgsInstalled Constant
hi def link minpacPrgsUpdated Special
hi def link minpacPrgsUptodate Comment
hi def link minpacPrgsString String
endfunction
function! s:mappings() abort
nnoremap <silent><buffer> q :q<CR>
nnoremap <silent><buffer> s :call minpac#status()<CR>
endfunction
" vim: set ts=8 sw=2 et:

View File

@ -3,14 +3,20 @@
"
" Maintainer: Ken Takata
" Created By: Kristijan Husak
" Last Change: 2018-09-01
" Last Change: 2020-01-28
" License: VIM License
" URL: https://github.com/k-takata/minpac
" ---------------------------------------------------------------------
let s:results = []
let s:bufnr = 0
let s:git_sign = -1 " Support --no-show-signature option.
function! minpac#status#get(opt) abort
let l:bufname = '[minpac status]'
if s:bufnr != 0
exec "silent! bwipe" s:bufnr
endif
let l:is_update_ran = minpac#impl#is_update_ran()
let l:update_count = 0
let l:install_count = 0
@ -24,9 +30,18 @@ function! minpac#status#get(opt) abort
if !isdirectory(l:dir)
let l:plugin.status = 'Not installed'
else
let l:commits = minpac#impl#system([g:minpac#opt.git, '-C', l:dir, 'log',
\ '--color=never', '--pretty=format:%h <<<<%D>>>> %s (%cr)', '--no-show-signature', 'HEAD...HEAD@{1}'
\ ])
let l:cmd = [g:minpac#opt.git, '-C', l:dir, 'log',
\ '--color=never', '--pretty=format:%h <<<<%D>>>> %s (%cr)', 'HEAD...HEAD@{1}'
\ ]
let l:commits = minpac#impl#system(l:cmd + (s:git_sign ? ['--no-show-signature'] : []))
if s:git_sign == -1
if l:commits[0] == 128
let s:git_sign = v:false
let l:commits = minpac#impl#system(l:cmd)
else
let s:git_sign = v:true
endif
endif
let l:plugin.lines = filter(l:commits[1], {-> v:val !=# ''})
call map(l:plugin.lines,
@ -95,6 +110,8 @@ function! minpac#status#get(opt) abort
call s:syntax()
call s:mappings()
setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline nomodifiable nospell
silent file `=l:bufname`
let s:bufnr = bufnr('')
endfunction

View File

@ -1,6 +1,6 @@
*minpac.txt* A minimal package manager for Vim 8 (and Neovim)
Version: 2.0
Version: 3.0.0
Author: Ken Takata
License: The Vim License
URL: https://github.com/k-takata/minpac
@ -56,10 +56,16 @@ before that. Therefore, minpac should be installed under "opt" directory, and
should be loaded using `packadd minpac`.
Windows ~
Vim:
>
cd /d %USERPROFILE%
git clone https://github.com/k-takata/minpac.git ^
vimfiles\pack\minpac\opt\minpac
%USERPROFILE%\vimfiles\pack\minpac\opt\minpac
<
Neovim:
>
git clone https://github.com/k-takata/minpac.git ^
%LOCALAPPDATA%\nvim\pack\minpac\opt\minpac
<
Linux, macOS ~
@ -79,6 +85,15 @@ Sample .vimrc ~
Basic sample
>
" Normally this if-block is not needed, because `:set nocp` is done
" automatically when .vimrc is found. However, this might be useful
" when you execute `vim -u .vimrc` from the command line.
if &compatible
" `:set nocp` has many side effects. Therefore this should be done
" only when 'compatible' is set.
set nocompatible
endif
packadd minpac
call minpac#init()
@ -94,6 +109,9 @@ Basic sample
" Load the plugins right now. (optional)
"packloadall
<
Minpac itself requires 'compatible' to be unset. However, the
`if &compatible`-block is optional.
Customizing 'packpath'
If you want to use ".vim" directory instead of "vimfiles" even on Windows,
@ -113,7 +131,7 @@ Advanced sample
" Try to load minpac.
packadd minpac
if !exists('*minpac#init')
if !exists('g:loaded_minpac')
" minpac is not available.
" Settings for plugin-less environment.
@ -135,55 +153,14 @@ Advanced sample
<
Load minpac on demand
Very interestingly, minpac doesn't need to be loaded every time. Unlike
other plugin managers, it is needed only when updating, installing or
cleaning the plugins. This is because minpac itself doesn't handle the
runtime path.
You can define a user command to load minpac, reload .vimrc to register the
information of plugins, then call |minpac#update()|, |minpac#clean()| or
|minpac#status()|. >
" For a paranoia.
" Normally `:set nocp` is not needed, because it is done automatically
" when .vimrc is found.
if &compatible
" `:set nocp` has many side effects. Therefore this should be done
" only when 'compatible' is set.
set nocompatible
endif
if exists('*minpac#init')
" minpac is loaded.
call minpac#init()
call minpac#add('k-takata/minpac', {'type': 'opt'})
" Additional plugins here.
call minpac#add('vim-jp/syntax-vim-ex')
...
endif
" Plugin settings here.
...
" Define user commands for updating/cleaning the plugins.
" Each of them loads minpac, reloads .vimrc to register the
" information of plugins, then performs the task.
command! PackUpdate packadd minpac | source $MYVIMRC | call minpac#update('', {'do': 'call minpac#status()'})
command! PackClean packadd minpac | source $MYVIMRC | call minpac#clean()
command! PackStatus packadd minpac | source $MYVIMRC | call minpac#status()
<
Note that your .vimrc must be reloadable to use this. E.g.:
* `:set nocompatible` should not be executed twice to avoid side effects.
* `:function!` should be used to define a user function.
* `:command!` should be used to define a user command.
* `:augroup!` should be used properly to avoid the same autogroups are
defined twice.
Another way is defining a function to load minpac and register the
information of plugins. >
Very interestingly, minpac doesn't need to be loaded every time when you
execute Vim. Unlike other plugin managers, it is needed only when updating,
installing or cleaning the plugins. This is because minpac itself doesn't
handle the runtime path.
You can define user commands to load minpac, register the information of
plugins, then call |minpac#update()|, |minpac#clean()| or |minpac#status()|.
>
function! PackInit() abort
packadd minpac
@ -202,13 +179,25 @@ Load minpac on demand
" Define user commands for updating/cleaning the plugins.
" Each of them calls PackInit() to load minpac and register
" the information of plugins, then performs the task.
command! PackUpdate call PackInit() | call minpac#update('', {'do': 'call minpac#status()'})
command! PackUpdate call PackInit() | call minpac#update()
command! PackClean call PackInit() | call minpac#clean()
command! PackStatus call PackInit() | call minpac#status()
command! PackStatus packadd minpac | call minpac#status()
<
This doesn't reload .vimrc, so the .vimrc doesn't need to be reloadable.
However, if you make it reloadable, you can apply the changes to the .vimrc
immediately by executing `:so $MYVIMRC | PackUpdate` .
If you make your .vimrc reloadable, you can reflect the setting of the
.vimrc immediately after you edit it by executing
`:so $MYVIMRC | PackUpdate`. Or you can define the commands like this: >
command! PackUpdate source $MYVIMRC | call PackInit() | call minpac#update()
command! PackClean source $MYVIMRC | call PackInit() | call minpac#clean()
command! PackStatus packadd minpac | call minpac#status()
<
To make your .vimrc reloadable:
* `:set nocompatible` should not be executed twice to avoid side effects.
* `:function!` should be used to define a user function.
* `:command!` should be used to define a user command.
* `:augroup!` should be used properly to avoid the same autogroups are
defined twice.
Sometimes, you may want to open a shell at the directory where a plugin is
@ -255,6 +244,8 @@ functions. E.g.: >
" To see plugins status:
call minpac#status()
<
Or define commands by yourself as described in the previous section.
------------------------------------------------------------------------------
FUNCTIONS *minpac-functions*
@ -279,9 +270,31 @@ minpac#init([{config}]) *minpac#init()*
3: Show start/end messages for each plugin.
4: Show debug messages.
Default: 2
confirm Show interactive confirmation prompts, such as
in |minpac#clean()|.
Default: |TRUE|
progress_open Specify how to show the progress of
|minpac#update()|.
"none": Do not open the progress window.
(Compatible with minpac v2.0.x or earlier.)
"horizontal": Open the progress window by
splitting horizontally.
"vertical": Open the progress window by
splitting vertically.
"tab": Open the progress window in a new tab.
Default: "horizontal"
status_open Default setting for the open option of
|minpac#status()|.
Default: "vertical"
Default: "horizontal"
status_auto Specify whether the status window will open
automatically after |minpac#update()| is
finished.
|TRUE|: Open the status window automatically,
when one or more plugins are updated or
installed.
|FALSE|: Do not open the status window
automatically.
Default: |FALSE|
All plugins will be installed under the following directories:
@ -312,8 +325,8 @@ minpac#add({url}[, {config}]) *minpac#add()*
Default: derived from the repository name.
type Type of the plugin. "start" or "opt".
Default: "start"
frozen If 1, the plugin will not be updated
automatically. Default: 0
frozen If |TRUE|, the plugin will not be updated
automatically. Default: |FALSE|
depth If >= 1, it is used as a depth to be cloned.
Only effective when install the plugin newly.
Default: 1 or specified value by
@ -328,6 +341,13 @@ minpac#add({url}[, {config}]) *minpac#add()*
do Post-update hook.
See |minpac-post-update-hooks|.
Default: empty
subdir Subdirectory that contains Vim plugin.
Default: empty
pullmethod Specify how to update the plugin.
Empty: Update with `--ff-only` option.
"autostash": Update with `--rebase --autostash`
options.
Default: empty
The "branch" and "rev" options are slightly different.
The "branch" option is used only when the plugin is newly installed.
@ -347,6 +367,16 @@ minpac#add({url}[, {config}]) *minpac#add()*
If you include "*" in "rev", minpac tries to checkout the latest tag
name which matches the "rev".
When "subdir"" is specified, the plugin will be installed as usual
(e.g. in `pack/minpac/start/pluginname`), however, another directory
is created and a symlink (or a junction on Windows) will be created in
it. E.g.: >
ln -s pack/minpac/start/pluginname/subdir \
pack/minpac-sub/start/pluginname
< This way, Vim can load the plugin from its subdirectory.
minpac#update([{name}[, {config}]]) *minpac#update()*
Install or update all plugins or the specified plugin.
@ -380,15 +410,16 @@ minpac#clean([{name}]) *minpac#clean()*
{name} is a name of a plugin. It can be a unique plugin name
(|minpac-plugin_name|) or a plugin name with wildcards ("*" and "?"
are supported).
are supported). It can also be a list of plugin names.
If {name} is omitted, all plugins under the minpac directory will be
checked. If unregistered plugins are found, they are listed and a
prompt is shown. If you type "y", they will be removed.
If {name} is specified, matched plugins are listed (even they are
registered with |minpac#add()|) and a prompt is shown. If you type
"y", they will be removed. {name} can also be a list of plugin names.
When called, matched plugins are listed (even they are registered with
|minpac#add()|) and a prompt is shown. If you type "y", they will be
removed. If the "confirm" option is not |TRUE|, the prompt will not
be shown.
minpac#getpluginfo({name}) *minpac#getpluginfo()*
@ -401,7 +432,8 @@ minpac#getpluginfo({name}) *minpac#getpluginfo()*
name Name of the plugin.
url URL of the plugin repository.
dir Local directory of the plugin.
frozen If 1, the plugin is frozen.
subdir Subdirectory that contains Vim plugin.
frozen If |TRUE|, the plugin is frozen.
type Type of the plugin.
depth Depth to be cloned.
branch Branch name to be cloned.
@ -431,8 +463,8 @@ minpac#getpackages([{packname}[, {packtype}[, {plugname}[, {nameonly}]]]])
{plugname} specifies a plugin name. Wildcards can be used. If omitted
or an empty string is specified, "*" is used.
If {nameonly} is 1, plugin (or package) names are listed instead of
the direcotries. Default is 0.
If {nameonly} is |TRUE|, plugin (or package) names are listed instead
of the direcotries. Default is |FALSE|.
E.g.: >
@ -462,7 +494,7 @@ minpac#status([{config}]) *minpac#status()*
"vertical": Open in vertical split.
"horizontal": Open in horizontal split.
"tab": Open in a new tab.
Default: "vertical" or specified value by
Default: "horizontal" or specified value by
|minpac#init()|.
------------------------------------------------------------------------------
@ -543,18 +575,27 @@ E.g.: >
------------------------------------------------------------------------------
MAPPINGS *minpac-mappings*
List of mappings available only in progress window.
*minpac-progress-s*
s Open the status window.
*minpac-progress-q*
q Exit the progress window.
List of mappings available only in status window.
*minpac-<CR>*
*minpac-status-<CR>*
<CR> Preview the commit under the cursor.
*minpac-CTRL-j*
*minpac-status-CTRL-j*
<C-j> Jump to next package in list.
*minpac-CTRL-k*
*minpac-status-CTRL-k*
<C-k> Jump to previous package in list.
*minpac-q*
*minpac-status-q*
q Exit the status window.
(Also works for commit preview window)

View File

@ -1,26 +0,0 @@
minpac#add() minpac.txt /*minpac#add()*
minpac#clean() minpac.txt /*minpac#clean()*
minpac#getpackages() minpac.txt /*minpac#getpackages()*
minpac#getpluginfo() minpac.txt /*minpac#getpluginfo()*
minpac#getpluglist() minpac.txt /*minpac#getpluglist()*
minpac#init() minpac.txt /*minpac#init()*
minpac#status() minpac.txt /*minpac#status()*
minpac#update() minpac.txt /*minpac#update()*
minpac-<CR> minpac.txt /*minpac-<CR>*
minpac-CTRL-j minpac.txt /*minpac-CTRL-j*
minpac-CTRL-k minpac.txt /*minpac-CTRL-k*
minpac-commands minpac.txt /*minpac-commands*
minpac-concept minpac.txt /*minpac-concept*
minpac-contents minpac.txt /*minpac-contents*
minpac-finish-update-hooks minpac.txt /*minpac-finish-update-hooks*
minpac-functions minpac.txt /*minpac-functions*
minpac-hooks minpac.txt /*minpac-hooks*
minpac-installation minpac.txt /*minpac-installation*
minpac-mappings minpac.txt /*minpac-mappings*
minpac-overview minpac.txt /*minpac-overview*
minpac-plugin_name minpac.txt /*minpac-plugin_name*
minpac-post-update-hooks minpac.txt /*minpac-post-update-hooks*
minpac-q minpac.txt /*minpac-q*
minpac-requirements minpac.txt /*minpac-requirements*
minpac-usage minpac.txt /*minpac-usage*
minpac.txt minpac.txt /*minpac.txt*

View File

@ -2,7 +2,7 @@
" minpac: A minimal package manager for Vim 8 (and Neovim)
"
" Maintainer: Ken Takata
" Last Change: 2018-09-01
" Last Change: 2020-08-22
" License: VIM License
" URL: https://github.com/k-takata/minpac
" ---------------------------------------------------------------------
@ -11,125 +11,3 @@ if exists('g:loaded_minpac')
finish
endif
let g:loaded_minpac = 1
" Get a list of package/plugin directories.
function! minpac#getpackages(...)
return call("minpac#impl#getpackages", a:000)
endfunction
function! s:ensure_initialization() abort
if !exists('g:minpac#opt')
echohl WarningMsg
echom 'Minpac has not been initialized. Use the default values.'
echohl None
call minpac#init()
endif
endfunction
" Initialize minpac.
function! minpac#init(...) abort
let l:opt = extend(copy(get(a:000, 0, {})),
\ {'dir': '', 'package_name': 'minpac', 'git': 'git', 'depth': 1, 'jobs': 8, 'verbose': 2, 'status_open': 'vertical'}, 'keep')
let g:minpac#opt = l:opt
let g:minpac#pluglist = {}
let l:packdir = l:opt.dir
if l:packdir ==# ''
" If 'dir' is not specified, the first directory of 'packpath' is used.
let l:packdir = split(&packpath, ',')[0]
endif
let l:opt.minpac_dir = l:packdir . '/pack/' . l:opt.package_name
let l:opt.minpac_start_dir = l:opt.minpac_dir . '/start'
let l:opt.minpac_opt_dir = l:opt.minpac_dir . '/opt'
if !isdirectory(l:packdir)
echoerr 'Pack directory not available: ' . l:packdir
return
endif
if !isdirectory(l:opt.minpac_start_dir)
call mkdir(l:opt.minpac_start_dir, 'p')
endif
if !isdirectory(l:opt.minpac_opt_dir)
call mkdir(l:opt.minpac_opt_dir, 'p')
endif
endfunction
" Register the specified plugin.
function! minpac#add(plugname, ...) abort
call s:ensure_initialization()
let l:opt = extend(copy(get(a:000, 0, {})),
\ {'name': '', 'type': 'start', 'depth': g:minpac#opt.depth,
\ 'frozen': 0, 'branch': '', 'rev': '', 'do': ''}, 'keep')
" URL
if a:plugname =~? '^[-._0-9a-z]\+\/[-._0-9a-z]\+$'
let l:opt.url = 'https://github.com/' . a:plugname . '.git'
else
let l:opt.url = a:plugname
endif
" Name of the plugin
if l:opt.name ==# ''
let l:opt.name = matchstr(l:opt.url, '[/\\]\zs[^/\\]\+$')
let l:opt.name = substitute(l:opt.name, '\C\.git$', '', '')
endif
if l:opt.name ==# ''
echoerr 'Cannot extract the plugin name. (' . a:plugname . ')'
return
endif
" Loading type / Local directory
if l:opt.type ==# 'start'
let l:opt.dir = g:minpac#opt.minpac_start_dir . '/' . l:opt.name
elseif l:opt.type ==# 'opt'
let l:opt.dir = g:minpac#opt.minpac_opt_dir . '/' . l:opt.name
else
echoerr "Wrong type (must be 'start' or 'opt'): " . l:opt.type
return
endif
" Initialize the status
let l:opt.stat = {'errcode': 0, 'lines': [], 'prev_rev': '', 'installed': -1}
" Add to pluglist
let g:minpac#pluglist[l:opt.name] = l:opt
endfunction
" Update all or specified plugin(s).
function! minpac#update(...)
call s:ensure_initialization()
return call("minpac#impl#update", a:000)
endfunction
" Remove plugins that are not registered.
function! minpac#clean(...)
call s:ensure_initialization()
return call("minpac#impl#clean", a:000)
endfunction
function! minpac#status(...)
call s:ensure_initialization()
let l:opt = extend(copy(get(a:000, 0, {})),
\ {'open': g:minpac#opt.status_open}, 'keep')
return minpac#status#get(l:opt)
endfunction
" Get information of specified plugin. Mainly for debugging.
function! minpac#getpluginfo(name)
call s:ensure_initialization()
return g:minpac#pluglist[a:name]
endfunction
" Get a list of plugin information. Mainly for debugging.
function! minpac#getpluglist()
return g:minpac#pluglist
endfunction
" vim: set ts=8 sw=2 et:

View File

@ -7,8 +7,12 @@
NO_PLUGINS = --noplugin # --not-a-term
NO_INITS = -U NONE $(NO_PLUGINS)
# Tests using runtest.vim.
# Individual tests.
NEW_TESTS = \
test_minpac
# Test targets that use runtest.vim.
NEW_TESTS_RES = \
test_minpac.res
# vim: ts=8 sw=8 sts=8

View File

@ -10,14 +10,24 @@ VIMPROG = vim
.SUFFIXES: .res .vim
all: newtests report
all: nolog newtests report
report:
@echo ""
@echo.
@echo Test results:
@if exist test.log ( type test.log & echo TEST FAILURE & exit /b 1 ) \
else ( echo ALL DONE )
# Execute an individual new style test, e.g.:
# nmake -f Make_dos.mak test_largefile
$(NEW_TESTS):
-if exist $@.res del $@.res
-if exist test.log del test.log
-if exist messages del messages
@$(MAKE) -nologo -f Make_win.mak $@.res VIMPROG=$(VIMPROG)
@type messages
@if exist test.log exit 1
clean:
-del *.res
-if exist test.log del test.log
@ -33,7 +43,10 @@ nolog:
# to write and a lot easier to read and debug.
# Limitation: Only works with the +eval feature.
newtests: $(NEW_TESTS)
newtests: newtestssilent
@if exist messages type messages
newtestssilent: $(NEW_TESTS_RES)
.vim.res:
@echo "$(VIMPROG)" > vimcmd

View File

@ -4,14 +4,18 @@
VIMPROG = vim
# Comment out this line to see the verbose output of tests.
#
# Catches SwapExists to avoid hanging at the ATTENTION prompt.
REDIR_TEST_TO_NULL = --cmd 'au SwapExists * let v:swapchoice = "e"' > /dev/null
# The list of tests is common to all systems.
# This defines NEW_TESTS.
include Make_all.mak
.SUFFIXES: .res .vim
#all: newtests report
all: newtestssilent report
all: nolog newtests report
report:
@echo
@ -21,9 +25,20 @@ report:
else echo ALL DONE; \
fi"
# Execute an individual new style test, e.g.:
# make test_largefile
$(NEW_TESTS):
rm -f $@.res test.log messages
@MAKEFLAGS=--no-print-directory $(MAKE) -f Makefile $@.res VIMPROG=$(VIMPROG) XXDPROG=$(XXDPROG) SCRIPTSOURCE=$(SCRIPTSOURCE)
@cat messages
@if test -f test.log; then \
exit 1; \
fi
clean:
-rm -rf *.res test.log messages
-rm -rf pack
nolog:
-rm -f test.log messages
@ -34,14 +49,15 @@ nolog:
RUN_VIMTEST = $(VIMPROG) -u NONE
newtests: newtestssilent
@/bin/sh -c "if test -f messages && grep -q 'SKIPPED\|FAILED' messages; then cat messages && if test -f test.log; then cat test.log; fi ; fi"
@if test -f messages; then cat messages; fi
newtestssilent: $(NEW_TESTS)
newtestssilent: $(NEW_TESTS_RES)
.vim.res:
@echo "$(RUN_VIMTEST)" > vimcmd
$(RUN_VIMTEST) $(NO_INITS) -S runtest.vim $*.vim
@echo "$(VIMPROG)" > vimcmd
@echo "$(RUN_VIMTEST)" >> vimcmd
$(RUN_VIMTEST) $(NO_INITS) -S runtest.vim $*.vim $(REDIR_TEST_TO_NULL)
@rm vimcmd
# vim: ts=8 sw=8 sts=8

View File

@ -3,10 +3,26 @@
" Errors are appended to the test.log file.
"
" To execute only specific test functions, add a second argument. It will be
" matched against the names of the Test_ funtion. E.g.:
" matched against the names of the Test_ function. E.g.:
" ../vim -u NONE -S runtest.vim test_channel.vim open_delay
" The output can be found in the "messages" file.
"
" If the environment variable $TEST_FILTER is set then only test functions
" matching this pattern are executed. E.g. for sh/bash:
" export TEST_FILTER=Test_channel
" For csh:
" setenv TEST_FILTER Test_channel
"
" While working on a test you can make $TEST_NO_RETRY non-empty to not retry:
" export TEST_NO_RETRY=yes
"
" To ignore failure for tests that are known to fail in a certain environment,
" set $TEST_MAY_FAIL to a comma separated list of function names. E.g. for
" sh/bash:
" export TEST_MAY_FAIL=Test_channel_one,Test_channel_other
" The failure report will then not be included in the test.log file and
" "make test" will not fail.
"
" The test script may contain anything, only functions that start with
" "Test_" are special. These will be invoked and should contain assert
" functions. See test_assert.vim for an example.
@ -26,20 +42,36 @@
" It will be called after each Test_ function.
"
" When debugging a test it can be useful to add messages to v:errors:
" call add(v:errors, "this happened")
" call add(v:errors, "this happened")
" Without the +eval feature we can't run these tests, bail out.
so small.vim
silent! while 0
qa!
silent! endwhile
" In the GUI we can always change the screen size.
if has('gui_running')
set columns=80 lines=25
endif
" Check that the screen size is at least 24 x 80 characters.
if &lines < 24 || &columns < 80
let error = 'Screen size too small! Tests require at least 24 lines with 80 characters'
let error = 'Screen size too small! Tests require at least 24 lines with 80 characters, got ' .. &lines .. ' lines with ' .. &columns .. ' characters'
echoerr error
split test.log
$put =error
w
cquit
write
split messages
call append(line('$'), '')
call append(line('$'), 'From ' . expand('%') . ':')
call append(line('$'), error)
write
qa!
endif
if has('reltime')
let s:start_time = reltime()
endif
" Common with all tests on all systems.
@ -49,13 +81,31 @@ source setup.vim
" This also enables use of line continuation.
set nocp viminfo+=nviminfo
" Use utf-8 or latin1 by default, instead of whatever the system default
" happens to be. Individual tests can overrule this at the top of the file.
if has('multi_byte')
set encoding=utf-8
else
set encoding=latin1
endif
" Use utf-8 by default, instead of whatever the system default happens to be.
" Individual tests can overrule this at the top of the file and use
" g:orig_encoding if needed.
let g:orig_encoding = &encoding
set encoding=utf-8
" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
" the test_name.vim file itself. Replace it here with a more restrictive one,
" so we still catch mistakes.
let s:test_script_fname = expand('%')
au! SwapExists * call HandleSwapExists()
func HandleSwapExists()
if exists('g:ignoreSwapExists')
return
endif
" Ignore finding a swap file for the test script (the user might be
" editing it and do ":make test_name") and the output file.
" Report finding another swap file and chose 'q' to avoid getting stuck.
if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
let v:swapchoice = 'e'
else
call assert_report('Unexpected swap file: ' .. v:swapname)
let v:swapchoice = 'q'
endif
endfunc
" Avoid stopping at the "hit enter" prompt
set nomore
@ -63,11 +113,29 @@ set nomore
" Output all messages in English.
lang mess C
" suppress menu translation
if has('gui_running') && exists('did_install_default_menus')
source $VIMRUNTIME/delmenu.vim
set langmenu=none
source $VIMRUNTIME/menu.vim
endif
" Always use forward slashes.
set shellslash
let s:srcdir = expand('%:p:h:h')
if has('win32')
" avoid prompt that is long or contains a line break
let $PROMPT = '$P$G'
" On MS-Windows t_md and t_me are Vim specific escape sequences.
let s:t_bold = "\x1b[1m"
let s:t_normal = "\x1b[m"
else
let s:t_bold = &t_md
let s:t_normal = &t_me
endif
" Prepare for calling test_garbagecollect_now().
let v:testing = 1
@ -88,6 +156,9 @@ endfunc
func RunTheTest(test)
echo 'Executing ' . a:test
if has('reltime')
let func_start = reltime()
endif
" Avoid stopping at the "hit enter" prompt
set nomore
@ -117,17 +188,13 @@ func RunTheTest(test)
endtry
endif
call add(s:messages, 'Executing ' . a:test)
let s:done += 1
if a:test =~ 'Test_nocatch_'
" Function handles errors itself. This avoids skipping commands after the
" error.
exe 'call ' . a:test
else
try
let s:test = a:test
au VimLeavePre * call EarlyExit(s:test)
au VimLeavePre * call EarlyExit(g:testfunc)
exe 'call ' . a:test
au! VimLeavePre
catch /^\cskipped/
@ -138,6 +205,10 @@ func RunTheTest(test)
endtry
endif
" In case 'insertmode' was set and something went wrong, make sure it is
" reset to avoid trouble with anything else.
set noinsertmode
if exists("*TearDown")
try
call TearDown()
@ -146,8 +217,15 @@ func RunTheTest(test)
endtry
endif
" Clear any autocommands
" Clear any autocommands and put back the catch-all for SwapExists.
au!
au SwapExists * call HandleSwapExists()
" Check for and close any stray popup windows.
if has('popupwin')
call assert_equal([], popup_list())
call popup_clear(1)
endif
" Close any extra tab pages and windows and make the current one not modified.
while tabpagenr('$') > 1
@ -168,13 +246,34 @@ func RunTheTest(test)
endwhile
exe 'cd ' . save_cwd
let message = 'Executed ' . a:test
if has('reltime')
let message ..= repeat(' ', 50 - len(message))
let time = reltime(func_start)
if has('float') && reltimefloat(time) > 0.1
let message = s:t_bold .. message
endif
let message ..= ' in ' .. reltimestr(time) .. ' seconds'
if has('float') && reltimefloat(time) > 0.1
let message ..= s:t_normal
endif
endif
call add(s:messages, message)
let s:done += 1
endfunc
func AfterTheTest()
func AfterTheTest(func_name)
if len(v:errors) > 0
let s:fail += 1
call add(s:errors, 'Found errors in ' . s:test . ':')
call extend(s:errors, v:errors)
if match(s:may_fail_list, '^' .. a:func_name) >= 0
let s:fail_expected += 1
call add(s:errors_expected, 'Found errors in ' . g:testfunc . ':')
call extend(s:errors_expected, v:errors)
else
let s:fail += 1
call add(s:errors, 'Found errors in ' . g:testfunc . ':')
call extend(s:errors, v:errors)
endif
let v:errors = []
endif
endfunc
@ -190,7 +289,7 @@ endfunc
" This function can be called by a test if it wants to abort testing.
func FinishTesting()
call AfterTheTest()
call AfterTheTest('')
" Don't write viminfo on exit.
set viminfo=
@ -198,7 +297,7 @@ func FinishTesting()
" Clean up files created by setup.vim
call delete('XfakeHOME', 'rf')
if s:fail == 0
if s:fail == 0 && s:fail_expected == 0
" Success, create the .res file so that make knows it's done.
exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
write
@ -214,10 +313,22 @@ func FinishTesting()
endif
if s:done == 0
let message = 'NO tests executed'
if s:filtered > 0
let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'"
else
let message = 'NO tests executed'
endif
else
if s:filtered > 0
call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER")
endif
let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
endif
if s:done > 0 && has('reltime')
let message = s:t_bold .. message .. repeat(' ', 40 - len(message))
let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds'
let message ..= s:t_normal
endif
echo message
call add(s:messages, message)
if s:fail > 0
@ -226,6 +337,12 @@ func FinishTesting()
call add(s:messages, message)
call extend(s:messages, s:errors)
endif
if s:fail_expected > 0
let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):'
echo message
call add(s:messages, message)
call extend(s:messages, s:errors_expected)
endif
" Add SKIPPED messages
call extend(s:messages, s:skipped)
@ -245,15 +362,20 @@ endfunc
let g:testname = expand('%')
let s:done = 0
let s:fail = 0
let s:fail_expected = 0
let s:errors = []
let s:errors_expected = []
let s:messages = []
let s:skipped = []
if expand('%') =~ 'test_vimscript.vim'
" this test has intentional s:errors, don't use try/catch.
" this test has intentional errors, don't use try/catch.
source %
else
try
source %
catch /^\cskipped/
call add(s:messages, ' Skipped')
call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
catch
let s:fail += 1
call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
@ -261,49 +383,90 @@ else
endif
" Names of flaky tests.
let s:flaky = [
let s:flaky_tests = [
\ ]
" Locate Test_ functions and execute them.
redir @q
silent function /^Test_
redir END
let s:tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g'))
let s:tests = split(substitute(@q, '\(function\|def\) \(\k*()\)', '\2', 'g'))
" If there is an extra argument filter the function names against it.
if argc() > 1
let s:tests = filter(s:tests, 'v:val =~ argv(1)')
endif
" If the environment variable $TEST_FILTER is set then filter the function
" names against it.
let s:filtered = 0
if $TEST_FILTER != ''
let s:filtered = len(s:tests)
let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER')
let s:filtered -= len(s:tests)
endif
let s:may_fail_list = []
if $TEST_MAY_FAIL != ''
" Split the list at commas and add () to make it match g:testfunc.
let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'})
endif
" Execute the tests in alphabetical order.
for s:test in sort(s:tests)
for g:testfunc in sort(s:tests)
" Silence, please!
silent! set belloff=all
let prev_error = ''
let total_errors = []
let g:run_nr = 1
call RunTheTest(s:test)
" A test can set g:test_is_flaky to retry running the test.
let g:test_is_flaky = 0
if len(v:errors) > 0 && index(s:flaky, s:test) >= 0
call add(s:messages, 'Found errors in ' . s:test . ':')
call extend(s:messages, v:errors)
call add(s:messages, 'Flaky test failed, running it again')
let first_run = v:errors
call RunTheTest(g:testfunc)
" Flakiness is often caused by the system being very busy. Sleep a couple
" of seconds to have a higher chance of succeeding the second time.
sleep 2
" Repeat a flaky test. Give up when:
" - $TEST_NO_RETRY is not empty
" - it fails again with the same message
" - it fails five times (with a different message)
if len(v:errors) > 0
\ && $TEST_NO_RETRY == ''
\ && (index(s:flaky_tests, g:testfunc) >= 0
\ || g:test_is_flaky)
while 1
call add(s:messages, 'Found errors in ' . g:testfunc . ':')
call extend(s:messages, v:errors)
let v:errors = []
call RunTheTest(s:test)
if len(v:errors) > 0
let second_run = v:errors
let v:errors = ['First run:']
call extend(v:errors, first_run)
call add(v:errors, 'Second run:')
call extend(v:errors, second_run)
endif
call add(total_errors, 'Run ' . g:run_nr . ':')
call extend(total_errors, v:errors)
if g:run_nr == 5 || prev_error == v:errors[0]
call add(total_errors, 'Flaky test failed too often, giving up')
let v:errors = total_errors
break
endif
call add(s:messages, 'Flaky test failed, running it again')
" Flakiness is often caused by the system being very busy. Sleep a
" couple of seconds to have a higher chance of succeeding the second
" time.
sleep 2
let prev_error = v:errors[0]
let v:errors = []
let g:run_nr += 1
call RunTheTest(g:testfunc)
if len(v:errors) == 0
" Test passed on rerun.
break
endif
endwhile
endif
call AfterTheTest()
call AfterTheTest(g:testfunc)
endfor
call FinishTesting()

View File

@ -21,20 +21,24 @@ func Test_minpac_init()
call assert_equal(1, g:minpac#opt.depth)
call assert_equal(8, g:minpac#opt.jobs)
call assert_equal(2, g:minpac#opt.verbose)
call assert_equal('vertical', g:minpac#opt.status_open)
call assert_equal('horizontal', g:minpac#opt.progress_open)
call assert_equal('horizontal', g:minpac#opt.status_open)
call assert_equal(v:false, g:minpac#opt.status_auto)
call assert_equal({}, minpac#getpluglist())
let g:minpac#pluglist.foo = 'bar'
" Change settings
call minpac#init({'package_name': 'm', 'git': 'foo', 'depth': 10, 'jobs': 2, 'verbose': 1, 'status_open': 'horizontal'})
call minpac#init({'package_name': 'm', 'git': 'foo', 'depth': 10, 'jobs': 2, 'verbose': 1, 'progress_open': 'tab', 'status_open': 'vertical', 'status_auto': v:true})
call assert_true(isdirectory('pack/m/start'))
call assert_true(isdirectory('pack/m/opt'))
call assert_equal('foo', g:minpac#opt.git)
call assert_equal(10, g:minpac#opt.depth)
call assert_equal(2, g:minpac#opt.jobs)
call assert_equal(1, g:minpac#opt.verbose)
call assert_equal('horizontal', g:minpac#opt.status_open)
call assert_equal('tab', g:minpac#opt.progress_open)
call assert_equal('vertical', g:minpac#opt.status_open)
call assert_equal(v:true, g:minpac#opt.status_auto)
call assert_equal({}, minpac#getpluglist())
call delete('pack', 'rf')
@ -51,24 +55,28 @@ func Test_minpac_add()
let p = minpac#getpluginfo('minpac')
call assert_equal('https://github.com/k-takata/minpac.git', p.url)
call assert_match('/pack/minpac/start/minpac$', p.dir)
call assert_equal(0, p.frozen)
call assert_equal(v:false, p.frozen)
call assert_equal('start', p.type)
call assert_equal('', p.branch)
call assert_equal(1, p.depth)
call assert_equal('', p.do)
call assert_equal('', p.rev)
call assert_equal('', p.subdir)
call assert_equal('', p.pullmethod)
" With configuration
call minpac#add('k-takata/minpac', {'type': 'opt', 'frozen': 1, 'branch': 'master', 'depth': 10, 'rev': 'abcdef'})
call minpac#add('k-takata/minpac', {'type': 'opt', 'frozen': v:true, 'branch': 'master', 'depth': 10, 'rev': 'abcdef', 'subdir': 'dir', 'pullmethod': 'autostash'})
let p = minpac#getpluginfo('minpac')
call assert_equal('https://github.com/k-takata/minpac.git', p.url)
call assert_match('/pack/minpac/opt/minpac$', p.dir)
call assert_equal(1, p.frozen)
call assert_equal(v:true, p.frozen)
call assert_equal('opt', p.type)
call assert_equal('master', p.branch)
call assert_equal(10, p.depth)
call assert_equal('', p.do)
call assert_equal('abcdef', p.rev)
call assert_equal('dir', p.subdir)
call assert_equal('autostash', p.pullmethod)
" SSH URL
call minpac#add('git@github.com:k-takata/minpac.git', {'name': 'm'})
@ -189,7 +197,7 @@ func Test_minpac_update()
let g:finish_update = 0
call minpac#update('', {'do': 'let g:finish_update = 1'})
while g:finish_update == 0
sleep 1
sleep 100m
endwhile
call assert_equal(1, g:post_update)
call assert_true(isdirectory('pack/minpac/opt/minpac'))
@ -211,7 +219,7 @@ func Test_minpac_update()
\ l:finish_update
\ ]}})
while l:finish_update == 0
sleep 1
sleep 100m
endwhile
call assert_equal(1, l:post_update)
call assert_true(isdirectory('pack/minpac/start/hg-vim'))

View File

@ -2,7 +2,7 @@
set CACHED=yes
set DL=yes
py tools\dl-kaoriya-vim.py -c > release-info.txt
py tools\dl-vim-kt.py -c > release-info.txt
if ERRORLEVEL 1 (
rem Maybe this is a PR build and reaches the limit rate of GitHub API.
set DL=no
@ -15,7 +15,7 @@ if ERRORLEVEL 1 (
)
if "%DL%"=="yes" (
echo Download the latest Vim.
py tools\dl-kaoriya-vim.py --arch win64 --filename vim.zip --force --noprogress
py tools\dl-vim-kt.py --arch win64 --filename vim.zip --force --noprogress
if not ERRORLEVEL 1 (
move /y vim.zip downloads > nul
copy /y release-info.txt downloads > nul
@ -29,4 +29,3 @@ if "%DL%"=="yes" (
echo Use cached version of Vim.
)
7z x downloads\vim.zip > nul
move vim??-kaoriya-win64 vim-kaoriya-win64 > nul

View File

@ -0,0 +1,136 @@
#!/usr/bin/python3
# Download the latest vim-kt from the GitHub releases
import argparse
import calendar
import io
import json
import os
import sys
import time
import urllib.request, urllib.error
# Repository Name
repo_name = 'k-takata/vim-kt'
gh_releases_url = 'https://api.github.com/repos/' + repo_name + '/releases'
# Asset name checker
def does_skip_asset(asset):
return asset['name'].find('pdb') >= 0 or asset['name'].find('zip') >= 0
# Arguments properties
arg_desc = 'Download the latest vim-kt from the GitHub releases'
arg_archs = ['all', 'win32', 'win64']
arg_default_arch = 'all'
arg_allow_prerelease = False
# Parse arguments
def parse_args():
global parser
parser = argparse.ArgumentParser(description=arg_desc)
parser.add_argument('-c', '--check', action='store_true',
help='only check the information of the latest release')
parser.add_argument('--noprogress', action='store_true',
help="Don't show the progress")
parser.add_argument('-f', '--force', action='store_true',
help='overwrite the download file')
parser.add_argument('-n', '--filename', type=str, action='store',
help='filename to save')
parser.add_argument('-p', '--prerelease', action='store_true',
default=arg_allow_prerelease,
help='Allow downloading prerelease')
parser.add_argument('-a', '--arch', type=str, action='store',
choices=arg_archs, default=arg_default_arch,
help='architecture to download')
parser.add_argument('--auth', type=str, action='store',
default=os.getenv('AUTH_TOKEN'),
metavar="TOKEN", help='GitHub API token (Environment variable AUTH_TOKEN can be also used.)')
return parser.parse_args()
# Get information of GitHub release
# see: https://developer.github.com/v3/repos/releases/
def get_rel_info(url, auth):
if auth:
# Unauthenticated requests are limited up to 60 requests per hour.
# Authenticated requests are allowed up to 5,000 requests per hour.
# See: https://developer.github.com/v3/#rate-limiting
request = urllib.request.Request(url)
request.add_header("Authorization", "token " + auth)
else:
request = url
try:
response = urllib.request.urlopen(request)
except urllib.error.HTTPError as err:
print('GitHub release not found. (%s)' % err.reason, file=sys.stderr)
exit(1)
return json.load(io.StringIO(str(response.read(), 'utf-8')))
# Show progress
def reporthook(count, blocksize, totalsize):
size = count * blocksize
if totalsize <= 0:
print("\r{:,}".format(size))
else:
size = min(size, totalsize)
print("\r{:,} / {:,} ({:.1%})".format(size, totalsize, size / totalsize), end='')
# Download the files
def download(args, rel_info):
for asset in rel_info['assets']:
if args.filename:
name = args.filename
else:
name = asset['name']
if does_skip_asset(asset):
continue
if args.arch != 'all' and asset['name'].find(args.arch) < 0:
continue
if os.path.isfile(name) and not args.force:
print('File exists:', name)
continue
print('Downloading from:', asset['browser_download_url'])
print('Downloading to:', name)
if args.noprogress:
hook = None
else:
hook = reporthook
urllib.request.urlretrieve(asset['browser_download_url'], name, hook)
# Set timestamp
asset_time = time.strptime(asset['updated_at'], '%Y-%m-%dT%H:%M:%SZ')
os.utime(name, times=(time.time(), calendar.timegm(asset_time)))
if not args.noprogress:
print()
def main():
args = parse_args()
if args.filename and args.arch == 'all':
parser.error('-a must be specified when you specify -n.')
if args.prerelease:
rels_info = get_rel_info(gh_releases_url, args.auth)
for rel in rels_info:
if rel['draft']:
continue
gh_release_url = rel['url']
break
else:
print('GitHub release not found.', file=sys.stderr)
exit(1)
else:
gh_release_url = gh_releases_url + '/latest'
rel_info = get_rel_info(gh_release_url, args.auth)
print('Last release:', rel_info['name'])
print('Created at:', rel_info['created_at'])
if args.check:
exit(0)
download(args, rel_info)
exit(0)
if __name__ == "__main__":
main()

View File

@ -1,102 +0,0 @@
#!/usr/bin/python3
# Download the latest KaoriYa Vim from the GitHub release
import argparse
import calendar
import io
import json
import os
import sys
import time
import urllib.request, urllib.error
# Repository Name
repo_name = 'koron/vim-kaoriya'
gh_release_url = 'https://api.github.com/repos/' + repo_name + '/releases/latest'
# Asset name checker
def does_skip_asset(asset):
return asset['name'].find('pdb') >= 0
# Arguments properties
arg_desc = 'Download the latest KaoriYa Vim from the GitHub release'
arg_archs = ['all', 'win32', 'win64']
arg_default_arch = 'all'
# Parse arguments
parser = argparse.ArgumentParser(description=arg_desc)
parser.add_argument('-c', '--check', action='store_true',
help='only check the information of the latest release')
parser.add_argument('-p', '--noprogress', action='store_true',
help="Don't show the progress")
parser.add_argument('-f', '--force', action='store_true',
help='overwrite the download file')
parser.add_argument('-n', '--filename', type=str, action='store',
help='filename to save')
parser.add_argument('-a', '--arch', type=str, action='store',
choices=arg_archs, default=arg_default_arch,
help='architecture to download')
parser.add_argument('--auth', type=str, action='store',
default=os.getenv('AUTH_TOKEN'),
metavar="TOKEN", help='GitHub API token (Environment variable AUTH_TOKEN can be also used.)')
args = parser.parse_args()
if args.filename and args.arch == 'all':
parser.error('-a must be specified when you specify -n.')
# Get information of GitHub release
# see: https://developer.github.com/v3/repos/releases/
if args.auth:
# Unauthenticated requests are limited up to 60 requests per hour.
# Authenticated requests are allowed up to 5,000 requests per hour.
# See: https://developer.github.com/v3/#rate-limiting
request = urllib.request.Request(gh_release_url)
request.add_header("Authorization", "token " + args.auth)
else:
request = gh_release_url
try:
response = urllib.request.urlopen(request)
except urllib.error.HTTPError as err:
print('GitHub release not found. (%s)' % err.reason, file=sys.stderr)
exit(1)
rel_info = json.load(io.StringIO(str(response.read(), 'utf-8')))
print('Last release:', rel_info['name'])
print('Created at:', rel_info['created_at'])
if args.check:
exit(0)
def reporthook(count, blocksize, totalsize):
if args.noprogress:
return
size = count * blocksize
if totalsize <= 0:
print("\r{:,}".format(size))
else:
size = min(size, totalsize)
print("\r{:,} / {:,} ({:.1%})".format(size, totalsize, size / totalsize), end='')
# Download the files
for asset in rel_info['assets']:
if args.filename:
name = args.filename
else:
name = asset['name']
if does_skip_asset(asset):
continue
if args.arch != 'all' and asset['name'].find(args.arch) < 0:
continue
if os.path.isfile(name) and not args.force:
print('File exists:', name)
continue
print('Downloading from:', asset['browser_download_url'])
print('Downloading to:', name)
urllib.request.urlretrieve(asset['browser_download_url'], name, reporthook)
# Set timestamp
asset_time = time.strptime(asset['updated_at'], '%Y-%m-%dT%H:%M:%SZ')
os.utime(name, times=(time.time(), calendar.timegm(asset_time)))
print()
exit(0)