aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Ennen <mike.ennen@gmail.com>2016-10-28 12:38:36 -0700
committerJames McCoy <jamessan@jamessan.com>2016-12-12 10:17:35 -0500
commitc82dc7a6fd4987fee72320133579b008815b28d1 (patch)
tree26768dfc53a53eb1070d577cedb7459894feeab1
parenteb337c9949d679eeb9f0995963c639fdf7772fd4 (diff)
downloadrneovim-c82dc7a6fd4987fee72320133579b008815b28d1.tar.gz
rneovim-c82dc7a6fd4987fee72320133579b008815b28d1.tar.bz2
rneovim-c82dc7a6fd4987fee72320133579b008815b28d1.zip
vim-patch:7.4.1836
Problem: When using a partial on a dictionary it always gets bound to that dictionary. Solution: Make a difference between binding a function to a dictionary explicitly or automatically. https://github.com/vim/vim/commit/1d429610bf9e99a6252be8abbc910d6667e4d1da
-rw-r--r--runtime/doc/eval.txt41
-rw-r--r--src/nvim/eval.c30
-rw-r--r--src/nvim/eval_defs.h2
-rw-r--r--src/nvim/version.c3
4 files changed, 63 insertions, 13 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index f377ebdf31..133f35990c 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,6 +1,5 @@
*eval.txt* For Vim version 7.4. Last change: 2016 Jun 04
-
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -49,6 +48,9 @@ String A NUL terminated string of 8-bit unsigned characters (bytes).
Funcref A reference to a function |Funcref|.
Example: function("strlen")
+ It can be bound to a dictionary and arguments, it then works
+ like a Partial.
+ Example: function("Callback", [arg], myDict)
List An ordered sequence of items |List|.
Example: [1, 2, ['a', 'b']]
@@ -139,6 +141,43 @@ The name of the referenced function can be obtained with |string()|. >
You can use |call()| to invoke a Funcref and use a list variable for the
arguments: >
:let r = call(Fn, mylist)
+<
+ *Partial*
+A Funcref optionally binds a Dictionary and/or arguments. This is also called
+a Partial. This is created by passing the Dictionary and/or arguments to
+function(). When calling the function the Dictionary and/or arguments will be
+passed to the function. Example: >
+
+ let Cb = function('Callback', ['foo'], myDict)
+ call Cb()
+
+This will invoke the function as if using: >
+ call myDict.Callback('foo')
+
+This is very useful when passing a function around, e.g. in the arguments of
+|ch_open()|.
+
+Note that binding a function to a Dictionary also happens when the function is
+a member of the Dictionary: >
+
+ let myDict.myFunction = MyFunction
+ call myDict.myFunction()
+
+Here MyFunction() will get myDict passed as "self". This happens when the
+"myFunction" member is accessed. When making assigning "myFunction" to
+otherDict and calling it, it will be bound to otherDict: >
+
+ let otherDict.myFunction = myDict.myFunction
+ call otherDict.myFunction()
+
+Now "self" will be "otherDict". But when the dictionary was bound explicitly
+this won't happen: >
+
+ let myDict.myFunction = function(MyFunction, myDict)
+ let otherDict.myFunction = myDict.myFunction
+ call otherDict.myFunction()
+
+Here "self" will be "myDict", because it was bound explitly.
1.3 Lists ~
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 2888ddc82d..14e6003ca0 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -7099,12 +7099,11 @@ call_func(
*doesrange = FALSE;
if (partial != NULL) {
- if (partial->pt_dict != NULL) {
- // When the function has a partial with a dict and there is a dict
- // argument, use the dict argument. That is backwards compatible.
- if (selfdict_in == NULL) {
- selfdict = partial->pt_dict;
- }
+ // When the function has a partial with a dict and there is a dict
+ // argument, use the dict argument. That is backwards compatible.
+ // When the dict was bound explicitly use the one from the partial.
+ if (partial->pt_dict != NULL
+ && (selfdict_in == NULL || !partial->pt_auto)) {
selfdict = partial->pt_dict;
}
if (error == ERROR_NONE && partial->pt_argc > 0) {
@@ -9643,10 +9642,14 @@ static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// For "function(dict.func, [], dict)" and "func" is a partial
// use "dict". That is backwards compatible.
if (dict_idx > 0) {
- pt->pt_dict = argvars[dict_idx].vval.v_dict;
- (pt->pt_dict->dv_refcount)++;
+ // The dict is bound explicitly, pt_auto is false
+ pt->pt_dict = argvars[dict_idx].vval.v_dict;
+ (pt->pt_dict->dv_refcount)++;
} else if (arg_pt != NULL) {
+ // If the dict was bound automatically the result is also
+ // bound automatically.
pt->pt_dict = arg_pt->pt_dict;
+ pt->pt_auto = arg_pt->pt_auto;
if (pt->pt_dict != NULL) {
(pt->pt_dict->dv_refcount)++;
}
@@ -18424,8 +18427,14 @@ handle_subscript (
}
}
- if ((rettv->v_type == VAR_FUNC || rettv->v_type == VAR_PARTIAL)
- && selfdict != NULL) {
+ // Turn "dict.Func" into a partial for "Func" bound to "dict".
+ // Don't do this when "Func" is already a partial that was bound
+ // explicitly (pt_auto is false).
+ if (self != NULL
+ && (rettv->v_type == VAR_FUNC
+ || (rettv->v_type == VAR_PARTIAL
+ && (rettv->vval.v_partial->pt_auto
+ || rettv->vval.v_partial->pt_dict == NULL)))) {
char_u *fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
: rettv->vval.v_partial->pt_name;
char_u *tofree = NULL;
@@ -18446,6 +18455,7 @@ handle_subscript (
if (pt != NULL) {
pt->pt_refcount = 1;
pt->pt_dict = selfdict;
+ pt->pt_auto = true;
selfdict = NULL;
if (rettv->v_type == VAR_FUNC) {
// Just a function: Take over the function name and use
diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h
index a33ac10e61..74d0782356 100644
--- a/src/nvim/eval_defs.h
+++ b/src/nvim/eval_defs.h
@@ -150,6 +150,8 @@ struct dictvar_S {
struct partial_S {
int pt_refcount; ///< Reference count.
char_u *pt_name; ///< Function name.
+ bool pt_auto; ///< when true the partial was created for using
+ ///< dict.member in handle_subscript().
int pt_argc; ///< Number of arguments.
typval_T *pt_argv; ///< Arguments in allocated array.
dict_T *pt_dict; ///< Dict for "self".
diff --git a/src/nvim/version.c b/src/nvim/version.c
index f091b12810..88c0185f57 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -604,9 +604,8 @@ static int included_patches[] = {
// 1839,
// 1838,
// 1837,
- // 1836,
+ 1836,
1835,
- // 1834,
1833,
1832,
1831,