@@ -231,13 +231,86 @@ void cread_print_hist_list(void)
}
}
-#define BEGINNING_OF_LINE() { \
- while (cls->num) { \
+#define GOTO_LINE_START(target) { \
+ while (cls->num > (target)) { \
cls_putch(cls, CTL_BACKSPACE); \
cls->num--; \
} \
}
+#define ERASE_TO(erase_to) { \
+ if (cls->num < (erase_to)) { \
+ uint wlen = (erase_to) - cls->num; \
+ \
+ /* erase characters on screen */ \
+ printf("%*s", wlen, ""); \
+ while (wlen--) \
+ cls_putch(cls, CTL_BACKSPACE); \
+ \
+ /* remove characters from buffer */ \
+ memmove(&buf[cls->num], &buf[erase_to], \
+ cls->eol_num - (erase_to) + 1); \
+ cls->eol_num -= (erase_to) - cls->num; \
+ } \
+}
+
+#if CONFIG_IS_ENABLED(CMDLINE_EDITOR)
+/**
+ * cread_start_of_line() - Move cursor to start of line
+ *
+ * In multiline mode, moves to the character after the previous newline.
+ * Otherwise moves to position 0.
+ *
+ * @cls: CLI line state
+ */
+static void cread_start_of_line(struct cli_line_state *cls)
+{
+ struct cli_editor_state *ed = cli_editor(cls);
+ uint target = 0;
+
+ if (ed && ed->multiline) {
+ char *buf = cls->buf;
+ uint i;
+
+ /* find previous newline */
+ for (i = cls->num; i > 0; i--) {
+ if (buf[i - 1] == '\n') {
+ target = i;
+ break;
+ }
+ }
+ }
+ GOTO_LINE_START(target);
+}
+#define BEGINNING_OF_LINE() cread_start_of_line(cls)
+#else
+#define BEGINNING_OF_LINE() GOTO_LINE_START(0)
+#endif
+
+#if CONFIG_IS_ENABLED(CMDLINE_EDITOR)
+static void cread_erase_to_eol(struct cli_line_state *cls)
+{
+ struct cli_editor_state *ed = cli_editor(cls);
+ char *buf = cls->buf;
+ uint erase_to;
+
+ if (cls->num >= cls->eol_num)
+ return;
+
+ /*
+ * In multiline mode, only erase to end of current line (next newline
+ * or end of buffer)
+ */
+ erase_to = cls->eol_num;
+ if (ed && ed->multiline) {
+ char *nl = strchr(&buf[cls->num], '\n');
+
+ if (nl)
+ erase_to = nl - buf;
+ }
+ ERASE_TO(erase_to);
+}
+#else
static void cread_erase_to_eol(struct cli_line_state *cls)
{
if (cls->num < cls->eol_num) {
@@ -247,15 +320,44 @@ static void cread_erase_to_eol(struct cli_line_state *cls)
} while (--cls->eol_num > cls->num);
}
}
+#endif
-#define REFRESH_TO_EOL() { \
- if (cls->num < cls->eol_num) { \
- uint wlen = cls->eol_num - cls->num; \
+#define GOTO_LINE_END(target) { \
+ if (cls->num < (target)) { \
+ uint wlen = (target) - cls->num; \
cls_putnstr(cls, buf + cls->num, wlen); \
- cls->num = cls->eol_num; \
+ cls->num = (target); \
} \
}
+#if CONFIG_IS_ENABLED(CMDLINE_EDITOR)
+/**
+ * cread_end_of_line() - Move cursor to end of line
+ *
+ * In multiline mode, moves to the next newline character.
+ * Otherwise moves to end of buffer.
+ *
+ * @cls: CLI line state
+ */
+static void cread_end_of_line(struct cli_line_state *cls)
+{
+ struct cli_editor_state *ed = cli_editor(cls);
+ char *buf = cls->buf;
+ uint target = cls->eol_num;
+
+ if (ed && ed->multiline) {
+ char *nl = strchr(&buf[cls->num], '\n');
+
+ if (nl)
+ target = nl - buf;
+ }
+ GOTO_LINE_END(target);
+}
+#define REFRESH_TO_EOL() cread_end_of_line(cls)
+#else
+#define REFRESH_TO_EOL() GOTO_LINE_END(cls->eol_num)
+#endif
+
static void cread_add_char(struct cli_line_state *cls, char ichar, int insert,
uint *num, uint *eol_num, char *buf, uint len)
{
@@ -179,15 +179,22 @@ static int editenv_test_funcs(struct unit_test_state *uts)
ut_assertok(editenv_send(&info, BKEY_DOWN));
ut_asserteq(16611, ut_check_video(uts, "down"));
- /* Type a character and press Ctrl-S to save */
+ /* Navigate with up arrow and insert '*' */
+ ut_assertok(editenv_send(&info, BKEY_UP));
+ ut_asserteq(16684, ut_check_video(uts, "up2"));
+
ut_assertok(editenv_send(&info, '*'));
- ut_asserteq(16689, ut_check_video(uts, "insert"));
+ ut_asserteq(16877, ut_check_video(uts, "insert"));
+
+ /* Use Ctrl-K to kill to end of line (stops at the existing newline) */
+ ut_assertok(editenv_send(&info, CTL_CH('k')));
+ ut_asserteq(16033, ut_check_video(uts, "kill"));
ut_asserteq(1, editenv_send(&info, BKEY_SAVE));
- /* The '*' should be appended to the initial text */
- ut_assert(strstr(expo_editenv_result(&info), "editor.*"));
- ut_asserteq(16689, ut_check_video(uts, "save"));
+ /* The '*' is inserted after "tes", Ctrl-K killed "ted properly." */
+ ut_assert(strstr(expo_editenv_result(&info), "tes*\n"));
+ ut_asserteq(16033, ut_check_video(uts, "save"));
expo_editenv_uninit(&info);
@@ -1681,16 +1681,16 @@ static int expo_render_textedit(struct unit_test_state *uts)
ut_assertok(expo_render(exp));
ut_asserteq(21211, video_compress_fb(uts, dev, false));
- /* go to start of buffer and delete a character */
+ /* go to start of line (multiline Home goes to start of current line) */
ut_assertok(expo_send_key(exp, CTL_CH('a')));
- ut_asserteq(0, ted->tin.cls.num);
+ ut_asserteq(5, ted->tin.cls.num);
ut_asserteq(91, ted->tin.cls.eol_num);
ut_assertok(expo_send_key(exp, CTL_CH('d')));
- ut_asserteq(0, ted->tin.cls.num);
+ ut_asserteq(5, ted->tin.cls.num);
ut_asserteq(90, ted->tin.cls.eol_num);
ut_assertok(scene_arrange(scn));
ut_assertok(expo_render(exp));
- ut_asserteq(21147, video_compress_fb(uts, dev, false));
+ ut_asserteq(21174, video_compress_fb(uts, dev, false));
/* go to end of buffer and backspace */
ut_assertok(expo_send_key(exp, CTL_CH('e')));
@@ -1701,7 +1701,7 @@ static int expo_render_textedit(struct unit_test_state *uts)
ut_asserteq(89, ted->tin.cls.eol_num);
ut_assertok(scene_arrange(scn));
ut_assertok(expo_render(exp));
- ut_asserteq(21083, video_compress_fb(uts, dev, false));
+ ut_asserteq(21079, video_compress_fb(uts, dev, false));
/* set multiline mode and check Enter inserts newline */
ted->obj.flags |= SCENEOF_MULTILINE;
@@ -1712,7 +1712,22 @@ static int expo_render_textedit(struct unit_test_state *uts)
ut_asserteq('\n', ((char *)abuf_data(&ted->tin.buf))[89]);
ut_assertok(scene_arrange(scn));
ut_assertok(expo_render(exp));
- ut_asserteq(21091, video_compress_fb(uts, dev, false));
+ ut_asserteq(21109, video_compress_fb(uts, dev, false));
+
+ /* go back 5 characters (before the newline) and use Ctrl+K */
+ ut_assertok(expo_send_key(exp, CTL_CH('b')));
+ ut_assertok(expo_send_key(exp, CTL_CH('b')));
+ ut_assertok(expo_send_key(exp, CTL_CH('b')));
+ ut_assertok(expo_send_key(exp, CTL_CH('b')));
+ ut_assertok(expo_send_key(exp, CTL_CH('b')));
+ ut_asserteq(85, ted->tin.cls.num);
+ ut_asserteq(90, ted->tin.cls.eol_num);
+
+ /* Ctrl+K in multiline mode should only delete to the newline */
+ ut_assertok(expo_send_key(exp, CTL_CH('k')));
+ ut_asserteq(85, ted->tin.cls.num);
+ ut_asserteq(86, ted->tin.cls.eol_num);
+ ut_asserteq('\n', ((char *)abuf_data(&ted->tin.buf))[85]);
/* clear multiline mode, close the textedit with Enter (BKEY_SELECT) */
ted->obj.flags &= ~SCENEOF_MULTILINE;
@@ -1724,12 +1739,12 @@ static int expo_render_textedit(struct unit_test_state *uts)
/* check the textedit is closed and text is changed */
ut_asserteq(0, ted->obj.flags & SCENEOF_OPEN);
- ut_asserteq_str("his\nis the initial contents of the text "
- "editor but it is ely that more will be added latr\n",
+ ut_asserteq_str("This\ns the initial contents of the text "
+ "editor but it is ely that more will be added \n",
abuf_data(&ted->tin.buf));
ut_assertok(scene_arrange(scn));
ut_assertok(expo_render(exp));
- ut_asserteq(21230, video_compress_fb(uts, dev, false));
+ ut_asserteq(21099, video_compress_fb(uts, dev, false));
abuf_uninit(&buf);
abuf_uninit(&logo_copy);