]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0572: lines disappear with wrapping virtual text after a double-width char v9.2.0572
authorHirohito Higashi <h.east.727@gmail.com>
Sun, 31 May 2026 18:43:42 +0000 (18:43 +0000)
committerChristian Brabandt <cb@256bit.org>
Sun, 31 May 2026 18:43:42 +0000 (18:43 +0000)
Problem:  With 'nowrap', when a line ends with a double-width character
          exactly at the window width and has wrapping "after" virtual
          text, the lines below disappear and "@@@" is shown.
Solution: Detect that the last character fills the rightmost column using
          its displayed width (win_chartabsize(), so a <Tab> or double-width
          character is handled like a single-width one), and also when it
          overflows the last column.  Also clarify in the help that "wrap"
          only takes effect with the 'wrap' option set.

fixes:   #20384
related: #12213
closes:  #20395

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/doc/textprop.txt
src/drawline.c
src/testdir/dumps/Test_prop_with_text_after_wide_char_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_prop_with_text_after_wide_char_2.dump [new file with mode: 0644]
src/testdir/test_textprop.vim
src/testdir/test_vim9_cmd.vim
src/userfunc.c
src/version.c

index 9fd5ff6686a5446d43e650c1cc6a65b9c8d20fc2..ce2867791382ef07e4a784a71ba2c02642a4a3a3 100644 (file)
@@ -1,4 +1,4 @@
-*textprop.txt* For Vim version 9.2.  Last change: 2026 Apr 07
+*textprop.txt* For Vim version 9.2.  Last change: 2026 May 31
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -177,7 +177,9 @@ prop_add({lnum}, {col}, {props})
                                When omitted "truncate" is used.
                                Note that this applies to the individual text
                                property, the 'wrap' option sets the overall
-                               behavior
+                               behavior.  "wrap" only takes effect when the
+                               'wrap' option is set; with 'nowrap' the text
+                               is truncated at the right edge of the window.
                All fields except "type" are optional.
 
                It is an error when both "length" and "end_lnum" or "end_col"
