6 Commits

Author SHA1 Message Date
Daniel Hahler
7655e8218f Merge 00d3f0ada6 into a7d4a73dd6 2025-02-06 19:47:17 +08:00
Daniel Hahler
00d3f0ada6 Queue autocommands for VimEnter
This also uses `s:dobufread` for the `BufEnter` event (which enables
`<nomodeline>` for it).

Triggering `BufRead` during startup of Vim should be avoided, because it
will also trigger `FileType` events, which can have unexpected side
effects.

Ref: https://github.com/vim/vim/issues/2810
2018-04-17 10:02:25 +02:00
Daniel Hahler
a78b28a318 tests: trigger VimEnter for #112 test 2018-04-17 10:02:25 +02:00
Daniel Hahler
66e48daac3 adjust test "Filetype-based on-demand loading" 2018-04-17 10:02:25 +02:00
Daniel Hahler
fa165cd592 handle missing v:vim_did_enter / use s:vim_did_enter 2018-04-17 10:02:25 +02:00
Daniel Hahler
bd33a4337d Do not trigger filetypeindent/filetypeplugin autocmds by default
This is not necessary if `filetype plugin indent on` was not used before
`plug#end()`, since then the `FileType` autocmds from there will come
after vim-plug's.

This will issue a warning, and makes handling of this conditional.

This could use `filetype plugin/indent off` to work around this (similar
to the `filetype off` being used), but `runtime/indoff.vim` and
`runtime/ftplugof.vim` will only empty the augroups, and not remove
them.

Fixing the user's config is the best solution anyway, so I think a
warning is good.
2018-04-17 10:02:25 +02:00
3 changed files with 85 additions and 74 deletions

135
plug.vim
View File

