From 4261c8146812f0e48b8090e79c05cbc5db4bbd41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Mon, 26 Jun 2017 03:10:02 +0200 Subject: Teach the line editor to scroll + prompt --- nncmpp.c | 55 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/nncmpp.c b/nncmpp.c index 1e39ec1..65435d3 100644 --- a/nncmpp.c +++ b/nncmpp.c @@ -639,6 +639,7 @@ static struct app_context int *editor_w; ///< Codepoint widths, 0-terminated size_t editor_len; ///< Editor length size_t editor_alloc; ///< Editor allocated + char editor_prompt; ///< Prompt character void (*on_editor_changed) (void); ///< Callback on text change 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 app_write_editor (struct row_buffer *row) { - // TODO: there should be a one-character prefix to distinguish operations - // (also known as the 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++) + int limit = COLS; + if (g.editor_prompt) { - if (g.editor_point > (int) i) - offset += g.editor_w[i]; - row_buffer_append_c (row, g.editor_line[i], APP_ATTR (HIGHLIGHT)); + hard_assert (g.editor_prompt < 127); + row_buffer_append_c (row, g.editor_prompt, 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 @@ -1612,22 +1625,25 @@ app_editor_abort (bool status) g.on_editor_end = NULL; free (g.editor_line); - free (g.editor_w); g.editor_line = NULL; + free (g.editor_w); g.editor_w = NULL; g.editor_alloc = 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 static void -app_editor_start (void) +app_editor_start (char prompt) { g.editor_alloc = 16; g.editor_line = xcalloc (sizeof *g.editor_line, g.editor_alloc); g.editor_w = xcalloc (sizeof *g.editor_w, g.editor_alloc); g.editor_len = 0; g.editor_point = 0; + g.editor_prompt = prompt; app_invalidate (); } @@ -1751,7 +1767,7 @@ app_editor_process_action (enum action action) static void 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_line = xreallocarray @@ -1759,11 +1775,14 @@ app_editor_insert (ucs4_t codepoint) g.editor_w = xreallocarray (g.editor_w, sizeof *g.editor_w, g.editor_alloc); } + app_editor_move (g.editor_point + 1, g.editor_point, g.editor_len - g.editor_point); 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] = uc_width (codepoint, locale_charset ()); + g.editor_w[g.editor_point] = app_is_character_in_locale (codepoint) + ? uc_width (codepoint, locale_charset ()) + : 1 /* the replacement question mark */; + g.editor_point++; g.editor_len++; app_editor_changed (); -- cgit v1.2.3