aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/provider/clipboard.vim16
-rw-r--r--runtime/autoload/provider/node.vim4
-rw-r--r--runtime/autoload/provider/python.vim6
-rw-r--r--runtime/autoload/provider/python3.vim6
-rw-r--r--runtime/autoload/provider/ruby.vim3
-rw-r--r--runtime/doc/develop.txt6
-rw-r--r--src/nvim/eval.c61
-rw-r--r--test/functional/fixtures/autoload/provider/brokencall.vim2
-rw-r--r--test/functional/fixtures/autoload/provider/brokenenabled.vim6
-rw-r--r--test/functional/fixtures/autoload/provider/clipboard.vim1
-rw-r--r--test/functional/provider/provider_spec.lua19
11 files changed, 68 insertions, 62 deletions
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 2b06ee8c48..e43f8fbb7a 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -48,6 +48,9 @@ endfunction
let s:cache_enabled = 1
let s:err = ''
+" eval_has_provider checks the variable to verify provider status
+let g:provider#clipboard#enabled = 0
+
function! provider#clipboard#Error() abort
return s:err
endfunction
@@ -120,12 +123,11 @@ function! provider#clipboard#Executable() abort
return ''
endfunction
-if empty(provider#clipboard#Executable())
- " provider#clipboard#Call() *must not* be defined if the provider is broken.
- " Otherwise eval_has_provider() thinks the clipboard provider is
- " functioning, and eval_call_provider() will happily call it.
- finish
-endif
+" Call this to setup/reload the provider
+function! provider#clipboard#Reload()
+ " #enabled is used by eval_has_provider()
+ let g:provider#clipboard#enabled = !empty(provider#clipboard#Executable())
+endfunction
function! s:clipboard.get(reg) abort
if type(s:paste[a:reg]) == v:t_func
@@ -192,3 +194,5 @@ function! provider#clipboard#Call(method, args) abort
let s:here = v:false
endtry
endfunction
+
+call provider#clipboard#Reload()
diff --git a/runtime/autoload/provider/node.vim b/runtime/autoload/provider/node.vim
index 35882849bd..6413720605 100644
--- a/runtime/autoload/provider/node.vim
+++ b/runtime/autoload/provider/node.vim
@@ -2,6 +2,7 @@ if exists('g:loaded_node_provider')
finish
endif
let g:loaded_node_provider = 1
+let g:provider#node#enabled = 0
function! s:is_minimum_version(version, min_major, min_minor) abort
if empty(a:version)
@@ -143,6 +144,9 @@ let s:prog = provider#node#Detect()
if empty(s:prog)
let s:err = 'Cannot find the "neovim" node package. Try :checkhealth'
+else
+ let g:provider#node#enabled = 1
endif
call remote#host#RegisterPlugin('node-provider', 'node', [])
+
diff --git a/runtime/autoload/provider/python.vim b/runtime/autoload/provider/python.vim
index a06cbe4814..d65506a55a 100644
--- a/runtime/autoload/provider/python.vim
+++ b/runtime/autoload/provider/python.vim
@@ -10,6 +10,7 @@ endif
let g:loaded_python_provider = 1
let [s:prog, s:err] = provider#pythonx#Detect(2)
+let g:provider#python#enabled = !empty(s:prog)
function! provider#python#Prog() abort
return s:prog
@@ -19,11 +20,6 @@ function! provider#python#Error() abort
return s:err
endfunction
-if s:prog == ''
- " Detection failed
- finish
-endif
-
" The Python provider plugin will run in a separate instance of the Python
" host.
call remote#host#RegisterClone('legacy-python-provider', 'python')
diff --git a/runtime/autoload/provider/python3.vim b/runtime/autoload/provider/python3.vim
index 242a224cb3..469611c7ce 100644
--- a/runtime/autoload/provider/python3.vim
+++ b/runtime/autoload/provider/python3.vim
@@ -10,6 +10,7 @@ endif
let g:loaded_python3_provider = 1
let [s:prog, s:err] = provider#pythonx#Detect(3)
+let g:provider#python3#enabled = !empty(s:prog)
function! provider#python3#Prog() abort
return s:prog
@@ -19,11 +20,6 @@ function! provider#python3#Error() abort
return s:err
endfunction
-if s:prog == ''
- " Detection failed
- finish
-endif
-
" The Python3 provider plugin will run in a separate instance of the Python3
" host.
call remote#host#RegisterClone('legacy-python3-provider', 'python3')
diff --git a/runtime/autoload/provider/ruby.vim b/runtime/autoload/provider/ruby.vim
index 3b4c6c4839..df43dffa40 100644
--- a/runtime/autoload/provider/ruby.vim
+++ b/runtime/autoload/provider/ruby.vim
@@ -7,6 +7,7 @@ let g:loaded_ruby_provider = 1
function! provider#ruby#Detect() abort
return s:prog
endfunction
+let g:provider#ruby#enabled = 0
function! provider#ruby#Prog() abort
return s:prog
@@ -65,6 +66,8 @@ let s:plugin_path = expand('<sfile>:p:h') . '/script_host.rb'
if empty(s:prog)
let s:err = 'Cannot find the neovim RubyGem. Try :checkhealth'
+else
+ let g:provider#ruby#enabled = 1
endif
call remote#host#RegisterClone('legacy-ruby-provider', 'ruby')
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index 843e23ee54..0f9e17e697 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -111,7 +111,7 @@ functions in eval.c:
- eval_call_provider(name, method, arguments): calls provider#(name)#Call
with the method and arguments.
- eval_has_provider(name): Checks if a provider is implemented. Returns true
- if the provider#(name)#Call function is implemented. Called by |has()|
+ if the provider#(name)#enabled variable is not 0. Called by |has()|
(vimscript) to check if features are available.
The provider#(name)#Call function implements integration with an external
@@ -119,8 +119,8 @@ system, because shell commands and |RPC| clients are easier to work with in
vimscript.
For example, the Python provider is implemented by the
-autoload/provider/python.vim script; the provider#python#Call function is only
-defined if a valid external Python host is found. That works well with the
+autoload/provider/python.vim script; the variable provider#python#enabled is only
+1 if a valid external Python host is found. That works well with the
`has('python')` expression (normally used by Python plugins) because if the
Python host isn't installed then the plugin will "think" it is running in
a Vim compiled without the "+python" feature.
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index cefd351dd7..ed01ca9f99 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -23968,52 +23968,27 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
return rettv;
}
-bool eval_has_provider(const char *name)
-{
-#define CHECK_PROVIDER(name) \
- if (has_##name == -1) { \
- has_##name = !!find_func((char_u *)"provider#" #name "#Call"); \
- if (!has_##name) { \
- script_autoload("provider#" #name "#Call", \
- sizeof("provider#" #name "#Call") - 1, \
- false); \
- has_##name = !!find_func((char_u *)"provider#" #name "#Call"); \
- } \
- }
-
- static int has_clipboard = -1;
- static int has_python = -1;
- static int has_python3 = -1;
- static int has_ruby = -1;
- typval_T args[1];
- args[0].v_type = VAR_UNKNOWN;
-
- if (strequal(name, "clipboard")) {
- CHECK_PROVIDER(clipboard);
- return has_clipboard;
- } else if (strequal(name, "python3")) {
- CHECK_PROVIDER(python3);
- return has_python3;
- } else if (strequal(name, "python")) {
- CHECK_PROVIDER(python);
- return has_python;
- } else if (strequal(name, "ruby")) {
- bool need_check_ruby = (has_ruby == -1);
- CHECK_PROVIDER(ruby);
- if (need_check_ruby && has_ruby == 1) {
- char *rubyhost = call_func_retstr("provider#ruby#Detect", 0, args, true);
- if (rubyhost) {
- if (*rubyhost == NUL) {
- // Invalid rubyhost executable. Gem is probably not installed.
- has_ruby = 0;
- }
- xfree(rubyhost);
- }
+/// Check if a named provider is enabled
+bool eval_has_provider(const char *provider)
+{
+ char enabled_varname[256];
+ int enabled_varname_len = snprintf(enabled_varname, sizeof(enabled_varname),
+ "provider#%s#enabled", provider);
+
+ typval_T tv;
+ if (get_var_tv(enabled_varname, enabled_varname_len, &tv,
+ NULL, false, false) == FAIL) {
+ char call_varname[256];
+ snprintf(call_varname, sizeof(call_varname), "provider#%s#Call", provider);
+ int has_call = !!find_func((char_u *)call_varname);
+
+ if (has_call && p_lpl) {
+ emsgf("Provider '%s' failed to set %s", provider, enabled_varname);
}
- return has_ruby;
+ return false;
}
- return false;
+ return (tv.v_type == VAR_NUMBER) ? tv.vval.v_number != 0: true;
}
/// Writes "<sourcing_name>:<sourcing_lnum>" to `buf[bufsize]`.
diff --git a/test/functional/fixtures/autoload/provider/brokencall.vim b/test/functional/fixtures/autoload/provider/brokencall.vim
new file mode 100644
index 0000000000..2c83dd2b4a
--- /dev/null
+++ b/test/functional/fixtures/autoload/provider/brokencall.vim
@@ -0,0 +1,2 @@
+" A dummy test provider
+let g:provider#brokencall#enabled = 1
diff --git a/test/functional/fixtures/autoload/provider/brokenenabled.vim b/test/functional/fixtures/autoload/provider/brokenenabled.vim
new file mode 100644
index 0000000000..54ed11cedc
--- /dev/null
+++ b/test/functional/fixtures/autoload/provider/brokenenabled.vim
@@ -0,0 +1,6 @@
+" Dummy test provider, missing
+" let g:provider#brokenenabled#enabled = 0
+
+function! provider#brokenenabled#Call(method, args)
+ return 42
+endfunction
diff --git a/test/functional/fixtures/autoload/provider/clipboard.vim b/test/functional/fixtures/autoload/provider/clipboard.vim
index 6d777255c8..d1ddd81b12 100644
--- a/test/functional/fixtures/autoload/provider/clipboard.vim
+++ b/test/functional/fixtures/autoload/provider/clipboard.vim
@@ -35,6 +35,7 @@ function! s:methods.set(lines, regtype, reg)
let g:test_clip[a:reg] = [a:lines, a:regtype]
endfunction
+let provider#clipboard#enabled = 1
function! provider#clipboard#Call(method, args)
return call(s:methods[a:method],a:args,s:methods)
diff --git a/test/functional/provider/provider_spec.lua b/test/functional/provider/provider_spec.lua
new file mode 100644
index 0000000000..6f414f36f4
--- /dev/null
+++ b/test/functional/provider/provider_spec.lua
@@ -0,0 +1,19 @@
+
+local helpers = require('test.functional.helpers')(after_each)
+local clear, eq, feed_command, eval = helpers.clear, helpers.eq, helpers.feed_command, helpers.eval
+
+describe('Providers', function()
+ before_each(function()
+ clear('--cmd', 'let &rtp = "test/functional/fixtures,".&rtp')
+ end)
+
+ it('must set the enabled variable or fail', function()
+ eq(42, eval("provider#brokenenabled#Call('dosomething', [])"))
+ feed_command("call has('brokenenabled')")
+ eq(0, eval("has('brokenenabled')"))
+ end)
+
+ it('without Call() are enabled', function()
+ eq(1, eval("has('brokencall')"))
+ end)
+end)