@@ -68,7 +68,6 @@ let s:mac_gui = has('gui_macvim') && has('gui_running')
let s:is_win = has('win32') let s:is_win = has('win32')
let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win) let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win)
let s:vim8 = has('patch-8.0.0039') && exists('*job_start') let s:vim8 = has('patch-8.0.0039') && exists('*job_start')
let s:shell_error = 0
if s:is_win && &shellslash if s:is_win && &shellslash
set noshellslash set noshellslash
let s:me = resolve(expand('<sfile>:p')) let s:me = resolve(expand('<sfile>:p'))
@@ -85,6 +84,9 @@ let s:TYPE = {
\ } \ }
let s:loaded = get(s:, 'loaded', {}) let s:loaded = get(s:, 'loaded', {})
let s:triggers = get(s:, 'triggers', {}) let s:triggers = get(s:, 'triggers', {})
let s:need_filetypeplugin_au = 0
let s:need_filetypeindent_au = 0
let s:autocmd_queue_for_vimenter = []
function! s:is_powershell(shell) function! s:is_powershell(shell)
return a:shell =~# 'powershell\(\.exe\)\?$' || a:shell =~# 'pwsh\(\.exe\)\?$' return a:shell =~# 'powershell\(\.exe\)\?$' || a:shell =~# 'pwsh\(\.exe\)\?$'
@@ -171,7 +173,7 @@ function! s:git_origin_branch(spec)
" The command may not return the name of a branch in detached HEAD state " The command may not return the name of a branch in detached HEAD state
let result = s:lines(s:system('git symbolic-ref --short HEAD', a:spec.dir)) let result = s:lines(s:system('git symbolic-ref --short HEAD', a:spec.dir))
return s:shell_error ? '' : result[-1] return v:shell_error ? '' : result[-1]
endfunction endfunction
if s:is_win if s:is_win
@@ -324,6 +326,21 @@ function! plug#end()
if get(g:, 'did_load_filetypes', 0) if get(g:, 'did_load_filetypes', 0)
filetype off filetype off
endif endif
let warn = []
if exists('g:did_load_ftplugin')
let warn += ['plugin']
let s:need_filetypeindent_au = 1
endif
if exists('g:did_indent_on')
let warn += ['indent']
let s:need_filetypeplugin_au = 1
endif
if !empty(warn)
redraw
call s:warn('echom', printf('[vim-plug] "filetype %s on" should not be used manually with vim-plug, please remove it from your vimrc.', join(warn)))
endif
for name in g:plugs_order for name in g:plugs_order
if !has_key(g:plugs, name) if !has_key(g:plugs, name)
continue continue
@@ -373,10 +390,8 @@ function! plug#end()
for [cmd, names] in items(lod.cmd) for [cmd, names] in items(lod.cmd)
execute printf( execute printf(
\ has('patch-7.4.1898') \ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)',
\ ? 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, <q-mods> ,%s)' \ cmd, string(cmd), string(names))
\ : 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)'
\ , cmd, string(cmd), string(names))
endfor endfor
for [map, names] in items(lod.map) for [map, names] in items(lod.map)
@@ -401,7 +416,21 @@ function! plug#end()
if has('syntax') && !exists('g:syntax_on') if has('syntax') && !exists('g:syntax_on')
syntax enable syntax enable
end end
" NOTE: v:vim_did_enter might not exist with older Vims, and handling it
" manually can be used in tests.
let s:vim_did_enter = 0
function! s:plug_on_vimenter()
let s:vim_did_enter = 1
for event in s:autocmd_queue_for_vimenter
call s:doautocmd(event)
endfor
endfunction
augroup PlugLOD
autocmd VimEnter * call s:plug_on_vimenter()
augroup END
else else
let s:vim_did_enter = 1
call s:reload_plugins() call s:reload_plugins()
endif endif
endfunction endfunction
@@ -564,6 +593,12 @@ function! s:reorg_rtp()
endfunction endfunction
function! s:doautocmd(...) function! s:doautocmd(...)
if !s:vim_did_enter
if index(s:autocmd_queue_for_vimenter, a:000) == -1
call add(s:autocmd_queue_for_vimenter, a:000)
endif
return
endif
if exists('#'.join(a:000, '#')) if exists('#'.join(a:000, '#'))
execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '<nomodeline>' : '') join(a:000) execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '<nomodeline>' : '') join(a:000)
endif endif
@@ -574,9 +609,7 @@ function! s:dobufread(names)
let path = s:rtp(g:plugs[name]) let path = s:rtp(g:plugs[name])
for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin'] for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin']
if len(finddir(dir, path)) if len(finddir(dir, path))
if exists('#BufRead') call s:doautocmd('BufRead')
doautocmd BufRead
endif
return return
endif endif
endfor endfor
@@ -650,23 +683,24 @@ function! s:lod_ft(pat, names)
let syn = 'syntax/'.a:pat.'.vim' let syn = 'syntax/'.a:pat.'.vim'
call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn) call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn)
execute 'autocmd! PlugLOD FileType' a:pat execute 'autocmd! PlugLOD FileType' a:pat
" Executing this is only necessary if "filetype plugin indent on" was used
" before plug#end, and can be skipped when Vim has not entered always.
if s:vim_did_enter
if s:need_filetypeplugin_au
call s:doautocmd('filetypeplugin', 'FileType') call s:doautocmd('filetypeplugin', 'FileType')
endif
if s:need_filetypeindent_au
call s:doautocmd('filetypeindent', 'FileType') call s:doautocmd('filetypeindent', 'FileType')
endif
endif
endfunction endfunction
if has('patch-7.4.1898')
function! s:lod_cmd(cmd, bang, l1, l2, args, mods, names)
call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
call s:dobufread(a:names)
execute printf('%s %s%s%s %s', a:mods, (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
endfunction
else
function! s:lod_cmd(cmd, bang, l1, l2, args, names) function! s:lod_cmd(cmd, bang, l1, l2, args, names)
call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
call s:dobufread(a:names) call s:dobufread(a:names)
execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
endfunction endfunction
endif
function! s:lod_map(map, names, with_prefix, prefix) function! s:lod_map(map, names, with_prefix, prefix)
call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
@@ -1086,19 +1120,15 @@ function! s:hash_match(a, b)
return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0 return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0
endfunction endfunction
function! s:disable_credential_helper()
return s:git_version_requirement(2) && get(g:, 'plug_disable_credential_helper', 1)
endfunction
function! s:checkout(spec) function! s:checkout(spec)
let sha = a:spec.commit let sha = a:spec.commit
let output = s:git_revision(a:spec.dir) let output = s:git_revision(a:spec.dir)
let error = 0 let error = 0
if !empty(output) && !s:hash_match(sha, s:lines(output)[0]) if !empty(output) && !s:hash_match(sha, s:lines(output)[0])
let credential_helper = s:disable_credential_helper() ? '-c credential.helper= ' : '' let credential_helper = s:git_version_requirement(2) ? '-c credential.helper= ' : ''
let output = s:system( let output = s:system(
\ 'git '.credential_helper.'fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir) \ 'git '.credential_helper.'fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir)
let error = s:shell_error let error = v:shell_error
endif endif
return [output, error] return [output, error]
endfunction endfunction
@@ -1304,7 +1334,7 @@ function! s:update_finish()
let tag = spec.tag let tag = spec.tag
if tag =~ '\*' if tag =~ '\*'
let tags = s:lines(s:system('git tag --list '.plug#shellescape(tag).' --sort -version:refname 2>&1', spec.dir)) let tags = s:lines(s:system('git tag --list '.plug#shellescape(tag).' --sort -version:refname 2>&1', spec.dir))
if !s:shell_error && !empty(tags) if !v:shell_error && !empty(tags)
let tag = tags[0] let tag = tags[0]
call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag)) call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag))
call append(3, '') call append(3, '')
@@ -1312,7 +1342,7 @@ function! s:update_finish()
endif endif
call s:log4(name, 'Checking out '.tag) call s:log4(name, 'Checking out '.tag)
let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir) let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir)
let error = s:shell_error let error = v:shell_error
endif endif
if !error && filereadable(spec.dir.'/.gitmodules') && if !error && filereadable(spec.dir.'/.gitmodules') &&
\ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir)) \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir))
@@ -1320,7 +1350,7 @@ function! s:update_finish()
let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir) let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir)
let error = v:shell_error let error = v:shell_error
endif endif
let msg = s:format_message(error ? 'x': '-', name, out) let msg = s:format_message(v:shell_error ? 'x': '-', name, out)
if error if error
call add(s:update.errors, name) call add(s:update.errors, name)
call s:regress_bar() call s:regress_bar()
@@ -1481,7 +1511,7 @@ function! s:spawn(name, spec, queue, opts)
endif endif
else else
let job.lines = s:lines(call('s:system', has_key(a:opts, 'dir') ? [argv, a:opts.dir] : [argv])) let job.lines = s:lines(call('s:system', has_key(a:opts, 'dir') ? [argv, a:opts.dir] : [argv]))
let job.error = s:shell_error != 0 let job.error = v:shell_error != 0
let job.running = 0 let job.running = 0
endif endif
endfunction endfunction
@@ -1604,7 +1634,7 @@ while 1 " Without TCO, Vim stack is bound to explode
let [error, _] = s:git_validate(spec, 0) let [error, _] = s:git_validate(spec, 0)
if empty(error) if empty(error)
if pull if pull
let cmd = s:disable_credential_helper() ? ['git', '-c', 'credential.helper=', 'fetch'] : ['git', 'fetch'] let cmd = s:git_version_requirement(2) ? ['git', '-c', 'credential.helper=', 'fetch'] : ['git', 'fetch']
if has_tag && !empty(globpath(spec.dir, '.git/shallow')) if has_tag && !empty(globpath(spec.dir, '.git/shallow'))
call extend(cmd, ['--depth', '99999999']) call extend(cmd, ['--depth', '99999999'])
endif endif
@@ -2335,22 +2365,6 @@ function! s:with_cd(cmd, dir, ...)
return printf('%s %s %s %s', cd, plug#shellescape(a:dir, {'script': script, 'shell': &shell}), sep, a:cmd) return printf('%s %s %s %s', cd, plug#shellescape(a:dir, {'script': script, 'shell': &shell}), sep, a:cmd)
endfunction endfunction
function! s:system_job(cmd) abort
let tmp = tempname()
let job = job_start(['/bin/sh', '-c', a:cmd], {
\ 'out_io': 'file',
\ 'out_name': tmp,
\ 'err_io': 'out',
\})
while job_status(job) ==# 'run'
sleep 1m
endwhile
let s:shell_error = job_info(job).exitval
let result = filereadable(tmp) ? join(readfile(tmp, 'b'), "\n") : ''
silent! call delete(tmp)
return result
endfunction
function! s:system(cmd, ...) function! s:system(cmd, ...)
let batchfile = '' let batchfile = ''
try try
@@ -2360,9 +2374,7 @@ function! s:system(cmd, ...)
" but it cannot set the working directory for the command. " but it cannot set the working directory for the command.
" Assume that the command does not rely on the shell. " Assume that the command does not rely on the shell.
if has('nvim') && a:0 == 0 if has('nvim') && a:0 == 0
let ret = system(a:cmd) return system(a:cmd)
let s:shell_error = v:shell_error
return ret
endif endif
let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"shell": &shell, "script": 0})')) let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"shell": &shell, "script": 0})'))
if s:is_powershell(&shell) if s:is_powershell(&shell)
@@ -2377,12 +2389,7 @@ function! s:system(cmd, ...)
if s:is_win && type(a:cmd) != s:TYPE.list if s:is_win && type(a:cmd) != s:TYPE.list
let [batchfile, cmd] = s:batchfile(cmd) let [batchfile, cmd] = s:batchfile(cmd)
endif endif
if s:vim8 && has('gui_running') && !s:is_win return system(cmd)
return s:system_job(cmd)
endif
let ret = system(cmd)
let s:shell_error = v:shell_error
return ret
finally finally
let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
if s:is_win && filereadable(batchfile) if s:is_win && filereadable(batchfile)
@@ -2393,7 +2400,7 @@ endfunction
function! s:system_chomp(...) function! s:system_chomp(...)
let ret = call('s:system', a:000) let ret = call('s:system', a:000)
return s:shell_error ? '' : substitute(ret, '\n$', '', '') return v:shell_error ? '' : substitute(ret, '\n$', '', '')
endfunction endfunction
function! s:git_validate(spec, check_branch) function! s:git_validate(spec, check_branch)
@@ -2407,9 +2414,7 @@ function! s:git_validate(spec, check_branch)
let err = join(['Invalid URI: '.remote, let err = join(['Invalid URI: '.remote,
\ 'Expected: '.a:spec.uri, \ 'Expected: '.a:spec.uri,
\ 'PlugClean required.'], "\n") \ 'PlugClean required.'], "\n")
elseif !a:check_branch elseif a:check_branch && has_key(a:spec, 'commit')
return ['', 0]
elseif has_key(a:spec, 'commit')
let sha = s:git_revision(a:spec.dir) let sha = s:git_revision(a:spec.dir)
if empty(sha) if empty(sha)
let err = join(add(result, 'PlugClean required.'), "\n") let err = join(add(result, 'PlugClean required.'), "\n")
@@ -2418,16 +2423,18 @@ function! s:git_validate(spec, check_branch)
\ a:spec.commit[:6], sha[:6]), \ a:spec.commit[:6], sha[:6]),
\ 'PlugUpdate required.'], "\n") \ 'PlugUpdate required.'], "\n")
endif endif
elseif has_key(a:spec, 'tag') elseif a:check_branch
let current_branch = result[0]
" Check tag
let origin_branch = s:git_origin_branch(a:spec)
if has_key(a:spec, 'tag')
let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir)
if a:spec.tag !=# tag && a:spec.tag !~ '\*' if a:spec.tag !=# tag && a:spec.tag !~ '\*'
let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.', let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.',
\ (empty(tag) ? 'N/A' : tag), a:spec.tag) \ (empty(tag) ? 'N/A' : tag), a:spec.tag)
endif endif
elseif a:check_branch " Check branch
let current_branch = result[0] elseif origin_branch !=# current_branch
let origin_branch = s:git_origin_branch(a:spec)
if origin_branch !=# current_branch
let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.', let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.',
\ current_branch, origin_branch) \ current_branch, origin_branch)
endif endif
@@ -2436,7 +2443,7 @@ function! s:git_validate(spec, check_branch)
\ 'git', 'rev-list', '--count', '--left-right', \ 'git', 'rev-list', '--count', '--left-right',
\ printf('HEAD...origin/%s', origin_branch) \ printf('HEAD...origin/%s', origin_branch)
\ ], a:spec.dir)), '\t') \ ], a:spec.dir)), '\t')
if s:shell_error || len(ahead_behind) != 2 if v:shell_error || len(ahead_behind) != 2
let err = "Failed to compare with the origin. The default branch might have changed.\nPlugClean required." let err = "Failed to compare with the origin. The default branch might have changed.\nPlugClean required."
else else
let [ahead, behind] = ahead_behind let [ahead, behind] = ahead_behind
@@ -2586,7 +2593,7 @@ function! s:upgrade()
try try
let out = s:system(['git', 'clone', '--depth', '1', s:plug_src, tmp]) let out = s:system(['git', 'clone', '--depth', '1', s:plug_src, tmp])
if s:shell_error if v:shell_error
return s:err('Error upgrading vim-plug: '. out) return s:err('Error upgrading vim-plug: '. out)
endif endif

