summaryrefslogtreecommitdiffstats
path: root/src/evalfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/evalfunc.c')
-rw-r--r--src/evalfunc.c286
1 files changed, 271 insertions, 15 deletions
diff --git a/src/evalfunc.c b/src/evalfunc.c
index e37b3a4..14650ca 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -63,15 +63,16 @@ static void f_get(typval_T *argvars, typval_T *rettv);
static void f_getchangelist(typval_T *argvars, typval_T *rettv);
static void f_getcharpos(typval_T *argvars, typval_T *rettv);
static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
+static void f_getcurpos(typval_T *argvars, typval_T *rettv);
+static void f_getcursorcharpos(typval_T *argvars, typval_T *rettv);
static void f_getenv(typval_T *argvars, typval_T *rettv);
static void f_getfontname(typval_T *argvars, typval_T *rettv);
static void f_getjumplist(typval_T *argvars, typval_T *rettv);
static void f_getpid(typval_T *argvars, typval_T *rettv);
-static void f_getcurpos(typval_T *argvars, typval_T *rettv);
-static void f_getcursorcharpos(typval_T *argvars, typval_T *rettv);
static void f_getpos(typval_T *argvars, typval_T *rettv);
static void f_getreg(typval_T *argvars, typval_T *rettv);
static void f_getreginfo(typval_T *argvars, typval_T *rettv);
+static void f_getregion(typval_T *argvars, typval_T *rettv);
static void f_getregtype(typval_T *argvars, typval_T *rettv);
static void f_gettagstack(typval_T *argvars, typval_T *rettv);
static void f_gettext(typval_T *argvars, typval_T *rettv);
@@ -607,10 +608,11 @@ arg_list_or_dict_or_blob_or_string_mod(
}
/*
- * Check second argument of map() or filter().
+ * Check second argument of map(), filter(), foreach().
*/
static int
-check_map_filter_arg2(type_T *type, argcontext_T *context, int is_map)
+check_map_filter_arg2(type_T *type, argcontext_T *context,
+ filtermap_T filtermap)
{
type_T *expected_member = NULL;
type_T *(args[2]);
@@ -663,12 +665,14 @@ check_map_filter_arg2(type_T *type, argcontext_T *context, int is_map)
{
where_T where = WHERE_INIT;
- if (is_map)
+ if (filtermap == FILTERMAP_MAP)
t_func_exp.tt_member = expected_member == NULL
|| type_any_or_unknown(type->tt_member)
? &t_any : expected_member;
- else
+ else if (filtermap == FILTERMAP_FILTER)
t_func_exp.tt_member = &t_bool;
+ else // filtermap == FILTERMAP_FOREACH
+ t_func_exp.tt_member = &t_unknown;
if (args[0] == NULL)
args[0] = &t_unknown;
if (type->tt_argcount == -1)
@@ -693,7 +697,7 @@ arg_filter_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
return OK;
if (type->tt_type == VAR_FUNC)
- return check_map_filter_arg2(type, context, FALSE);
+ return check_map_filter_arg2(type, context, FILTERMAP_FILTER);
semsg(_(e_string_or_function_required_for_argument_nr), 2);
return FAIL;
}
@@ -710,7 +714,24 @@ arg_map_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
return OK;
if (type->tt_type == VAR_FUNC)
- return check_map_filter_arg2(type, context, TRUE);
+ return check_map_filter_arg2(type, context, FILTERMAP_MAP);
+ semsg(_(e_string_or_function_required_for_argument_nr), 2);
+ return FAIL;
+}
+
+/*
+ * Check second argument of foreach(), the function.
+ */
+ static int
+arg_foreach_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
+{
+ if (type->tt_type == VAR_STRING
+ || type->tt_type == VAR_PARTIAL
+ || type_any_or_unknown(type))
+ return OK;
+
+ if (type->tt_type == VAR_FUNC)
+ return check_map_filter_arg2(type, context, FILTERMAP_FOREACH);
semsg(_(e_string_or_function_required_for_argument_nr), 2);
return FAIL;
}
@@ -965,6 +986,7 @@ arg_len1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|| type->tt_type == VAR_BLOB
|| type->tt_type == VAR_LIST
|| type->tt_type == VAR_DICT
+ || type->tt_type == VAR_OBJECT
|| type_any_or_unknown(type))
return OK;
@@ -1128,7 +1150,9 @@ static argcheck_T arg3_buffer_number_number[] = {arg_buffer, arg_number, arg_num
static argcheck_T arg3_buffer_string_any[] = {arg_buffer, arg_string, arg_any};
static argcheck_T arg3_buffer_string_dict[] = {arg_buffer, arg_string, arg_dict_any};
static argcheck_T arg3_dict_number_number[] = {arg_dict_any, arg_number, arg_number};
+static argcheck_T arg3_diff[] = {arg_list_string, arg_list_string, arg_dict_any};
static argcheck_T arg3_list_string_dict[] = {arg_list_any, arg_string, arg_dict_any};
+static argcheck_T arg3_list_list_dict[] = {arg_list_any, arg_list_any, arg_dict_any};
static argcheck_T arg3_lnum_number_bool[] = {arg_lnum, arg_number, arg_bool};
static argcheck_T arg3_number[] = {arg_number, arg_number, arg_number};
static argcheck_T arg3_number_any_dict[] = {arg_number, arg_any, arg_dict_any};
@@ -1173,6 +1197,7 @@ static argcheck_T arg1_len[] = {arg_len1};
static argcheck_T arg3_libcall[] = {arg_string, arg_string, arg_string_or_nr};
static argcheck_T arg14_maparg[] = {arg_string, arg_string, arg_bool, arg_bool};
static argcheck_T arg2_filter[] = {arg_list_or_dict_or_blob_or_string_mod, arg_filter_func};
+static argcheck_T arg2_foreach[] = {arg_list_or_dict_or_blob_or_string, arg_foreach_func};
static argcheck_T arg2_instanceof[] = {arg_object, varargs_class, NULL };
static argcheck_T arg2_map[] = {arg_list_or_dict_or_blob_or_string_mod, arg_map_func};
static argcheck_T arg2_mapnew[] = {arg_list_or_dict_or_blob_or_string, arg_any};
@@ -1929,6 +1954,8 @@ static funcentry_T global_functions[] =
ret_number_bool, f_deletebufline},
{"did_filetype", 0, 0, 0, NULL,
ret_number_bool, f_did_filetype},
+ {"diff", 2, 3, FEARG_1, arg3_diff,
+ ret_any, f_diff},
{"diff_filler", 1, 1, FEARG_1, arg1_lnum,
ret_number, f_diff_filler},
{"diff_hlID", 2, 2, FEARG_1, arg2_lnum_number,
@@ -2013,6 +2040,8 @@ static funcentry_T global_functions[] =
ret_string, f_foldtext},
{"foldtextresult", 1, 1, FEARG_1, arg1_lnum,
ret_string, f_foldtextresult},
+ {"foreach", 2, 2, FEARG_1, arg2_foreach,
+ ret_first_arg, f_foreach},
{"foreground", 0, 0, 0, NULL,
ret_void, f_foreground},
{"fullcommand", 1, 2, FEARG_1, arg2_string_bool,
@@ -2105,6 +2134,8 @@ static funcentry_T global_functions[] =
ret_getreg, f_getreg},
{"getreginfo", 0, 1, FEARG_1, arg1_string,
ret_dict_any, f_getreginfo},
+ {"getregion", 2, 3, FEARG_1, arg3_list_list_dict,
+ ret_list_string, f_getregion},
{"getregtype", 0, 1, FEARG_1, arg1_string,
ret_string, f_getregtype},
{"getscriptinfo", 0, 1, 0, arg1_dict_any,
@@ -3606,7 +3637,7 @@ get_col(typval_T *argvars, typval_T *rettv, int charcol)
{
// '> can be MAXCOL, get the length of the line then
if (fp->lnum <= curbuf->b_ml.ml_line_count)
- col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
+ col = ml_get_len(fp->lnum) + 1;
else
col = MAXCOL;
}
@@ -3951,7 +3982,7 @@ f_empty(typval_T *argvars, typval_T *rettv)
n = argvars[0].vval.v_class != NULL;
break;
case VAR_OBJECT:
- n = argvars[0].vval.v_object != NULL;
+ n = object_empty(argvars[0].vval.v_object);
break;
case VAR_BLOB:
@@ -5427,6 +5458,229 @@ f_getpos(typval_T *argvars, typval_T *rettv)
}
/*
+ * Convert from block_def to string
+ */
+ static char_u *
+block_def2str(struct block_def *bd)
+{
+ char_u *p, *ret;
+ size_t size = bd->startspaces + bd->endspaces + bd->textlen;
+
+ ret = alloc(size + 1);
+ if (ret != NULL)
+ {
+ p = ret;
+ vim_memset(p, ' ', bd->startspaces);
+ p += bd->startspaces;
+ mch_memmove(p, bd->textstart, bd->textlen);
+ p += bd->textlen;
+ vim_memset(p, ' ', bd->endspaces);
+ *(p + bd->endspaces) = NUL;
+ }
+ return ret;
+}
+
+/*
+ * "getregion()" function
+ */
+ static void
+f_getregion(typval_T *argvars, typval_T *rettv)
+{
+ linenr_T lnum;
+ oparg_T oa;
+ struct block_def bd;
+ char_u *akt = NULL;
+ int inclusive = TRUE;
+ int fnum1 = -1, fnum2 = -1;
+ pos_T p1, p2;
+ char_u *type;
+ buf_T *save_curbuf;
+ buf_T *findbuf;
+ char_u default_type[] = "v";
+ int save_virtual;
+ int l;
+ int region_type = -1;
+ int is_select_exclusive;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+
+ if (check_for_list_arg(argvars, 0) == FAIL
+ || check_for_list_arg(argvars, 1) == FAIL
+ || check_for_opt_dict_arg(argvars, 2) == FAIL)
+ return;
+
+ if (list2fpos(&argvars[0], &p1, &fnum1, NULL, FALSE) != OK
+ || list2fpos(&argvars[1], &p2, &fnum2, NULL, FALSE) != OK
+ || fnum1 != fnum2)
+ return;
+
+ if (argvars[2].v_type == VAR_DICT)
+ {
+ is_select_exclusive = dict_get_bool(
+ argvars[2].vval.v_dict, "exclusive", *p_sel == 'e');
+ type = dict_get_string(
+ argvars[2].vval.v_dict, "type", FALSE);
+ if (type == NULL)
+ type = default_type;
+ }
+ else
+ {
+ is_select_exclusive = *p_sel == 'e';
+ type = default_type;
+ }
+
+ if (type[0] == 'v' && type[1] == NUL)
+ region_type = MCHAR;
+ else if (type[0] == 'V' && type[1] == NUL)
+ region_type = MLINE;
+ else if (type[0] == Ctrl_V && type[1] == NUL)
+ region_type = MBLOCK;
+ else
+ {
+ semsg(_(e_invalid_value_for_argument_str_str), "type", type);
+ return;
+ }
+
+ findbuf = fnum1 != 0 ? buflist_findnr(fnum1) : curbuf;
+ if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL)
+ {
+ emsg(_(e_buffer_is_not_loaded));
+ return;
+ }
+
+ if (p1.lnum < 1 || p1.lnum > findbuf->b_ml.ml_line_count)
+ {
+ semsg(_(e_invalid_line_number_nr), p1.lnum);
+ return;
+ }
+ if (p1.col < 1 || p1.col > ml_get_buf_len(findbuf, p1.lnum) + 1)
+ {
+ semsg(_(e_invalid_column_number_nr), p1.col);
+ return;
+ }
+ if (p2.lnum < 1 || p2.lnum > findbuf->b_ml.ml_line_count)
+ {
+ semsg(_(e_invalid_line_number_nr), p2.lnum);
+ return;
+ }
+ if (p2.col < 1 || p2.col > ml_get_buf_len(findbuf, p2.lnum) + 1)
+ {
+ semsg(_(e_invalid_column_number_nr), p2.col);
+ return;
+ }
+
+ save_curbuf = curbuf;
+ curbuf = findbuf;
+ curwin->w_buffer = curbuf;
+ save_virtual = virtual_op;
+ virtual_op = virtual_active();
+
+ // NOTE: Adjust is needed.
+ p1.col--;
+ p2.col--;
+
+ if (!LT_POS(p1, p2))
+ {
+ // swap position
+ pos_T p;
+
+ p = p1;
+ p1 = p2;
+ p2 = p;
+ }
+
+ if (region_type == MCHAR)
+ {
+ // handle 'selection' == "exclusive"
+ if (is_select_exclusive && !EQUAL_POS(p1, p2))
+ {
+ if (p2.coladd > 0)
+ p2.coladd--;
+ else if (p2.col > 0)
+ {
+ p2.col--;
+
+ mb_adjustpos(curbuf, &p2);
+ }
+ else if (p2.lnum > 1)
+ {
+ p2.lnum--;
+ p2.col = ml_get_len(p2.lnum);
+ if (p2.col > 0)
+ {
+ p2.col--;
+
+ mb_adjustpos(curbuf, &p2);
+ }
+ }
+ }
+ // if fp2 is on NUL (empty line) inclusive becomes false
+ if (*ml_get_pos(&p2) == NUL && !virtual_op)
+ inclusive = FALSE;
+ }
+ else if (region_type == MBLOCK)
+ {
+ colnr_T sc1, ec1, sc2, ec2;
+
+ getvvcol(curwin, &p1, &sc1, NULL, &ec1);
+ getvvcol(curwin, &p2, &sc2, NULL, &ec2);
+ oa.motion_type = MBLOCK;
+ oa.inclusive = TRUE;
+ oa.op_type = OP_NOP;
+ oa.start = p1;
+ oa.end = p2;
+ oa.start_vcol = MIN(sc1, sc2);
+ if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1)
+ oa.end_vcol = sc2 - 1;
+ else
+ oa.end_vcol = MAX(ec1, ec2);
+ }
+
+ // Include the trailing byte of a multi-byte char.
+ l = utfc_ptr2len((char_u *)ml_get_pos(&p2));
+ if (l > 1)
+ p2.col += l - 1;
+
+ for (lnum = p1.lnum; lnum <= p2.lnum; lnum++)
+ {
+ int ret = 0;
+
+ if (region_type == MLINE)
+ akt = vim_strsave(ml_get(lnum));
+ else if (region_type == MBLOCK)
+ {
+ block_prep(&oa, &bd, lnum, FALSE);
+ akt = block_def2str(&bd);
+ }
+ else if (p1.lnum < lnum && lnum < p2.lnum)
+ akt = vim_strsave(ml_get(lnum));
+ else
+ {
+ charwise_block_prep(p1, p2, &bd, lnum, inclusive);
+ akt = block_def2str(&bd);
+ }
+
+ if (akt)
+ {
+ ret = list_append_string(rettv->vval.v_list, akt, -1);
+ vim_free(akt);
+ }
+
+ if (akt == NULL || ret == FAIL)
+ {
+ clear_tv(rettv);
+ (void)rettv_list_alloc(rettv);
+ break;
+ }
+ }
+
+ curbuf = save_curbuf;
+ curwin->w_buffer = curbuf;
+ virtual_op = save_virtual;
+}
+
+/*
* Common between getreg(), getreginfo() and getregtype(): get the register
* name from the first argument.
* Returns zero on error.
@@ -7613,6 +7867,9 @@ f_len(typval_T *argvars, typval_T *rettv)
case VAR_DICT:
rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
break;
+ case VAR_OBJECT:
+ rettv->vval.v_number = object_len(argvars[0].vval.v_object);
+ break;
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_VOID:
@@ -7625,7 +7882,6 @@ f_len(typval_T *argvars, typval_T *rettv)
case VAR_CHANNEL:
case VAR_INSTR:
case VAR_CLASS:
- case VAR_OBJECT:
case VAR_TYPEALIAS:
emsg(_(e_invalid_type_for_len));
break;
@@ -10878,7 +11134,7 @@ f_synID(typval_T *argvars UNUSED, typval_T *rettv)
trans = (int)tv_get_bool_chk(&argvars[2], &transerr);
if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
- && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
+ && col >= 0 && col < (long)ml_get_len(lnum))
id = syn_get_id(curwin, lnum, col, trans, NULL, FALSE);
#endif
@@ -11055,7 +11311,7 @@ f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
if (rettv_list_alloc(rettv) == OK)
{
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
- && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
+ && col >= 0 && col <= (long)ml_get_len(lnum)
&& curwin->w_p_cole > 0)
{
(void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
@@ -11112,7 +11368,7 @@ f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
- && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
+ && col >= 0 && col <= (long)ml_get_len(lnum)
&& rettv_list_alloc(rettv) == OK)
{
(void)syn_get_id(curwin, lnum, col, FALSE, NULL, TRUE);
@@ -11290,7 +11546,7 @@ f_virtcol(typval_T *argvars, typval_T *rettv)
fp->col = 0;
else
{
- len = (int)STRLEN(ml_get(fp->lnum));
+ len = (int)ml_get_len(fp->lnum);
if (fp->col > len)
fp->col = len;
}