index 3ebb56a1737d89ce19cc08bc00205ae958538acf..0b912e1eae8ccc1b8b5ff9d3172180035d290dae 100644 (file)
@@ -2479,7 +2479,11 @@ win_line(
                    // displaying that character.
                    // Or when not wrapping and at the rightmost column.
 
-                   int only_below_follows = !wp->w_p_wrap && wlv.col == wp->w_width - 1;
+                   // Use the displayed width so a double-width or <Tab> last
+                   // character filling the rightmost column is detected too.
+                   int only_below_follows = !wp->w_p_wrap
+                                && wlv.col + win_chartabsize(wp, ptr, wlv.vcol)
+                                                               >= wp->w_width;
                    int suffix_flags = text_prop_suffix_flags[text_prop_next];
 
                    text_prop_follows = (suffix_flags
diff --git a/src/testdir/dumps/Test_prop_with_text_after_wide_char_1.dump b/src/testdir/dumps/Test_prop_with_text_after_wide_char_1.dump
new file mode 100644 (file)
index 0000000..36dfed3
--- /dev/null
@@ -0,0 +1,8 @@
+>x+0&#ffffff0@42|口*&
+|s+&|e|c|o|n|d| |l|i|n|e| @33
+|t|h|i|r|d| |l|i|n|e| @34
+|~+0#4040ff13&| @43
+|~| @43
+|~| @43
+|~| @43
+| +0#0000000&@26|1|,|1| @10|A|l@1| 
diff --git a/src/testdir/dumps/Test_prop_with_text_after_wide_char_2.dump b/src/testdir/dumps/Test_prop_with_text_after_wide_char_2.dump
new file mode 100644 (file)
index 0000000..5013651
--- /dev/null
@@ -0,0 +1,8 @@
+>x+0&#ffffff0@38|>+0#4040ff13&
+|b+0#0000000&|e|t|w|e@1|n| |l|i|n|e| @27
+|x@31| @7
+|l|a|s|t| |l|i|n|e| @30
+|~+0#4040ff13&| @38
+|~| @38
+|~| @38
+| +0#0000000&@21|1|,|1| @10|A|l@1| 
index a57493bc812d1b67b8fa30d7512f19a64d84c35d..7d868ec06452ca7003f3ac449423b4c4e38f6112 100644 (file)
@@ -3574,6 +3574,56 @@ func Test_props_with_text_after_nowrap()
   call StopVimInTerminal(buf)
 endfunc
 
+func Test_props_with_text_after_wide_char_at_end()
+  CheckScreendump
+  CheckRunVimInTerminal
+
+  " The buffer line ends with a double-width character exactly at the window
+  " width and has wrapping "after" virtual text.  This must not leave blank
+  " lines or "@@@", see issue #20384.
+  let lines =<< trim END
+      vim9script
+      set nowrap
+      setline(1, [repeat('x', 43) .. '口', 'second line', 'third line'])
+      prop_type_add('errtype', {highlight: 'WarningMsg', text_wrap: 'wrap'})
+      prop_add(1, 0, {type: 'errtype', text_padding_left: 3, text: 'E>'})
+  END
+  call writefile(lines, 'XscriptPropsAfterWideChar', 'D')
+  let buf = RunVimInTerminal('-S XscriptPropsAfterWideChar', #{rows: 8, cols: 45})
+  call VerifyScreenDump(buf, 'Test_prop_with_text_after_wide_char_1', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+func Test_props_with_text_after_wide_char_overflow()
+  CheckScreendump
+  CheckRunVimInTerminal
+
+  " Like above, but the last character reaches the rightmost column without
+  " starting on it: a double-width character that does not fit in the last
+  " column, and a <Tab> that expands up to the window width.  Both must be
+  " detected as filling the line so the wrapping "after" text does not cause
+  " blank lines, "@@@" or a spurious wrap with 'nowrap'.
+  let lines =<< trim END
+      vim9script
+      set nowrap tabstop=8 noexpandtab
+      setline(1, [
+          repeat('x', 39) .. '口',
+          'between line',
+          repeat('x', 32) .. "\t",
+          'last line',
+      ])
+      prop_type_add('errtype', {highlight: 'WarningMsg', text_wrap: 'wrap'})
+      prop_add(1, 0, {type: 'errtype', text_padding_left: 3, text: 'E>'})
+      prop_add(3, 0, {type: 'errtype', text_padding_left: 3, text: 'E>'})
+  END
+  call writefile(lines, 'XscriptPropsAfterWideOverflow', 'D')
+  let buf = RunVimInTerminal('-S XscriptPropsAfterWideOverflow', #{rows: 8, cols: 40})
+  call VerifyScreenDump(buf, 'Test_prop_with_text_after_wide_char_2', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
 func Test_prop_with_text_below_cul()
   CheckScreendump
   CheckRunVimInTerminal
index f90d7197158ed9c089508e3c6b6cb09da1ef3f82..a4c2d05d455d4efaa2306a394a1b45da67bb25d6 100644 (file)
@@ -2157,4 +2157,25 @@ def Test_map_legacy_expr()
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
+" :call on a funcref stored in a dict member used to fail with E1017 in Vim9
+" script because get_lval() treated the subscript as a re-declaration.
+def Test_call_dict_funcref()
+  var lines =<< trim END
+      vim9script
+      var d: dict<any> = {}
+      var marker = ''
+      def F()
+        marker = 'called'
+      enddef
+      d.key = F
+      d['k2'] = F
+      call d.key()
+      assert_equal('called', marker)
+      marker = ''
+      call d['k2']()
+      assert_equal('called', marker)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
index bd4c0bbc328651d8c0efe966b97f2e9620e48856..ff5cf76a0eba9925c66ef499def70ec26b760737 100644 (file)
@@ -6273,7 +6273,7 @@ ex_delfunction(exarg_T *eap)
     int                is_global = FALSE;
 
     p = eap->arg;
-    name = trans_function_name_ext(&p, &is_global, eap->skip, 0, &fudi,
+    name = trans_function_name_ext(&p, &is_global, eap->skip, TFN_NO_DECL, &fudi,
                                                             NULL, NULL, NULL);
     vim_free(fudi.fd_newkey);
     if (name == NULL)
@@ -6823,7 +6823,7 @@ ex_call(exarg_T *eap)
        return;
     }
 
-    tofree = trans_function_name_ext(&arg, NULL, FALSE, TFN_INT,
+    tofree = trans_function_name_ext(&arg, NULL, FALSE, TFN_INT | TFN_NO_DECL,
                           &fudi, &partial, vim9script ? &type : NULL, &ufunc);
     if (fudi.fd_newkey != NULL)
     {
index a90dc1cb9b4771c059ee95d4d2d307a58c7f10e6..ac58fbdf80b598dc750fc5f79a2dc76bf37f7edc 100644 (file)
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    572,
 /**/
     571,
 /**/