diff options
-rw-r--r-- | runtime/doc/job_control.txt | 12 | ||||
-rw-r--r-- | src/nvim/eval.c | 10 | ||||
-rw-r--r-- | test/functional/core/job_spec.lua | 20 | ||||
-rw-r--r-- | test/functional/helpers.lua | 26 | ||||
-rw-r--r-- | test/functional/legacy/061_undo_tree_spec.lua | 2 |
5 files changed, 50 insertions, 20 deletions
diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt index 5cb172f90a..1aa7ce06d6 100644 --- a/runtime/doc/job_control.txt +++ b/runtime/doc/job_control.txt @@ -40,7 +40,7 @@ for details. Job control is achieved by calling a combination of the |jobstart()|, |jobsend()| and |jobstop()| functions. Here's an example: > - function! s:JobHandler(job_id, data, event) + function! s:JobHandler(job_id, data, event) dict if a:event == 'stdout' let str = self.shell.' stdout: '.join(a:data) elseif a:event == 'stderr' @@ -102,23 +102,23 @@ function. Here's a more object-oriented version of the above: > let Shell = {} - function Shell.on_stdout(job_id, data) + function Shell.on_stdout(job_id, data) dict call append(line('$'), self.get_name().' stdout: '.join(a:data)) endfunction - function Shell.on_stderr(job_id, data) + function Shell.on_stderr(job_id, data) dict call append(line('$'), self.get_name().' stderr: '.join(a:data)) endfunction - function Shell.on_exit(job_id, data) + function Shell.on_exit(job_id, data) dict call append(line('$'), self.get_name().' exited') endfunction - function Shell.get_name() + function Shell.get_name() dict return 'shell '.self.name endfunction - function Shell.new(name, ...) + function Shell.new(name, ...) dict let instance = extend(copy(g:Shell), {'name': a:name}) let argv = ['bash'] if a:0 > 0 diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a205c37d6e..982074f62a 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -18665,15 +18665,17 @@ handle_subscript ( return ret; } -static void set_selfdict(typval_T *rettv, dict_T *selfdict) { +static void set_selfdict(typval_T *rettv, dict_T *selfdict) +{ // Don't do this when "dict.Func" is already a partial that was bound // explicitly (pt_auto is false). if (rettv->v_type == VAR_PARTIAL && !rettv->vval.v_partial->pt_auto && rettv->vval.v_partial->pt_dict != NULL) { return; } - char_u *fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string - : rettv->vval.v_partial->pt_name; + char_u *fname = rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING + ? rettv->vval.v_string + : rettv->vval.v_partial->pt_name; char_u *tofree = NULL; ufunc_T *fp; char_u fname_buf[FLEN_FIXED + 1]; @@ -18694,7 +18696,7 @@ static void set_selfdict(typval_T *rettv, dict_T *selfdict) { pt->pt_dict = selfdict; (selfdict->dv_refcount)++; pt->pt_auto = true; - if (rettv->v_type == VAR_FUNC) { + if (rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING) { // Just a function: Take over the function name and use selfdict. pt->pt_name = rettv->vval.v_string; } else { diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index fa38671529..e27adc1a51 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -303,6 +303,26 @@ describe('jobs', function() ]]) end) + it('requires funcrefs for script-local (s:) functions', function() + -- Pass job callback names _without_ `function(...)`. + source([[ + function! s:OnEvent(id, data, event) dict + let g:job_result = get(self, 'user') + endfunction + let s:job = jobstart(['echo'], { + \ 'on_stdout': 's:OnEvent', + \ 'on_stderr': 's:OnEvent', + \ 'on_exit': 's:OnEvent', + \ 'user': 2349 + \ }) + ]]) + + -- The behavior is asynchronous, retry until a time limit. + helpers.retry(nil, 10000, function() + eq("E120:", string.match(eval("v:errmsg"), "E%d*:")) + end) + end) + describe('jobwait', function() it('returns a list of status codes', function() source([[ diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index d1ab02f361..f3332cff4f 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -1,4 +1,5 @@ require('coxpcall') +local luv = require('luv') local lfs = require('lfs') local global_helpers = require('test.helpers') @@ -243,17 +244,24 @@ local function connect(file_or_address) return Session.new(stream) end --- Calls fn() until it returns without error, up to `max` times. -local function retry(fn, max) - local retries = max and (max - 1) or 2 - for _ = 1, retries do - local success = pcall(fn) - if success then - return +-- Calls fn() until it succeeds, up to `max` times or until `max_ms` +-- milliseconds have passed. +local function retry(max, max_ms, fn) + local tries = 1 + local timeout = (max_ms and max_ms > 0) and max_ms or 10000 + local start_time = luv.now() + while true do + local status, result = pcall(fn) + if status then + return result + end + if (max and tries >= max) or (luv.now() - start_time > timeout) then + break end + tries = tries + 1 end - -- pcall() is not used for the final attempt so failure can bubble up. - fn() + -- Do not use pcall() for the final attempt, let the failure bubble up. + return fn() end local function clear(...) diff --git a/test/functional/legacy/061_undo_tree_spec.lua b/test/functional/legacy/061_undo_tree_spec.lua index 2069204938..aeb2001d11 100644 --- a/test/functional/legacy/061_undo_tree_spec.lua +++ b/test/functional/legacy/061_undo_tree_spec.lua @@ -98,7 +98,7 @@ describe('undo tree:', function() expect_line('123456abc') end - helpers.retry(test_earlier_later) + helpers.retry(2, nil, test_earlier_later) end) it('file-write specifications', function() |