diff --git a/runtime/doc/tags b/runtime/doc/tags index 5117c07efc..77b19ec7ff 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -4573,7 +4573,6 @@ E1335 vim9class.txt /*E1335* E1336 options.txt /*E1336* E1337 vim9class.txt /*E1337* E1338 vim9class.txt /*E1338* -E1339 textprop.txt /*E1339* E134 change.txt /*E134* E1340 vim9class.txt /*E1340* E1341 vim9class.txt /*E1341* diff --git a/runtime/doc/textprop.txt b/runtime/doc/textprop.txt index 3fa7d14a51..fbe4231c7f 100644 --- a/runtime/doc/textprop.txt +++ b/runtime/doc/textprop.txt @@ -141,9 +141,9 @@ prop_add({lnum}, {col}, {props}) the current buffer is used id user defined ID for the property; must be a number, should be positive |E1510|; - when using "text" then "id" must not be - present and will be set automatically to a - negative number; otherwise zero is used + when using "text" then any "id" value is + ignored and a negative number is assigned + automatically; otherwise zero is used *E1305* text text to be displayed before {col}, or above/below the line if {col} is zero; prepend @@ -224,14 +224,9 @@ prop_add({lnum}, {col}, {props}) is difficult to compute). A negative "id" will be chosen and is returned. - Before text properties with text were supported it was - possible to use a negative "id", even though this was very - rare. Now that negative "id"s are reserved for text - properties with text an error is given when using a negative - "id". When a text property with text already exists using a - negative "id" results in *E1293* . If a negative "id" was - used and later a text property with text is added results in - *E1339* . + Negative "id"s are reserved for text properties with "text" + and cannot be used otherwise. Using a negative "id" results + in *E1293* . Can also be used as a |method|: > GetLnum()->prop_add(col, props) diff --git a/src/errors.h b/src/errors.h index 9c4e485ef8..d780fb4207 100644 --- a/src/errors.h +++ b/src/errors.h @@ -3328,8 +3328,8 @@ EXTERN char e_invalid_argument_nr[] EXTERN char e_cmdline_window_already_open[] INIT(= N_("E1292: Command-line window is already open")); #ifdef FEAT_PROP_POPUP -EXTERN char e_cannot_use_negative_id_after_adding_textprop_with_text[] - INIT(= N_("E1293: Cannot use a negative id after adding a textprop with text")); +EXTERN char e_cannot_use_negative_id[] + INIT(= N_("E1293: Cannot use a negative id for a text property")); EXTERN char e_can_only_use_text_align_when_column_is_zero[] INIT(= N_("E1294: Can only use text_align when column is zero")); #endif @@ -3432,10 +3432,7 @@ EXTERN char e_class_variable_str_not_found_in_class_str[] INIT(= N_("E1337: Class variable \"%s\" not found in class \"%s\"")); // E1338 unused #endif -#ifdef FEAT_PROP_POPUP -EXTERN char e_cannot_add_textprop_with_text_after_using_textprop_with_negative_id[] - INIT(= N_("E1339: Cannot add a textprop with text after using a textprop with a negative id")); -#endif +// E1339 unused #ifdef FEAT_EVAL EXTERN char e_argument_already_declared_in_class_str[] INIT(= N_("E1340: Argument already declared in the class: %s")); diff --git a/src/po/vim.pot b/src/po/vim.pot index 446a0b91f5..d67bcafcc9 100644 --- a/src/po/vim.pot +++ b/src/po/vim.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Vim\n" "Report-Msgid-Bugs-To: vim-dev@vim.org\n" -"POT-Creation-Date: 2026-03-13 18:26+0000\n" +"POT-Creation-Date: 2026-03-18 21:08+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -8099,7 +8099,7 @@ msgstr "" msgid "E1292: Command-line window is already open" msgstr "" -msgid "E1293: Cannot use a negative id after adding a textprop with text" +msgid "E1293: Cannot use a negative id for a text property" msgstr "" msgid "E1294: Can only use text_align when column is zero" @@ -8243,11 +8243,6 @@ msgstr "" msgid "E1337: Class variable \"%s\" not found in class \"%s\"" msgstr "" -msgid "" -"E1339: Cannot add a textprop with text after using a textprop with a " -"negative id" -msgstr "" - #, c-format msgid "E1340: Argument already declared in the class: %s" msgstr "" diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim index 975a5846ac..f8323019bd 100644 --- a/src/testdir/test_textprop.vim +++ b/src/testdir/test_textprop.vim @@ -4669,49 +4669,20 @@ endfunc func Test_error_when_using_negative_id() call prop_type_add('test1', #{highlight: 'ErrorMsg'}) - call prop_add(1, 1, #{type: 'test1', text: 'virtual'}) + + " Negative id is always rejected. Before the fix, prop_add() with a negative + " id succeeded when no virtual text existed, then prop_list() would dereference + " a NULL pointer (b_textprop_text.ga_data) and crash. call assert_fails("call prop_add(1, 1, #{type: 'test1', length: 1, id: -1})", 'E1293:') + call assert_equal([], prop_list(1)) + + " id is silently ignored when text is also specified. + let propid = prop_add(1, 1, #{type: 'test1', text: 'virtual', id: 42}) + call assert_true(propid < 0) call prop_type_delete('test1') endfunc -func Test_error_after_using_negative_id() - CheckScreendump - " This needs to run a separate Vim instance because the - " "did_use_negative_pop_id" will be set. - CheckRunVimInTerminal - - let lines =<< trim END - vim9script - - setline(1, ['one', 'two', 'three']) - prop_type_add('test_1', {highlight: 'Error'}) - prop_type_add('test_2', {highlight: 'WildMenu'}) - - prop_add(3, 1, { - type: 'test_1', - length: 5, - id: -1 - }) - - def g:AddTextprop() - prop_add(1, 0, { - type: 'test_2', - text: 'The quick fox', - text_padding_left: 2 - }) - enddef - END - call writefile(lines, 'XtextPropError', 'D') - let buf = RunVimInTerminal('-S XtextPropError', #{rows: 8, cols: 60}) - call VerifyScreenDump(buf, 'Test_prop_negative_error_1', {}) - - call term_sendkeys(buf, ":call AddTextprop()\") - call VerifyScreenDump(buf, 'Test_prop_negative_error_2', {}) - - call StopVimInTerminal(buf) -endfunc - func Test_modify_text_before_prop() CheckScreendump CheckRunVimInTerminal diff --git a/src/textprop.c b/src/textprop.c index c2519e993d..f0d418eee2 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -434,10 +434,6 @@ get_textprop_id(buf_T *buf) return -(buf->b_textprop_text.ga_len + 1); } -// Flag that is set when a negative ID isused for a normal text property. -// It is then impossible to use virtual text properties. -static int did_use_negative_pop_id = FALSE; - /* * Shared between prop_add() and popup_create(). * "dict_arg" is the function argument of a dict containing "bufnr". @@ -599,24 +595,13 @@ prop_add_common( if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL) goto theend; - if (id < 0) - { - if (buf->b_textprop_text.ga_len > 0) - { - emsg(_(e_cannot_use_negative_id_after_adding_textprop_with_text)); - goto theend; - } - did_use_negative_pop_id = TRUE; - } - if (text != NULL) - { - if (did_use_negative_pop_id) - { - emsg(_(e_cannot_add_textprop_with_text_after_using_textprop_with_negative_id)); - goto theend; - } + // Always assign an internal negative id; ignore any user-provided id. id = get_textprop_id(buf); + else if (id < 0) + { + emsg(_(e_cannot_use_negative_id)); + goto theend; } // This must be done _before_ we add the property because property changes @@ -981,7 +966,11 @@ prop_fill_dict(dict_T *dict, textprop_T *prop, buf_T *buf) { proptype_T *pt; int buflocal = TRUE; - int virtualtext_prop = prop->tp_id < 0; + // A negative tp_id normally means a virtual text property, but a user + // may set a negative id for a regular property when no virtual text + // properties exist. Guard against that by checking the index is valid. + int virtualtext_prop = prop->tp_id < 0 + && -prop->tp_id - 1 < buf->b_textprop_text.ga_len; dict_add_number(dict, "col", (prop->tp_col == MAXCOL) ? 0 : prop->tp_col); if (!virtualtext_prop) diff --git a/src/version.c b/src/version.c index 4a23daa867..73c466b41e 100644 --- a/src/version.c +++ b/src/version.c @@ -734,6 +734,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 196, /**/ 195, /**/