patch 9.2.0572: lines disappear with wrapping virtual text after a double-width 
char

Commit: 
https://github.com/vim/vim/commit/09f7fc60d3d76504cf46871277e471d034776583
Author: Hirohito Higashi <[email protected]>
Date:   Sun May 31 18:43:42 2026 +0000

    patch 9.2.0572: lines disappear with wrapping virtual text after a 
double-width char
    
    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) <[email protected]>
    Signed-off-by: zeertzjq <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/runtime/doc/textprop.txt b/runtime/doc/textprop.txt
index 9fd5ff668..ce2867791 100644
--- a/runtime/doc/textprop.txt
+++ b/runtime/doc/textprop.txt
@@ -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"
diff --git a/src/drawline.c b/src/drawline.c
index 3ebb56a17..0b912e1ea 100644
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -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
index 000000000..36dfed3ff
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_with_text_after_wide_char_1.dump
@@ -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
index 000000000..50136517f
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_with_text_after_wide_char_2.dump
@@ -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| 
diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim
index a57493bc8..7d868ec06 100644
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -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) .. " ",
+          '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
diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim
index f90d71971..a4c2d05d4 100644
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -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
diff --git a/src/userfunc.c b/src/userfunc.c
index bd4c0bbc3..ff5cf76a0 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -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)
     {
diff --git a/src/version.c b/src/version.c
index a90dc1cb9..ac58fbdf8 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    572,
 /**/
     571,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1wTlOH-00GQdq-Aj%40256bit.org.

Raspunde prin e-mail lui