View File

@@ -5,6 +5,10 @@ Execute (#112 On-demand loading should not suppress messages from ftplugin):
Plug '$PLUG_FIXTURES/ftplugin-msg', { 'for': 'c' } Plug '$PLUG_FIXTURES/ftplugin-msg', { 'for': 'c' }
call plug#end() call plug#end()
" Trigger VimEnter (simulate Vim being started), so that s:lod handles
" filetypeindent/filetypeplugin."
doautocmd VimEnter
redir => out redir => out
tabnew a.c tabnew a.c
redir END redir END

View File

@@ -1230,7 +1230,7 @@ Execute (Filetype-based on-demand loading):
AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect'], g:xxx AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect'], g:xxx
setf xxx setf xxx
AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'xxx/plugin', 'xxx/after/plugin', 'xxx/syntax', 'xxx/after/syntax', 'xxx/ftplugin', 'xxx/after/ftplugin', 'xxx/indent', 'xxx/after/indent'], g:xxx AssertEqual ['xxx/ftdetect', 'xxx/after/ftdetect', 'xxx/plugin', 'xxx/after/plugin', 'xxx/syntax', 'xxx/after/syntax'], g:xxx
" syntax/xxx.vim and after/syntax/xxx.vim should not be loaded (#410) " syntax/xxx.vim and after/syntax/xxx.vim should not be loaded (#410)
setf yyy setf yyy