Teach the line editor to scroll + prompt
This commit is contained in:
parent
6b2def7531
commit
4261c81468
55
nncmpp.c
55
nncmpp.c
|
@ -639,6 +639,7 @@ static struct app_context
|
||||||
int *editor_w; ///< Codepoint widths, 0-terminated
|
int *editor_w; ///< Codepoint widths, 0-terminated
|
||||||
size_t editor_len; ///< Editor length
|
size_t editor_len; ///< Editor length
|
||||||
size_t editor_alloc; ///< Editor allocated
|
size_t editor_alloc; ///< Editor allocated
|
||||||
|
char editor_prompt; ///< Prompt character
|
||||||
void (*on_editor_changed) (void); ///< Callback on text change
|
void (*on_editor_changed) (void); ///< Callback on text change
|
||||||
void (*on_editor_end) (bool); ///< Callback on abort
|
void (*on_editor_end) (bool); ///< Callback on abort
|
||||||
|
|
||||||
|
@ -1362,21 +1363,33 @@ row_buffer_append_c (struct row_buffer *self, ucs4_t c, chtype attrs)
|
||||||
static int
|
static int
|
||||||
app_write_editor (struct row_buffer *row)
|
app_write_editor (struct row_buffer *row)
|
||||||
{
|
{
|
||||||
// TODO: there should be a one-character prefix to distinguish operations
|
int limit = COLS;
|
||||||
// (also known as the prompt)
|
if (g.editor_prompt)
|
||||||
// TODO: some scrolling mechanism
|
|
||||||
// - left = point - COLS/2 worth of cells
|
|
||||||
// - while there's space on the right, move the left further
|
|
||||||
// This seems to work in all cases.
|
|
||||||
|
|
||||||
int offset = 0;
|
|
||||||
for (size_t i = 0; i < g.editor_len; i++)
|
|
||||||
{
|
{
|
||||||
if (g.editor_point > (int) i)
|
hard_assert (g.editor_prompt < 127);
|
||||||
offset += g.editor_w[i];
|
row_buffer_append_c (row, g.editor_prompt, APP_ATTR (HIGHLIGHT));
|
||||||
row_buffer_append_c (row, g.editor_line[i], APP_ATTR (HIGHLIGHT));
|
limit--;
|
||||||
}
|
}
|
||||||
return MIN (offset, COLS - 1);
|
|
||||||
|
int following = 0;
|
||||||
|
for (size_t i = g.editor_point; i < g.editor_len; i++)
|
||||||
|
following += g.editor_w[i];
|
||||||
|
|
||||||
|
int preceding = 0;
|
||||||
|
size_t start = g.editor_point;
|
||||||
|
while (start && preceding < limit / 2)
|
||||||
|
preceding += g.editor_w[--start];
|
||||||
|
|
||||||
|
// There can be one extra space at the end of the line but this way we
|
||||||
|
// don't need to care about non-spacing marks following full-width chars
|
||||||
|
while (start && limit - preceding - following > 2 /* widest char */)
|
||||||
|
preceding += g.editor_w[--start];
|
||||||
|
|
||||||
|
// XXX: we should also show < > indicators for overflow but it'd probably
|
||||||
|
// considerably complicate this algorithm
|
||||||
|
for (; start < g.editor_len; start++)
|
||||||
|
row_buffer_append_c (row, g.editor_line[start], APP_ATTR (HIGHLIGHT));
|
||||||
|
return !!g.editor_prompt + preceding;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1612,22 +1625,25 @@ app_editor_abort (bool status)
|
||||||
g.on_editor_end = NULL;
|
g.on_editor_end = NULL;
|
||||||
|
|
||||||
free (g.editor_line);
|
free (g.editor_line);
|
||||||
free (g.editor_w);
|
|
||||||
g.editor_line = NULL;
|
g.editor_line = NULL;
|
||||||
|
free (g.editor_w);
|
||||||
g.editor_w = NULL;
|
g.editor_w = NULL;
|
||||||
g.editor_alloc = 0;
|
g.editor_alloc = 0;
|
||||||
g.editor_len = 0;
|
g.editor_len = 0;
|
||||||
|
g.editor_point = 0;
|
||||||
|
g.editor_prompt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start the line editor; remember to fill in "change" and "abort" callbacks
|
/// Start the line editor; remember to fill in "change" and "abort" callbacks
|
||||||
static void
|
static void
|
||||||
app_editor_start (void)
|
app_editor_start (char prompt)
|
||||||
{
|
{
|
||||||
g.editor_alloc = 16;
|
g.editor_alloc = 16;
|
||||||
g.editor_line = xcalloc (sizeof *g.editor_line, g.editor_alloc);
|
g.editor_line = xcalloc (sizeof *g.editor_line, g.editor_alloc);
|
||||||
g.editor_w = xcalloc (sizeof *g.editor_w, g.editor_alloc);
|
g.editor_w = xcalloc (sizeof *g.editor_w, g.editor_alloc);
|
||||||
g.editor_len = 0;
|
g.editor_len = 0;
|
||||||
g.editor_point = 0;
|
g.editor_point = 0;
|
||||||
|
g.editor_prompt = prompt;
|
||||||
app_invalidate ();
|
app_invalidate ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1751,7 +1767,7 @@ app_editor_process_action (enum action action)
|
||||||
static void
|
static void
|
||||||
app_editor_insert (ucs4_t codepoint)
|
app_editor_insert (ucs4_t codepoint)
|
||||||
{
|
{
|
||||||
while (g.editor_alloc - g.editor_len < 2)
|
while (g.editor_alloc - g.editor_len < 2 /* inserted + sentinel */)
|
||||||
{
|
{
|
||||||
g.editor_alloc <<= 1;
|
g.editor_alloc <<= 1;
|
||||||
g.editor_line = xreallocarray
|
g.editor_line = xreallocarray
|
||||||
|
@ -1759,11 +1775,14 @@ app_editor_insert (ucs4_t codepoint)
|
||||||
g.editor_w = xreallocarray
|
g.editor_w = xreallocarray
|
||||||
(g.editor_w, sizeof *g.editor_w, g.editor_alloc);
|
(g.editor_w, sizeof *g.editor_w, g.editor_alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
app_editor_move (g.editor_point + 1, g.editor_point,
|
app_editor_move (g.editor_point + 1, g.editor_point,
|
||||||
g.editor_len - g.editor_point);
|
g.editor_len - g.editor_point);
|
||||||
g.editor_line[g.editor_point] = codepoint;
|
g.editor_line[g.editor_point] = codepoint;
|
||||||
// FIXME: this should care about app_is_character_in_locale() as well
|
g.editor_w[g.editor_point] = app_is_character_in_locale (codepoint)
|
||||||
g.editor_w[g.editor_point] = uc_width (codepoint, locale_charset ());
|
? uc_width (codepoint, locale_charset ())
|
||||||
|
: 1 /* the replacement question mark */;
|
||||||
|
|
||||||
g.editor_point++;
|
g.editor_point++;
|
||||||
g.editor_len++;
|
g.editor_len++;
|
||||||
app_editor_changed ();
|
app_editor_changed ();
|
||||||
|
|
Loading…
Reference in New Issue