graphics/nxterm: support command-line cursor editing

Handle carriage return, cursor-left/right, and erase-to-end-of-line
sequences required by readline. Restore glyphs hidden by the cursor
so edited text redraws correctly.

Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: OpenAI Codex:gpt-5
This commit is contained in:
raiden00pl 2026-08-20 09:20:15 +02:00 committed by Xiang Xiao
parent 4ebc8a7291
commit 856fad2ffa
2 changed files with 116 additions and 2 deletions

View file

@ -51,10 +51,11 @@ void nxterm_putc(FAR struct nxterm_state_s *priv, uint8_t ch)
FAR const struct nxterm_bitmap_s *bm;
int lineheight;
/* Ignore carriage returns */
/* Handle carriage returns */
if (ch == '\r')
{
priv->fpos.x = priv->spwidth;
return;
}
@ -170,5 +171,22 @@ void nxterm_showcursor(FAR struct nxterm_state_s *priv)
void nxterm_hidecursor(FAR struct nxterm_state_s *priv)
{
int i;
nxterm_hidechar(priv, &priv->cursor);
/* A cursor moved into an existing line is drawn on top of a saved glyph.
* Restore that glyph after erasing the cursor so command-line editing does
* not leave a hole in the displayed text.
*/
for (i = priv->nchars - 1; i >= 0; i--)
{
if (priv->bm[i].pos.x == priv->cursor.pos.x &&
priv->bm[i].pos.y == priv->cursor.pos.y)
{
nxterm_fillchar(priv, NULL, &priv->bm[i]);
break;
}
}
}

View file

@ -51,6 +51,8 @@ struct vt100_sequence_s
****************************************************************************/
static int nxterm_erasetoeol(FAR struct nxterm_state_s *priv);
static int nxterm_cursorleft(FAR struct nxterm_state_s *priv);
static int nxterm_cursorright(FAR struct nxterm_state_s *priv);
/****************************************************************************
* Private Data
@ -63,12 +65,23 @@ static int nxterm_erasetoeol(FAR struct nxterm_state_s *priv);
/* <esc>[K is the VT100 command erases to the end of the line. */
static const char g_erasetoeol[] = VT100_CLEAREOL;
static const char g_cursorleft[] =
{
ASCII_ESC, '[', 'D'
};
static const char g_cursorright[] =
{
ASCII_ESC, '[', 'C'
};
/* The list of all VT100 sequences supported by the emulation */
static const struct vt100_sequence_s g_vt100sequences[] =
{
{g_erasetoeol, nxterm_erasetoeol, sizeof(g_erasetoeol)},
{g_cursorleft, nxterm_cursorleft, sizeof(g_cursorleft)},
{g_cursorright, nxterm_cursorright, sizeof(g_cursorright)},
{NULL, NULL, 0}
};
@ -92,7 +105,90 @@ static const struct vt100_sequence_s g_vt100sequences[] =
static int nxterm_erasetoeol(FAR struct nxterm_state_s *priv)
{
/* Does nothing yet (other than consume the sequence) */
struct nxgl_rect_s bounds;
uint16_t dst;
uint16_t src;
bounds.pt1.x = priv->fpos.x;
bounds.pt1.y = priv->fpos.y;
bounds.pt2.x = priv->wndo.wsize.w - 1;
bounds.pt2.y = priv->fpos.y + priv->fheight - 1;
priv->ops->fill(priv, &bounds, priv->wndo.wcolor);
/* Discard every saved glyph covered by the erased portion of this line.
* Keeping the bitmap list in sync is necessary for later redraw events.
*/
for (src = 0, dst = 0; src < priv->nchars; src++)
{
if (priv->bm[src].pos.y == priv->fpos.y &&
priv->bm[src].pos.x >= priv->fpos.x)
{
continue;
}
if (dst != src)
{
priv->bm[dst] = priv->bm[src];
}
dst++;
}
priv->nchars = dst;
return OK;
}
/****************************************************************************
* Name: nxterm_cursorleft
****************************************************************************/
static int nxterm_cursorleft(FAR struct nxterm_state_s *priv)
{
nxgl_coord_t x = priv->spwidth;
uint16_t i;
/* Find the closest saved glyph to the left on the current line. */
for (i = 0; i < priv->nchars; i++)
{
if (priv->bm[i].pos.y == priv->fpos.y &&
priv->bm[i].pos.x < priv->fpos.x &&
priv->bm[i].pos.x > x)
{
x = priv->bm[i].pos.x;
}
}
priv->fpos.x = x;
return OK;
}
/****************************************************************************
* Name: nxterm_cursorright
****************************************************************************/
static int nxterm_cursorright(FAR struct nxterm_state_s *priv)
{
FAR const struct nxfonts_glyph_s *glyph;
int i;
/* Prefer the most recently rendered glyph when editing has overdrawn a
* character at the same location.
*/
for (i = priv->nchars - 1; i >= 0; i--)
{
if (priv->bm[i].pos.y == priv->fpos.y &&
priv->bm[i].pos.x == priv->fpos.x)
{
glyph = nxf_cache_getglyph(priv->fcache, priv->bm[i].code);
priv->fpos.x += glyph == NULL ? priv->spwidth : glyph->width;
break;
}
}
return OK;
}