Rewrite tui_puts

This rewrites tui_puts.  It now writes as many bytes as possible in a
call to waddnstr, letting curses handle multi-byte sequences properly.

Note that tui_puts_internal remains.  It is needed to handle computing
the start line of the readline prompt, which is difficult to do
properly in the case where redisplaying can also cause the command
window to scroll.  This might be possible to implement by reverting to
single "character" output, by using mbsrtowcs for its side effects to
find character boundaries in the input.  I have not attempted this.

gdb/ChangeLog
2020-09-27  Tom Tromey  <tom@tromey.com>

	PR tui/25342:
	* tui/tui-io.c (tui_puts): Rewrite.  Move earlier.
This commit is contained in:
Tom Tromey 2020-09-27 20:30:30 -06:00
parent 35a982372f
commit 2c72d5e58a
2 changed files with 68 additions and 12 deletions

View File

@ -1,3 +1,8 @@
2020-09-27 Tom Tromey <tom@tromey.com>
PR tui/25342:
* tui/tui-io.c (tui_puts): Rewrite. Move earlier.
2020-09-27 Tom Tromey <tom@tromey.com>
PR tui/25342:

View File

@ -435,6 +435,69 @@ tui_write (const char *buf, size_t length)
tui_puts (copy.c_str ());
}
/* Print a string in the curses command window. The output is
buffered. It is up to the caller to refresh the screen if
necessary. */
void
tui_puts (const char *string, WINDOW *w)
{
if (w == nullptr)
w = TUI_CMD_WIN->handle.get ();
while (true)
{
const char *next = strpbrk (string, "\n\1\2\033\t");
/* Print the plain text prefix. */
size_t n_chars = next == nullptr ? strlen (string) : next - string;
if (n_chars > 0)
waddnstr (w, string, n_chars);
/* We finished. */
if (next == nullptr)
break;
char c = *next;
switch (c)
{
case '\1':
case '\2':
/* Ignore these, they are readline escape-marking
sequences. */
++next;
break;
case '\n':
case '\t':
do_tui_putc (w, c);
++next;
break;
case '\033':
{
size_t bytes_read = apply_ansi_escape (w, next);
if (bytes_read > 0)
next += bytes_read;
else
{
/* Just drop the escape. */
++next;
}
}
break;
default:
gdb_assert_not_reached ("missing case in tui_puts");
}
string = next;
}
if (TUI_CMD_WIN != nullptr && w == TUI_CMD_WIN->handle.get ())
update_cmdwin_start_line ();
}
static void
tui_puts_internal (WINDOW *w, const char *string, int *height)
{
@ -480,18 +543,6 @@ tui_puts_internal (WINDOW *w, const char *string, int *height)
wrefresh (w);
}
/* Print a string in the curses command window. The output is
buffered. It is up to the caller to refresh the screen if
necessary. */
void
tui_puts (const char *string, WINDOW *w)
{
if (w == nullptr)
w = TUI_CMD_WIN->handle.get ();
tui_puts_internal (w, string, nullptr);
}
/* Readline callback.
Redisplay the command line with its prompt after readline has
changed the edited text. */