return p && p[0] == 0x0a && p[1] == '\033' ? ++p : NULL;
}
+static bool in_dcs = false; // inside a DCS (sixel) sequence
+static bool dcs_esc = false; // last DCS byte written was ESC
+
+/*
+ * Write "len" bytes at "s" with WriteConsoleW, so that the console's own VT
+ * parser processes them. Needed for DCS sequences when USE_VTP is off.
+ */
+ static void
+write_vt(char_u *s, int len)
+{
+ int wlen;
+ WCHAR *ws;
+ DWORD written;
+
+ wlen = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)s, len, NULL, 0);
+ if (wlen <= 0)
+ return;
+ ws = ALLOC_MULT(WCHAR, wlen);
+ if (ws == NULL)
+ return;
+ MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)s, len, ws, wlen);
+ WriteConsoleW(g_hConOut, ws, wlen, &written, NULL);
+ vim_free(ws);
+}
+
+/*
+ * Return the pointer just after the ST (ESC '\') that ends a DCS sequence.
+ * Returns "end" when the ST is not in this chunk; "in_dcs" then stays set so
+ * that the next mch_write() call continues the scan.
+ */
+ static char_u *
+skip_dcs(char_u *s, char_u *end)
+{
+ for (char_u *p = s; p < end; ++p)
+ {
+ if (dcs_esc && *p == '\\')
+ {
+ dcs_esc = false;
+ in_dcs = false;
+ return p + 1;
+ }
+ dcs_esc = *p == ESC;
+ }
+ return end;
+}
+
/*
* mch_write(): write the output buffer to the screen, translating ESC
* sequences into calls to console output routines.
return;
}
+ if (in_dcs)
+ {
+ // Continuation of a DCS sequence split over several writes.
+ int l = (int)(skip_dcs(s, end) - s);
+
+ if (vtp_working)
+ write_vt(s, l);
+ len -= l - 1;
+ s += l;
+ continue;
+ }
+
while (s + ++prefix < end)
{
ch = s[prefix];
len -= l - 1;
s += l;
}
+ else if (s[0] == ESC && len >= 2-1 && s[1] == 'P')
+ {
+ // DCS (e.g. sixel image): write_chars() would print it as raw text
+ // when USE_VTP is off, so let the console's VT parser handle it.
+ int l;
+
+ in_dcs = true;
+ dcs_esc = false;
+ l = (int)(skip_dcs(s + 2, end) - s);
+ if (vtp_working)
+ write_vt(s, l);
+ len -= l - 1;
+ s += l;
+ }
else
{
// Write a single character
call popup_close(winid)
endfunc
+" A popup image is emitted as a DCS (sixel) escape sequence. On the Windows
+" console it has to go through the VT path, otherwise the escape sequence ends
+" up on the screen as raw text when 'termguicolors' is off. Send the sequence
+" with echoraw() so that only the console write is under test. See #20795.
+func Test_dcs_not_written_as_text_windows_cui()
+ CheckFeature terminal
+ if !has('win32') || has('gui_running')
+ throw 'Skipped: only for the Windows CUI'
+ endif
+
+ " Draw the text first, so nothing repairs the cells afterwards in case the
+ " sequence does land on the screen as text.
+ let lines =<< trim END
+ call setline(1, 'READY')
+ redraw
+ call echoraw("\<Esc>P0;1;8q\"1;1;8;8#1;2;100;0;0#1~~~~~~~~-\<Esc>\\")
+ END
+ call writefile(lines, 'XpopupDcs', 'D')
+
+ let buf = term_start(GetVimCommandCleanTerm() .. '-S XpopupDcs',
+ \ #{term_rows: 12, term_cols: 40})
+ call WaitForAssert({-> assert_equal('READY',
+ \ term_scrape(buf, 1)[:4]->map({_, v -> v['chars']})->join(''))})
+ call TermWait(buf, 50)
+
+ let screen = ''
+ for row in range(1, 12)
+ let screen ..= term_scrape(buf, row)->map({_, v -> v['chars']})->join('')
+ endfor
+ call assert_notmatch('0;1;8q', screen)
+
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_popup_image_set_and_getoptions()
CheckFeature image