changeset 31489:966c87c57912 v9.0.1077

patch 9.0.1077: can add text property with negative ID before virtual text Commit: https://github.com/vim/vim/commit/4ce1f99a2d58b809ab5a5c602bd031426f8527e8 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Dec 19 13:31:06 2022 +0000 patch 9.0.1077: can add text property with negative ID before virtual text Problem: Can add text property with negative ID before virtual text property. Solution: Remember that a text property with a negative ID was used and give an appropriate error message. (closes #11725) Fix index computation.
author Bram Moolenaar <Bram@vim.org>
date Mon, 19 Dec 2022 14:45:04 +0100
parents c81f178ad433
children 97e0789e6d10
files src/charset.c src/errors.h src/testdir/dumps/Test_prop_negative_error_1.dump src/testdir/dumps/Test_prop_negative_error_2.dump src/testdir/test_textprop.vim src/textprop.c src/version.c
diffstat 7 files changed, 86 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/charset.c
+++ b/src/charset.c
@@ -1181,7 +1181,7 @@ win_lbr_chartabsize(
 				? col == 0
 				: (s[0] == NUL || s[1] == NUL)
 						  && cts->cts_with_trailing)))
-		    && tp->tp_id - 1 < gap->ga_len)
+		    && -tp->tp_id - 1 < gap->ga_len)
 	    {
 		char_u *p = ((char_u **)gap->ga_data)[-tp->tp_id - 1];
 
--- a/src/errors.h
+++ b/src/errors.h
@@ -3397,3 +3397,7 @@ EXTERN char e_class_member_not_found_str
 EXTERN char e_member_not_found_on_class_str_str[]
 	INIT(= N_("E1338: Member not found on class \"%s\": %s"));
 #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
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_negative_error_1.dump
@@ -0,0 +1,8 @@
+>o+0&#ffffff0|n|e| @56
+|t|w|o| @56
+|t+0#ffffff16#ff404010|h|r|e@1| +0#0000000#ffffff0@54
+|~+0#4040ff13&| @58
+|~| @58
+|~| @58
+|~| @58
+| +0#0000000&@41|1|,|1| @10|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_negative_error_2.dump
@@ -0,0 +1,8 @@
+|~+0#4040ff13#ffffff0| @58
+|~| @58
+|~| @58
+|E+0#ffffff16#e000002|r@1|o|r| |d|e|t|e|c|t|e|d| |w|h|i|l|e| |p|r|o|c|e|s@1|i|n|g| |f|u|n|c|t|i|o|n| |A|d@1|T|e|x|t|p|r|o|p|:| +0#0000000#ffffff0@6
+|l+0#af5f00255&|i|n|e| @3|5|:| +0#0000000&@49
+|E+0#ffffff16#e000002|1|3@1|9|:| |C|a|n@1|o|t| |a|d@1| |a| |t|e|x|t|p|r|o|p| |w|i|t|h| |t|e|x|t| |a|f|t|e|r| |u|s|i|n|g| |a| |t|e|x|t|p|r|o
+|p| |w|i|t|h| |a| |n|e|g|a|t|i|v|e| |i|d| +0#0000000#ffffff0@39
+|P+0#00e0003&|r|e|s@1| |E|N|T|E|R| |o|r| |t|y|p|e| |c|o|m@1|a|n|d| |t|o| |c|o|n|t|i|n|u|e> +0#0000000&@20
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -3725,6 +3725,50 @@ func Test_text_prop_diff_mode()
 
   call StopVimInTerminal(buf)
 endfunc
+ 
+func Test_error_when_using_negative_id()
+  call prop_type_add('test1', #{highlight: 'ErrorMsg'})
+  call prop_add(1, 1, #{type: 'test1', text: 'virtual'})
+  call assert_fails("call prop_add(1, 1, #{type: 'test1', length: 1, id: -1})", 'E1293:')
+
+  call prop_type_delete('test1')
+endfunc
+
+func Test_error_after_using_negative_id()
+  " 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()\<CR>")
+  call VerifyScreenDump(buf, 'Test_prop_negative_error_2', {})
+
+  call StopVimInTerminal(buf)
+endfunc
 
 
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -424,6 +424,10 @@ 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".
@@ -576,13 +580,25 @@ prop_add_common(
     if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL)
 	goto theend;
 
-    if (id < 0 && buf->b_textprop_text.ga_len > 0)
+    if (id < 0)
     {
-	emsg(_(e_cannot_use_negative_id_after_adding_textprop_with_text));
-	goto theend;
+	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;
+	}
 	id = get_textprop_id(buf);
+    }
 
     // This must be done _before_ we add the property because property changes
     // trigger buffer (memline) reorganisation, which needs this flag to be
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1077,
+/**/
     1076,
 /**/
     1075,