Compare commits

...

13 Commits

Author SHA1 Message Date
DungSaga
48608b4a4b patch 8.2.3658: duplicate code in xxd
Problem:    Duplicate code in xxd.
Solution:   Merge duplicated code. Add more tests. (closes #9192)
2021-11-24 11:18:07 +00:00
Bram Moolenaar
112bed0cbe patch 8.2.3657: Vim9: debug text misses one line of return statement
Problem:    Vim9: debug text misses one line of return statement.
Solution:   Add a line when not at a debug instruction. (closes #9137)
2021-11-23 22:16:34 +00:00
Bram Moolenaar
65259b5c6a patch 8.2.3656: Vim9: no error for an evironment variable by itself
Problem:    Vim9: no error for an evironment variable by itself.
Solution:   Give a "without effect" error. (closes #9166)
2021-11-23 14:52:06 +00:00
Mike Williams
cc9d725bbb patch 8.2.3655: compiler warning for using size_t for int
Problem:    Compiler warning for using size_t for int.
Solution:   Add a type cast. (Mike Williams, closes #9199)
2021-11-23 12:35:57 +00:00
Chris Dalton
ee93e327ba patch 8.2.3654: GTK: a touch-drag does not update the selection
Problem:    GTK: a touch-drag does not update the selection.
Solution:   Add GDK_BUTTON1_MASK to the state. (Chris Dalton, close #9196,
            closes #9194)
2021-11-23 12:27:48 +00:00
Milly
b771b6b5fe patch 8.2.3653: terminal ANSI colors may be wrong
Problem:    Terminal ANSI colors may be wrong.
Solution:   Initialize the color type. (closes #9198, closes #9197)
2021-11-23 12:07:25 +00:00
Yegappan Lakshmanan
e021662f39 patch 8.2.3652: can only get text properties one line at a time
Problem:    Can only get text properties one line at a time.
Solution:   Add options to prop_list() to use a range of lines and filter by
            types. (Yegappan Lakshmanan, closes #9138)
2021-11-23 11:46:32 +00:00
Bram Moolenaar
04b568b38f patch 8.2.3651: Vim9: no error for :lock or :unlock with unknown variable
Problem:    Vim9: no error for :lock or :unlock with unknown variable.
Solution:   Give an error. (closes #9188)
2021-11-22 21:58:41 +00:00
Bram Moolenaar
3b3755fe19 patch 8.2.3650: Vim9: for loop variable can be a list member
Problem:    Vim9: for loop variable can be a list member.
Solution:   Check for valid variable name. (closes #9179)
2021-11-22 20:10:18 +00:00
Bram Moolenaar
7a53f29c03 patch 8.2.3649: Vim9: error for variable declared in while loop
Problem:    Vim9: error for variable declared in while loop.
Solution:   Do not keep the first variable. (closes #9191)
2021-11-22 18:31:02 +00:00
Bram Moolenaar
4671e88d7d patch 8.2.3648: "verbose pwd" is incorrect after dropping files on Vim
Problem:    "verbose pwd" is incorrect after dropping files on Vim.
Solution:   Set the chdir reason to "drop".
2021-11-22 17:21:48 +00:00
Dusan Popovic
ce59b9f292 patch 8.2.3647: GTK: when using ligatures the cursor is drawn wrong
Problem:    GTK: when using ligatures the cursor is drawn wrong.
Solution:   Clear more characters when ligatures are used. (Dusan Popovic,
            closes #9190)
2021-11-22 17:18:44 +00:00
Bram Moolenaar
c449271f4e patch 8.2.3646: using <sfile> in a function gives an unexpected result
Problem:    Using <sfile> in a function gives an unexpected result.
Solution:   Give an error in a Vim9 function. (issue #9189)
2021-11-22 15:37:15 +00:00
22 changed files with 680 additions and 64 deletions

View File

@@ -1,4 +1,4 @@
*textprop.txt* For Vim version 8.2. Last change: 2021 Aug 16
*textprop.txt* For Vim version 8.2. Last change: 2021 Nov 23
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -230,13 +230,25 @@ prop_find({props} [, {direction}])
prop_list({lnum} [, {props}]) *prop_list()*
Return a List with all text properties in line {lnum}.
Returns a List with all the text properties in line {lnum}.
When {props} contains a "bufnr" item, use this buffer instead
of the current buffer.
The following optional items are supported in {props}:
bufnr use this buffer instead of the current buffer
end_lnum return text properties in all the lines
between {lnum} and {end_lnum} (inclusive).
A negative value is used as an offset from the
last buffer line; -1 refers to the last buffer
line.
types List of property type names. Return only text
properties that match one of the type names.
ids List of property identifiers. Return only text
properties with one of these identifiers.
The properties are ordered by starting column and priority.
Each property is a Dict with these entries:
lnum starting line number. Present only when
returning text properties between {lnum} and
{end_lnum}.
col starting column
length length in bytes, one more if line break is
included
@@ -253,6 +265,30 @@ prop_list({lnum} [, {props}]) *prop_list()*
When "end" is zero the property continues in the next line.
The line break after this line is included.
Returns an empty list on error.
Examples:
" get text properties placed in line 5
echo prop_list(5)
" get text properties placed in line 20 in buffer 4
echo prop_list(20, {'bufnr': 4})
" get all the text properties between line 1 and 20
echo prop_list(1, {'end_lnum': 20})
" get all the text properties of type 'myprop'
echo prop_list(1, {'types': ['myprop'],
\ 'end_lnum': -1})
" get all the text properties of type 'prop1' or 'prop2'
echo prop_list(1, {'types': ['prop1', 'prop2'],
\ 'end_lnum': -1})
" get all the text properties with ID 8
echo prop_list(1, {'ids': [8], 'end_lnum': line('$')})
" get all the text properties with ID 10 and 20
echo prop_list(1, {'ids': [10, 20], 'end_lnum': -1})
" get text properties with type 'myprop' and ID 100
" in buffer 4.
echo prop_list(1, {'bufnr': 4, 'types': ['myprop'],
\ 'ids': [100], 'end_lnum': -1})
Can also be used as a |method|: >
GetLnum()->prop_list()
<

View File

@@ -1102,7 +1102,7 @@ dict_extend(dict_T *d1, dict_T *d2, char_u *action, char *func_name)
&& HI2DI(hi2)->di_tv.v_type == VAR_FUNC
&& var_wrong_func_name(hi2->hi_key, di1 == NULL))
break;
if (!valid_varname(hi2->hi_key, TRUE))
if (!valid_varname(hi2->hi_key, -1, TRUE))
break;
}

View File

@@ -684,3 +684,7 @@ EXTERN char e_ascii_code_not_in_range[]
INIT(= N_("E1243: ASCII code not in 32-127 range"));
EXTERN char e_bad_color_string_str[]
INIT(= N_("E1244: Bad color string: %s"));
EXTERN char e_cannot_expand_sfile_in_vim9_function[]
INIT(= N_("E1245: Cannot expand <sfile> in a Vim9 function"));
EXTERN char e_cannot_find_variable_to_unlock_str[]
INIT(= N_("E1246: Cannot find variable to (un)lock: %s"));

View File

@@ -1128,7 +1128,7 @@ get_lval(
wrong = (lp->ll_dict->dv_scope == VAR_DEF_SCOPE
&& rettv->v_type == VAR_FUNC
&& var_wrong_func_name(key, lp->ll_di == NULL))
|| !valid_varname(key, TRUE);
|| !valid_varname(key, -1, TRUE);
if (len != -1)
key[len] = prevval;
if (wrong)

View File

@@ -1827,7 +1827,12 @@ do_lock_var(
// Normal name or expanded name.
di = find_var(lp->ll_name, NULL, TRUE);
if (di == NULL)
{
if (in_vim9script())
semsg(_(e_cannot_find_variable_to_unlock_str),
lp->ll_name);
ret = FAIL;
}
else if ((di->di_flags & DI_FLAGS_FIX)
&& di->di_tv.v_type != VAR_DICT
&& di->di_tv.v_type != VAR_LIST)
@@ -3431,7 +3436,7 @@ set_var_const(
// Make sure the variable name is valid. In Vim9 script an autoload
// variable must be prefixed with "g:".
if (!valid_varname(varname, !vim9script
if (!valid_varname(varname, -1, !vim9script
|| STRNCMP(name, "g:", 2) == 0))
goto failed;
@@ -3631,14 +3636,15 @@ value_check_lock(int lock, char_u *name, int use_gettext)
/*
* Check if a variable name is valid. When "autoload" is true "#" is allowed.
* If "len" is -1 use all of "varname", otherwise up to "varname[len]".
* Return FALSE and give an error if not.
*/
int
valid_varname(char_u *varname, int autoload)
valid_varname(char_u *varname, int len, int autoload)
{
char_u *p;
for (p = varname; *p != NUL; ++p)
for (p = varname; len < 0 ? *p != NUL : p < varname + len; ++p)
if (!eval_isnamec1(*p) && (p == varname || !VIM_ISDIGIT(*p))
&& !(autoload && *p == AUTOLOAD_CHAR))
{

View File

@@ -888,7 +888,8 @@ report_discard_pending(int pending, void *value)
}
/*
* Return TRUE if "arg" is only a variable, register or option name.
* Return TRUE if "arg" is only a variable, register, environment variable or
* option name.
*/
int
cmd_is_name_only(char_u *arg)
@@ -911,6 +912,8 @@ cmd_is_name_only(char_u *arg)
if (STRNCMP("l:", p, 2) == 0 || STRNCMP("g:", p, 2) == 0)
p += 2;
}
else if (*p == '$')
++p;
get_name_len(&p, &alias, FALSE, FALSE);
}
name_only = ends_excmd2(arg, skipwhite(p));
@@ -1201,9 +1204,10 @@ ex_while(exarg_T *eap)
& CSF_FUNC_DEF;
// Any variables defined in the previous round are no longer
// visible. Keep the first one, it is the loop variable that
// we reuse every time around.
for (i = cstack->cs_script_var_len[cstack->cs_idx] + 1;
// visible. Keep the first one for ":for", it is the loop
// variable that we reuse every time around.
for (i = cstack->cs_script_var_len[cstack->cs_idx]
+ (eap->cmdidx == CMD_while ? 0 : 1);
i < si->sn_var_vals.ga_len; ++i)
{
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + i;

View File

@@ -1097,6 +1097,31 @@ gui_set_ligatures(void)
else
CLEAR_FIELD(gui.ligatures_map);
}
/*
* Adjust the columns to undraw for when the cursor is on ligatures.
*/
static void
gui_adjust_undraw_cursor_for_ligatures(int *startcol, int *endcol)
{
int off;
if (ScreenLines == NULL || *p_guiligatures == NUL)
return;
// expand before the cursor for all the chars in gui.ligatures_map
off = LineOffset[gui.cursor_row] + *startcol;
if (gui.ligatures_map[ScreenLines[off]])
while (*startcol > 0 && gui.ligatures_map[ScreenLines[--off]])
(*startcol)--;
// expand after the cursor for all the chars in gui.ligatures_map
off = LineOffset[gui.cursor_row] + *endcol;
if (gui.ligatures_map[ScreenLines[off]])
while (*endcol < ((int)screen_Columns - 1)
&& gui.ligatures_map[ScreenLines[++off]])
(*endcol)++;
}
#endif
static void
@@ -2673,19 +2698,24 @@ gui_outstr_nowrap(
}
/*
* Un-draw the cursor. Actually this just redraws the character at the given
* position.
* Undraw the cursor. This actually redraws the character at the cursor
* position, plus some more characters when needed.
*/
void
gui_undraw_cursor(void)
{
if (gui.cursor_is_valid)
{
// Redraw the character just before too, if there is one, because with
// some fonts and characters there can be a one pixel overlap.
gui_redraw_block(gui.cursor_row,
gui.cursor_col > 0 ? gui.cursor_col - 1 : gui.cursor_col,
gui.cursor_row, gui.cursor_col, GUI_MON_NOCLEAR);
// Always redraw the character just before if there is one, because
// with some fonts and characters there can be a one pixel overlap.
int startcol = gui.cursor_col > 0 ? gui.cursor_col - 1 : gui.cursor_col;
int endcol = gui.cursor_col;
#ifdef FEAT_GUI_GTK
gui_adjust_undraw_cursor_for_ligatures(&startcol, &endcol);
#endif
gui_redraw_block(gui.cursor_row, startcol,
gui.cursor_row, endcol, GUI_MON_NOCLEAR);
// Cursor_is_valid is reset when the cursor is undrawn, also reset it
// here in case it wasn't needed to undraw it.
@@ -5495,6 +5525,7 @@ gui_wingoto_xy(int x, int y)
drop_callback(void *cookie)
{
char_u *p = cookie;
int do_shorten = FALSE;
// If Shift held down, change to first file's directory. If the first
// item is a directory, change to that directory (and let the explorer
@@ -5504,11 +5535,16 @@ drop_callback(void *cookie)
if (mch_isdir(p))
{
if (mch_chdir((char *)p) == 0)
shorten_fnames(TRUE);
do_shorten = TRUE;
}
else if (vim_chdirfile(p, "drop") == OK)
shorten_fnames(TRUE);
do_shorten = TRUE;
vim_free(p);
if (do_shorten)
{
shorten_fnames(TRUE);
last_chdir_reason = "drop";
}
}
// Update the screen display
@@ -5605,7 +5641,7 @@ gui_handle_drop(
}
else
handle_drop(count, fnames, (modifiers & MOUSE_CTRL) != 0,
drop_callback, (void *)p);
drop_callback, (void *)p);
}
entered = FALSE;

View File

@@ -396,6 +396,12 @@ static int using_gnome = 0;
# define using_gnome 0
#endif
/*
* GTK doesn't set the GDK_BUTTON1_MASK state when dragging a touch. Add this
* state when dragging.
*/
static guint dragging_button_state = 0;
/*
* Parse the GUI related command-line arguments. Any arguments used are
* deleted from argv, and *argc is decremented accordingly. This is called
@@ -1585,6 +1591,9 @@ process_motion_notify(int x, int y, GdkModifierType state)
int_u vim_modifiers;
GtkAllocation allocation;
// Need to add GDK_BUTTON1_MASK state when dragging a touch.
state |= dragging_button_state;
button = (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK |
GDK_BUTTON3_MASK | GDK_BUTTON4_MASK |
GDK_BUTTON5_MASK))
@@ -1811,7 +1820,11 @@ button_press_event(GtkWidget *widget,
{
// Keep in sync with gui_x11.c.
// Buttons 4-7 are handled in scroll_event()
case 1: button = MOUSE_LEFT; break;
case 1:
button = MOUSE_LEFT;
// needed for touch-drag
dragging_button_state |= GDK_BUTTON1_MASK;
break;
case 2: button = MOUSE_MIDDLE; break;
case 3: button = MOUSE_RIGHT; break;
case 8: button = MOUSE_X1; break;
@@ -1906,6 +1919,13 @@ button_release_event(GtkWidget *widget UNUSED,
gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, vim_modifiers);
switch (event->button)
{
case 1: // MOUSE_LEFT
dragging_button_state = 0;
break;
}
return TRUE;
}

View File

@@ -78,7 +78,7 @@ int var_check_lock(int flags, char_u *name, int use_gettext);
int var_check_fixed(int flags, char_u *name, int use_gettext);
int var_wrong_func_name(char_u *name, int new_var);
int value_check_lock(int lock, char_u *name, int use_gettext);
int valid_varname(char_u *varname, int autoload);
int valid_varname(char_u *varname, int len, int autoload);
void reset_v_option_vars(void);
void assert_error(garray_T *gap);
int var_exists(char_u *var);

View File

@@ -135,6 +135,20 @@ estack_sfile(estack_arg_T which UNUSED)
return vim_strsave(entry->es_name);
}
#ifdef FEAT_EVAL
// expand('<sfile>') works in a function for backwards compatibility, but
// may give an unexpected result. Disallow it in Vim 9 script.
if (which == ESTACK_SFILE && in_vim9script())
{
int save_emsg_off = emsg_off;
if (emsg_off == 1)
// f_expand() silences errors but we do want this one
emsg_off = 0;
emsg(_(e_cannot_expand_sfile_in_vim9_function));
emsg_off = save_emsg_off;
return NULL;
}
// Give information about each stack entry up to the root.
// For a function we compose the call stack, as it was done in the past:
// "function One[123]..Two[456]..Three"

View File

@@ -4130,6 +4130,7 @@ set_vterm_palette(VTerm *vterm, long_u *rgb)
{
VTermColor color;
color.type = VTERM_COLOR_RGB;
color.red = (unsigned)(rgb[index] >> 16);
color.green = (unsigned)(rgb[index] >> 8) & 255;
color.blue = (unsigned)rgb[index] & 255;

View File

@@ -373,6 +373,29 @@ def Test_Debugger_breakadd_expr()
call delete('Xtest.vim')
enddef
def Test_Debugger_break_at_return()
var lines =<< trim END
vim9script
def g:GetNum(): number
return 1
+ 2
+ 3
enddef
breakadd func GetNum
END
writefile(lines, 'Xtest.vim')
# Start Vim in a terminal
var buf = RunVimInTerminal('-S Xtest.vim', {wait_for_ruler: 0})
call TermWait(buf)
RunDbgCmd(buf, ':call GetNum()',
['line 1: return 1 + 2 + 3'], {match: 'pattern'})
call StopVimInTerminal(buf)
call delete('Xtest.vim')
enddef
func Test_Backtrace_Through_Source()
CheckCWD
let file1 =<< trim END

View File

@@ -5,6 +5,7 @@ source check.vim
CheckFeature textprop
source screendump.vim
source vim9.vim
func Test_proptype_global()
call prop_type_add('comment', {'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1})
@@ -1645,6 +1646,154 @@ def Test_prop_bufnr_zero()
endtry
enddef
" Tests for the prop_list() function
func Test_prop_list()
let lines =<< trim END
new
call AddPropTypes()
call setline(1, repeat([repeat('a', 60)], 10))
call prop_add(1, 4, {'type': 'one', 'id': 5, 'end_col': 6})
call prop_add(1, 5, {'type': 'two', 'id': 10, 'end_col': 7})
call prop_add(3, 12, {'type': 'one', 'id': 20, 'end_col': 14})
call prop_add(3, 13, {'type': 'two', 'id': 10, 'end_col': 15})
call prop_add(5, 20, {'type': 'one', 'id': 10, 'end_col': 22})
call prop_add(5, 21, {'type': 'two', 'id': 20, 'end_col': 23})
call assert_equal([
\ {'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1},
\ {'id': 10, 'col': 5, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1}], prop_list(1))
#" text properties between a few lines
call assert_equal([
\ {'lnum': 3, 'id': 20, 'col': 12, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1},
\ {'lnum': 3, 'id': 10, 'col': 13, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1},
\ {'lnum': 5, 'id': 10, 'col': 20, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1},
\ {'lnum': 5, 'id': 20, 'col': 21, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1}],
\ prop_list(2, {'end_lnum': 5}))
#" text properties across all the lines
call assert_equal([
\ {'lnum': 1, 'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1},
\ {'lnum': 3, 'id': 20, 'col': 12, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1},
\ {'lnum': 5, 'id': 10, 'col': 20, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1}],
\ prop_list(1, {'types': ['one'], 'end_lnum': -1}))
#" text properties with the specified identifier
call assert_equal([
\ {'lnum': 3, 'id': 20, 'col': 12, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1},
\ {'lnum': 5, 'id': 20, 'col': 21, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1}],
\ prop_list(1, {'ids': [20], 'end_lnum': 10}))
#" text properties of the specified type and id
call assert_equal([
\ {'lnum': 1, 'id': 10, 'col': 5, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1},
\ {'lnum': 3, 'id': 10, 'col': 13, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1}],
\ prop_list(1, {'types': ['two'], 'ids': [10], 'end_lnum': 20}))
call assert_equal([], prop_list(1, {'ids': [40, 50], 'end_lnum': 10}))
call assert_equal([], prop_list(6, {'end_lnum': 10}))
call assert_equal([], prop_list(2, {'end_lnum': 2}))
#" error cases
call assert_fails("echo prop_list(1, {'end_lnum': -20})", 'E16:')
call assert_fails("echo prop_list(4, {'end_lnum': 2})", 'E16:')
call assert_fails("echo prop_list(1, {'end_lnum': '$'})", 'E889:')
call assert_fails("echo prop_list(1, {'types': ['blue'], 'end_lnum': 10})",
\ 'E971:')
call assert_fails("echo prop_list(1, {'types': ['one', 'blue'],
\ 'end_lnum': 10})", 'E971:')
call assert_fails("echo prop_list(1, {'types': ['one', 10],
\ 'end_lnum': 10})", 'E928:')
call assert_fails("echo prop_list(1, {'types': ['']})", 'E971:')
call assert_equal([], prop_list(2, {'types': []}))
call assert_equal([], prop_list(2, {'types': test_null_list()}))
call assert_fails("call prop_list(1, {'types': {}})", 'E714:')
call assert_fails("call prop_list(1, {'types': 'one'})", 'E714:')
call assert_equal([], prop_list(2, {'types': ['one'],
\ 'ids': test_null_list()}))
call assert_equal([], prop_list(2, {'types': ['one'], 'ids': []}))
call assert_fails("call prop_list(1, {'types': ['one'], 'ids': {}})",
\ 'E714:')
call assert_fails("call prop_list(1, {'types': ['one'], 'ids': 10})",
\ 'E714:')
call assert_fails("call prop_list(1, {'types': ['one'], 'ids': [[]]})",
\ 'E745:')
call assert_fails("call prop_list(1, {'types': ['one'], 'ids': [10, []]})",
\ 'E745:')
#" get text properties from a non-current buffer
wincmd w
call assert_equal([
\ {'lnum': 1, 'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1},
\ {'lnum': 1, 'id': 10, 'col': 5, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1},
\ {'lnum': 3, 'id': 20, 'col': 12, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1},
\ {'lnum': 3, 'id': 10, 'col': 13, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1}],
\ prop_list(1, {'bufnr': winbufnr(1), 'end_lnum': 4}))
wincmd w
#" get text properties after clearing all the properties
call prop_clear(1, line('$'))
call assert_equal([], prop_list(1, {'end_lnum': 10}))
call prop_add(2, 4, {'type': 'one', 'id': 5, 'end_col': 6})
call prop_add(2, 4, {'type': 'two', 'id': 10, 'end_col': 6})
call prop_add(2, 4, {'type': 'three', 'id': 15, 'end_col': 6})
#" get text properties with a list of types
call assert_equal([
\ {'id': 10, 'col': 4, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1},
\ {'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1}],
\ prop_list(2, {'types': ['one', 'two']}))
call assert_equal([
\ {'id': 15, 'col': 4, 'type_bufnr': 0, 'end': 1,
\ 'type': 'three', 'length': 2, 'start': 1},
\ {'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1}],
\ prop_list(2, {'types': ['one', 'three']}))
#" get text properties with a list of identifiers
call assert_equal([
\ {'id': 10, 'col': 4, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1},
\ {'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1}],
\ prop_list(2, {'ids': [5, 10, 20]}))
call prop_clear(1, line('$'))
call assert_equal([], prop_list(2, {'types': ['one', 'two']}))
call assert_equal([], prop_list(2, {'ids': [5, 10, 20]}))
#" get text properties from a hidden buffer
edit! Xaaa
call setline(1, repeat([repeat('b', 60)], 10))
call prop_add(1, 4, {'type': 'one', 'id': 5, 'end_col': 6})
call prop_add(4, 8, {'type': 'two', 'id': 10, 'end_col': 10})
VAR bnr = bufnr()
hide edit Xbbb
call assert_equal([
\ {'lnum': 1, 'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1,
\ 'type': 'one', 'length': 2, 'start': 1},
\ {'lnum': 4, 'id': 10, 'col': 8, 'type_bufnr': 0, 'end': 1,
\ 'type': 'two', 'length': 2, 'start': 1}],
\ prop_list(1, {'bufnr': bnr,
\ 'types': ['one', 'two'], 'ids': [5, 10], 'end_lnum': -1}))
#" get text properties from an unloaded buffer
bunload! Xaaa
call assert_equal([], prop_list(1, {'bufnr': bnr, 'end_lnum': -1}))
call DeletePropTypes()
:%bw!
END
call CheckLegacyAndVim9Success(lines)
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -915,6 +915,14 @@ def Test_expand()
CheckDefAndScriptFailure2(['expand("a", 2)'], 'E1013: Argument 2: type mismatch, expected bool but got number', 'E1212: Bool required for argument 2')
CheckDefAndScriptFailure2(['expand("a", true, 2)'], 'E1013: Argument 3: type mismatch, expected bool but got number', 'E1212: Bool required for argument 3')
expand('')->assert_equal('')
var caught = false
try
echo expand("<sfile>")
catch /E1245:/
caught = true
endtry
assert_true(caught)
enddef
def Test_expandcmd()

View File

@@ -584,6 +584,13 @@ def Test_use_register()
END
CheckDefAndScriptFailure(lines, 'E1207:', 2)
&g:showbreak = ''
lines =<< trim END
$SomeEnv = 'value'
$SomeEnv
END
CheckDefAndScriptFailure(lines, 'E1207:', 2)
$SomeEnv = ''
enddef
def Test_environment_use_linebreak()
@@ -1370,6 +1377,23 @@ def Test_lockvar()
unlockvar theList
END
CheckDefFailure(lines, 'E1178', 2)
lines =<< trim END
vim9script
var name = 'john'
lockvar nameX
END
CheckScriptFailure(lines, 'E1246', 3)
lines =<< trim END
vim9script
var name = 'john'
def LockIt()
lockvar nameX
enddef
LockIt()
END
CheckScriptFailure(lines, 'E1246', 1)
enddef
def Test_substitute_expr()

View File

@@ -2865,11 +2865,35 @@ def Test_for_loop_fails()
endfor
END
CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected job but got string', 2)
lines =<< trim END
var i = 0
for i in [1, 2, 3]
echo i
endfor
END
CheckDefExecAndScriptFailure2(lines, 'E1017:', 'E1041:')
lines =<< trim END
var l = [0]
for l[0] in [1, 2, 3]
echo l[0]
endfor
END
CheckDefExecAndScriptFailure2(lines, 'E461:', 'E1017:')
lines =<< trim END
var d = {x: 0}
for d.x in [1, 2, 3]
echo d.x
endfor
END
CheckDefExecAndScriptFailure2(lines, 'E461:', 'E1017:')
enddef
def Test_for_loop_script_var()
# cannot use s:var in a :def function
CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1101:')
CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E461:')
# can use s:var in Vim9 script, with or without s:
var lines =<< trim END
@@ -3083,6 +3107,21 @@ def Test_while_loop()
endwhile
enddef
def Test_while_loop_in_script()
var lines =<< trim END
vim9script
var result = ''
var cnt = 0
while cnt < 3
var s = 'v' .. cnt
result ..= s
cnt += 1
endwhile
assert_equal('v0v1v2', result)
END
CheckScriptSuccess(lines)
enddef
def Test_while_loop_fails()
CheckDefFailure(['while xxx'], 'E1001:')
CheckDefFailure(['endwhile'], 'E588:')

View File

@@ -263,6 +263,20 @@ func Test_xxd_usage()
endfor
endfunc
func Test_xxd_ignore_garbage()
new
exe 'r! printf "\n\r xxxx 0: 42 42" | ' . s:xxd_cmd . ' -r'
call assert_match('BB', join(getline(1, 3)))
bwipe!
endfunc
func Test_xxd_bit_dump()
new
exe 'r! printf "123456" | ' . s:xxd_cmd . ' -b1'
call assert_match('00000000: 00110001 00110010 00110011 00110100 00110101 00110110 123456', join(getline(1, 3)))
bwipe!
endfunc
func Test_xxd_version()
new
exe 'r! ' . s:xxd_cmd . ' -v'

View File

@@ -896,53 +896,260 @@ f_prop_find(typval_T *argvars, typval_T *rettv)
}
}
/*
* Returns TRUE if 'type_or_id' is in the 'types_or_ids' list.
*/
static int
prop_type_or_id_in_list(int *types_or_ids, int len, int type_or_id)
{
int i;
for (i = 0; i < len; i++)
if (types_or_ids[i] == type_or_id)
return TRUE;
return FALSE;
}
/*
* Return all the text properties in line 'lnum' in buffer 'buf' in 'retlist'.
* If 'prop_types' is not NULL, then return only the text properties with
* matching property type in the 'prop_types' array.
* If 'prop_ids' is not NULL, then return only the text properties with
* an identifier in the 'props_ids' array.
* If 'add_lnum' is TRUE, then add the line number also to the text property
* dictionary.
*/
static void
get_props_in_line(
buf_T *buf,
linenr_T lnum,
int *prop_types,
int prop_types_len,
int *prop_ids,
int prop_ids_len,
list_T *retlist,
int add_lnum)
{
char_u *text = ml_get_buf(buf, lnum, FALSE);
size_t textlen = STRLEN(text) + 1;
int count;
int i;
textprop_T prop;
count = (int)((buf->b_ml.ml_line_len - textlen) / sizeof(textprop_T));
for (i = 0; i < count; ++i)
{
mch_memmove(&prop, text + textlen + i * sizeof(textprop_T),
sizeof(textprop_T));
if ((prop_types == NULL
|| prop_type_or_id_in_list(prop_types, prop_types_len,
prop.tp_type))
&& (prop_ids == NULL ||
prop_type_or_id_in_list(prop_ids, prop_ids_len,
prop.tp_id)))
{
dict_T *d = dict_alloc();
if (d == NULL)
break;
prop_fill_dict(d, &prop, buf);
if (add_lnum)
dict_add_number(d, "lnum", lnum);
list_append_dict(retlist, d);
}
}
}
/*
* Convert a List of property type names into an array of property type
* identifiers. Returns a pointer to the allocated array. Returns NULL on
* error. 'num_types' is set to the number of returned property types.
*/
static int *
get_prop_types_from_names(list_T *l, buf_T *buf, int *num_types)
{
int *prop_types;
listitem_T *li;
int i;
char_u *name;
proptype_T *type;
*num_types = 0;
prop_types = ALLOC_MULT(int, list_len(l));
if (prop_types == NULL)
return NULL;
i = 0;
FOR_ALL_LIST_ITEMS(l, li)
{
if (li->li_tv.v_type != VAR_STRING)
{
emsg(_(e_stringreq));
goto errret;
}
name = li->li_tv.vval.v_string;
if (name == NULL)
goto errret;
type = lookup_prop_type(name, buf);
if (type == NULL)
goto errret;
prop_types[i++] = type->pt_id;
}
*num_types = i;
return prop_types;
errret:
VIM_CLEAR(prop_types);
return NULL;
}
/*
* Convert a List of property identifiers into an array of property
* identifiers. Returns a pointer to the allocated array. Returns NULL on
* error. 'num_ids' is set to the number of returned property identifiers.
*/
static int *
get_prop_ids_from_list(list_T *l, int *num_ids)
{
int *prop_ids;
listitem_T *li;
int i;
int id;
int error;
*num_ids = 0;
prop_ids = ALLOC_MULT(int, list_len(l));
if (prop_ids == NULL)
return NULL;
i = 0;
FOR_ALL_LIST_ITEMS(l, li)
{
error = FALSE;
id = tv_get_number_chk(&li->li_tv, &error);
if (error)
goto errret;
prop_ids[i++] = id;
}
*num_ids = i;
return prop_ids;
errret:
VIM_CLEAR(prop_ids);
return NULL;
}
/*
* prop_list({lnum} [, {bufnr}])
*/
void
f_prop_list(typval_T *argvars, typval_T *rettv)
{
linenr_T lnum;
buf_T *buf = curbuf;
linenr_T lnum;
linenr_T start_lnum;
linenr_T end_lnum;
buf_T *buf = curbuf;
int add_lnum = FALSE;
int *prop_types = NULL;
int prop_types_len = 0;
int *prop_ids = NULL;
int prop_ids_len = 0;
list_T *l;
dictitem_T *di;
if (in_vim9script()
&& (check_for_number_arg(argvars, 0) == FAIL
|| check_for_opt_dict_arg(argvars, 1) == FAIL))
return;
lnum = tv_get_number(&argvars[0]);
if (rettv_list_alloc(rettv) != OK)
return;
// default: get text properties on current line
start_lnum = tv_get_number(&argvars[0]);
end_lnum = start_lnum;
if (argvars[1].v_type != VAR_UNKNOWN)
{
dict_T *d;
if (argvars[1].v_type != VAR_DICT)
{
emsg(_(e_dictreq));
return;
}
d = argvars[1].vval.v_dict;
if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL)
return;
}
if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
{
emsg(_(e_invalid_range));
return;
}
if (rettv_list_alloc(rettv) == OK)
{
char_u *text = ml_get_buf(buf, lnum, FALSE);
size_t textlen = STRLEN(text) + 1;
int count = (int)((buf->b_ml.ml_line_len - textlen)
/ sizeof(textprop_T));
int i;
textprop_T prop;
for (i = 0; i < count; ++i)
if (d != NULL && (di = dict_find(d, (char_u *)"end_lnum", -1)) != NULL)
{
dict_T *d = dict_alloc();
if (di->di_tv.v_type != VAR_NUMBER)
{
emsg(_(e_numberreq));
return;
}
end_lnum = tv_get_number(&di->di_tv);
if (end_lnum < 0)
// negative end_lnum is used as an offset from the last buffer
// line
end_lnum = buf->b_ml.ml_line_count + end_lnum + 1;
else if (end_lnum > buf->b_ml.ml_line_count)
end_lnum = buf->b_ml.ml_line_count;
add_lnum = TRUE;
}
if (d != NULL && (di = dict_find(d, (char_u *)"types", -1)) != NULL)
{
if (di->di_tv.v_type != VAR_LIST)
{
emsg(_(e_listreq));
return;
}
if (d == NULL)
break;
mch_memmove(&prop, text + textlen + i * sizeof(textprop_T),
sizeof(textprop_T));
prop_fill_dict(d, &prop, buf);
list_append_dict(rettv->vval.v_list, d);
l = di->di_tv.vval.v_list;
if (l != NULL && list_len(l) > 0)
{
prop_types = get_prop_types_from_names(l, buf, &prop_types_len);
if (prop_types == NULL)
return;
}
}
if (d != NULL && (di = dict_find(d, (char_u *)"ids", -1)) != NULL)
{
if (di->di_tv.v_type != VAR_LIST)
{
emsg(_(e_listreq));
goto errret;
}
l = di->di_tv.vval.v_list;
if (l != NULL && list_len(l) > 0)
{
prop_ids = get_prop_ids_from_list(l, &prop_ids_len);
if (prop_ids == NULL)
goto errret;
}
}
}
if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count
|| end_lnum < 1 || end_lnum < start_lnum)
emsg(_(e_invalid_range));
else
for (lnum = start_lnum; lnum <= end_lnum; lnum++)
get_props_in_line(buf, lnum, prop_types, prop_types_len,
prop_ids, prop_ids_len,
rettv->vval.v_list, add_lnum);
errret:
VIM_CLEAR(prop_types);
VIM_CLEAR(prop_ids);
}
/*

View File

@@ -757,6 +757,32 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
3658,
/**/
3657,
/**/
3656,
/**/
3655,
/**/
3654,
/**/
3653,
/**/
3652,
/**/
3651,
/**/
3650,
/**/
3649,
/**/
3648,
/**/
3647,
/**/
3646,
/**/
3645,
/**/

View File

@@ -8220,8 +8220,8 @@ compile_for(char_u *arg_start, cctx_T *cctx)
for (idx = 0; idx < var_count; ++idx)
{
assign_dest_T dest = dest_local;
int opt_flags = 0;
int vimvaridx = -1;
int opt_flags = 0;
int vimvaridx = -1;
type_T *type = &t_any;
type_T *lhs_type = &t_any;
where_T where = WHERE_INIT;
@@ -8255,6 +8255,8 @@ compile_for(char_u *arg_start, cctx_T *cctx)
}
else
{
if (!valid_varname(arg, (int)varlen, FALSE))
goto failed;
if (lookup_local(arg, varlen, NULL, cctx) == OK)
{
semsg(_(e_variable_already_declared), arg);

View File

@@ -1602,7 +1602,7 @@ handle_debug(isn_T *iptr, ectx_T *ectx)
|| ni->isn_type == ISN_RETURN
|| ni->isn_type == ISN_RETURN_VOID)
{
end_lnum = ni->isn_lnum;
end_lnum = ni->isn_lnum + (ni->isn_type == ISN_DEBUG ? 0 : 1);
break;
}

View File

@@ -809,33 +809,34 @@ main(int argc, char *argv[])
e = 0;
while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
{
int x;
if (p == 0)
{
addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
((unsigned long)(n + seekoff + displayoff)));
for (c = addrlen; c < LLEN; l[c++] = ' ');
}
x = hextype == HEX_LITTLEENDIAN ? p ^ (octspergrp-1) : p;
c = addrlen + 1 + (grplen * x) / octspergrp;
if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
{
int x = hextype == HEX_NORMAL ? p : p ^ (octspergrp-1);
l[c = (addrlen + 1 + (grplen * x) / octspergrp)]
= hexx[(e >> 4) & 0xf];
l[c] = hexx[(e >> 4) & 0xf];
l[++c] = hexx[e & 0xf];
}
else /* hextype == HEX_BITS */
{
int i;
c = (addrlen + 1 + (grplen * p) / octspergrp) - 1;
for (i = 7; i >= 0; i--)
l[++c] = (e & (1 << i)) ? '1' : '0';
l[c++] = (e & (1 << i)) ? '1' : '0';
}
if (e)
nonzero++;
if (ebcdic)
e = (e < 64) ? '.' : etoa64[e-64];
/* When changing this update definition of LLEN above. */
l[addrlen + 3 + (grplen * cols - 1)/octspergrp + p] =
c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p;
l[c++] =
#ifdef __MVS__
(e >= 64)
#else
@@ -845,7 +846,8 @@ main(int argc, char *argv[])
n++;
if (++p == cols)
{
l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
l[c] = '\n';
l[++c] = '\0';
xxdline(fpo, l, autoskip ? nonzero : 1);
nonzero = 0;
p = 0;
@@ -855,7 +857,8 @@ main(int argc, char *argv[])
perror_exit(2);
if (p)
{
l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
l[c] = '\n';
l[++c] = '\0';
xxdline(fpo, l, 1);
}
else if (autoskip)