Hi On Sun, Feb 23, 2025 at 6:56 PM Roman Penyaev <r.peni...@gmail.com> wrote: > > This patch implements DCH (delete character) and ICH (insert > character) commands. > > DCH - Delete Character: > "As characters are deleted, the remaining characters between the > cursor and right margin move to the left. Character attributes move > with the characters. The terminal adds blank spaces with no visual > character attributes at the right margin. DCH has no effect outside > the scrolling margins" [1]. > > ICH - Insert Character: > "The ICH sequence inserts Pn blank characters with the normal > character attribute. The cursor remains at the beginning of the > blank characters. Text between the cursor and right margin moves to > the right. Characters scrolled past the right margin are lost. ICH > has no effect outside the scrolling margins" [2]. > > Without these commands console is barely usable. > > [1] https://vt100.net/docs/vt510-rm/DCH.html > [1] https://vt100.net/docs/vt510-rm/ICH.html > > Signed-off-by: Roman Penyaev <r.peni...@gmail.com> > Cc: "Marc-André Lureau" <marcandre.lur...@redhat.com> > Cc: qemu-devel@nongnu.org > --- > ui/console-vc.c | 108 +++++++++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 102 insertions(+), 6 deletions(-) > > diff --git a/ui/console-vc.c b/ui/console-vc.c > index 522adc2806c8..bc667897d1bc 100644 > --- a/ui/console-vc.c > +++ b/ui/console-vc.c > @@ -598,21 +598,29 @@ static void vc_clear_xy(VCChardev *vc, int x, int y) > vc_update_xy(vc, x, y); > } > > -static void vc_put_one(VCChardev *vc, int ch) > +static void vc_insert_xy(VCChardev *vc, int ch, int x, int y) > { > QemuTextConsole *s = vc->console; > TextCell *c; > int y1; > + > + y1 = (s->y_base + y) % s->total_height; > + c = &s->cells[y1 * s->width + x]; > + c->ch = ch; > + c->t_attrib = vc->t_attrib; > + vc_update_xy(vc, x, y); > +} > + > +static void vc_put_one(VCChardev *vc, int ch) > +{ > + QemuTextConsole *s = vc->console; > + > if (s->x >= s->width) { > /* line wrap */ > s->x = 0; > vc_put_lf(vc); > } > - y1 = (s->y_base + s->y) % s->total_height; > - c = &s->cells[y1 * s->width + s->x]; > - c->ch = ch; > - c->t_attrib = vc->t_attrib; > - vc_update_xy(vc, s->x, s->y); > + vc_insert_xy(vc, ch, s->x, s->y); > s->x++; > } > > @@ -645,6 +653,88 @@ static void vc_set_cursor(VCChardev *vc, int x, int y) > s->y = y; > } > > +/** > + * vc_csi_P() - (DCH) deletes one or more characters from the cursor > + * position to the right. As characters are deleted, the remaining > + * characters between the cursor and right margin move to the > + * left. Character attributes move with the characters. > + */ > +static void vc_csi_P(struct VCChardev *vc, unsigned int nr) > +{ > + QemuTextConsole *s = vc->console; > + TextCell *c1, *c2; > + unsigned int x1, x2, y; > + unsigned int end, len; > + > + if (!nr) { > + nr = 1; > + } > + if (nr > s->width - s->x) { > + nr = s->width - s->x; > + if (!nr) { > + return; > + } > + } > + > + x1 = s->x; > + x2 = s->x + nr; > + len = s->width - x2; > + if (len) { > + y = (s->y_base + s->y) % s->total_height; > + c1 = &s->cells[y * s->width + x1]; > + c2 = &s->cells[y * s->width + x2]; > + memmove(c1, c2, len * sizeof(*c1)); > + for (end = x1 + len; x1 < end; x1++) { > + vc_update_xy(vc, x1, s->y); > + } > + } > + /* Clear the rest */ > + for (; x1 < s->width; x1++) { > + vc_clear_xy(vc, x1, s->y); > + } > +} > + > +/** > + * vc_csi_at() - (ICH) inserts `nr` blank characters with the normal > + * character attribute. The cursor remains at the beginning of the
What is "normal character attribute"? Should you set it to TEXT_ATTRIBUTES_DEFAULT while inserting blank chars? > + * blank characters. Text between the cursor and right margin moves to > + * the right. Characters scrolled past the right margin are lost. > + */ > +static void vc_csi_at(struct VCChardev *vc, unsigned int nr) > +{ > + QemuTextConsole *s = vc->console; > + TextCell *c1, *c2; > + unsigned int x1, x2, y; > + unsigned int end, len; > + > + if (!nr) { > + nr = 1; > + } > + if (nr > s->width - s->x) { > + nr = s->width - s->x; > + if (!nr) { > + return; > + } > + } > + > + x1 = s->x + nr; > + x2 = s->x; > + len = s->width - x1; > + if (len) { > + y = (s->y_base + s->y) % s->total_height; > + c1 = &s->cells[y * s->width + x1]; > + c2 = &s->cells[y * s->width + x2]; > + memmove(c1, c2, len * sizeof(*c1)); > + for (end = x1 + len; x1 < end; x1++) { > + vc_update_xy(vc, x1, s->y); > + } > + } > + /* Insert spaces */ > + for (x1 = s->x; x1 < s->x + nr; x1++) { > + vc_insert_xy(vc, ' ', x1, s->y); > + } > +} > + > /** > * vc_save_cursor() - saves cursor position and character attributes. > */ > @@ -847,6 +937,9 @@ static void vc_putchar(VCChardev *vc, int ch) > break; > } > break; > + case 'P': > + vc_csi_P(vc, vc->esc_params[0]); > + break; > case 'm': > vc_handle_escape(vc); > break; > @@ -870,6 +963,9 @@ static void vc_putchar(VCChardev *vc, int ch) > case 'u': > vc_restore_cursor(vc); > break; > + case '@': > + vc_csi_at(vc, vc->esc_params[0]); > + break; > default: > trace_console_putchar_unhandled(ch); > break; > -- > 2.43.0 > > -- Marc-André Lureau