From b651ad4a8509e0f72f9c8f416dc02f3669672b35 Mon Sep 17 00:00:00 2001 From: rillig Date: Mon, 22 Feb 2021 17:36:42 +0000 Subject: cgram: add advanced cursor movement with tab, shift+tab, return --- cgram/cgram.c | 166 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 117 insertions(+), 49 deletions(-) diff --git a/cgram/cgram.c b/cgram/cgram.c index 3d33d85a..93ebddd9 100644 --- a/cgram/cgram.c +++ b/cgram/cgram.c @@ -1,4 +1,4 @@ -/* $NetBSD: cgram.c,v 1.12 2021/02/22 16:28:20 rillig Exp $ */ +/* $NetBSD: cgram.c,v 1.13 2021/02/22 17:36:42 rillig Exp $ */ /*- * Copyright (c) 2013, 2021 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include #if defined(__RCSID) && !defined(lint) -__RCSID("$NetBSD: cgram.c,v 1.12 2021/02/22 16:28:20 rillig Exp $"); +__RCSID("$NetBSD: cgram.c,v 1.13 2021/02/22 17:36:42 rillig Exp $"); #endif #include @@ -72,6 +72,12 @@ ch_islower(char ch) return islower((unsigned char)ch) != 0; } +static bool +ch_isspace(char ch) +{ + return isspace((unsigned char)ch) != 0; +} + static bool ch_isupper(char ch) { @@ -193,6 +199,23 @@ cur_max_y(void) return extent_y - 1; } +static char +char_left_of_cursor(void) +{ + if (cursor_x > 0) + return lines.v[cursor_y].s[cursor_x - 1]; + assert(cursor_y > 0); + return '\n'; /* eol of previous line */ +} + +static char +char_at_cursor(void) +{ + if (cursor_x == cur_max_x()) + return '\n'; + return lines.v[cursor_y].s[cursor_x]; +} + static void readquote(void) { @@ -266,7 +289,7 @@ substitute(char ch) return false; } - char och = lines.v[cursor_y].s[cursor_x]; + char och = char_at_cursor(); if (!ch_isalpha(och)) { beep(); return false; @@ -292,8 +315,6 @@ substitute(char ch) return true; } -//////////////////////////////////////////////////////////// - static bool is_solved(void) { @@ -303,6 +324,8 @@ is_solved(void) return true; } +//////////////////////////////////////////////////////////// + static void redraw(void) { @@ -342,21 +365,6 @@ redraw(void) refresh(); } -static void -opencurses(void) -{ - initscr(); - cbreak(); - noecho(); - keypad(stdscr, true); -} - -static void -closecurses(void) -{ - endwin(); -} - //////////////////////////////////////////////////////////// static void @@ -383,6 +391,72 @@ scroll_into_view(void) offset_y = cursor_y - (LINES - 2); } +static bool +can_go_left(void) +{ + return cursor_y > 0 || + (cursor_y == 0 && cursor_x > 0); +} + +static bool +can_go_right(void) +{ + return cursor_y < cur_max_y() || + (cursor_y == cur_max_y() && cursor_x < cur_max_x()); +} + +static void +go_to_prev_line(void) +{ + cursor_y--; + cursor_x = cur_max_x(); +} + +static void +go_to_next_line(void) +{ + cursor_x = 0; + cursor_y++; +} + +static void +go_left(void) +{ + if (cursor_x > 0) + cursor_x--; + else if (cursor_y > 0) + go_to_prev_line(); +} + +static void +go_right(void) +{ + if (cursor_x < cur_max_x()) + cursor_x++; + else if (cursor_y < cur_max_y()) + go_to_next_line(); +} + +static void +go_to_prev_word(void) +{ + while (can_go_left() && ch_isspace(char_left_of_cursor())) + go_left(); + + while (can_go_left() && !ch_isspace(char_left_of_cursor())) + go_left(); +} + +static void +go_to_next_word(void) +{ + while (can_go_right() && !ch_isspace(char_at_cursor())) + go_right(); + + while (can_go_right() && ch_isspace(char_at_cursor())) + go_right(); +} + static void handle_char_input(int ch) { @@ -390,23 +464,13 @@ handle_char_input(int ch) if (substitute((char)ch)) { if (cursor_x < cur_max_x()) cursor_x++; - if (cursor_x == cur_max_x() && - cursor_y < cur_max_y()) { - cursor_x = 0; - cursor_y++; - } - } - } else if (cursor_x < cur_max_x() && - ch == lines.v[cursor_y].s[cursor_x]) { - cursor_x++; - if (cursor_x == cur_max_x() && - cursor_y < cur_max_y()) { - cursor_x = 0; - cursor_y++; + if (cursor_x == cur_max_x()) + go_to_next_line(); } - } else { + } else if (ch == char_at_cursor()) + go_right(); + else beep(); - } } static bool @@ -421,12 +485,7 @@ handle_key(void) break; case 2: /* ^B */ case KEY_LEFT: - if (cursor_x > 0) { - cursor_x--; - } else if (cursor_y > 0) { - cursor_y--; - cursor_x = cur_max_x(); - } + go_left(); break; case 5: /* ^E */ case KEY_END: @@ -434,12 +493,16 @@ handle_key(void) break; case 6: /* ^F */ case KEY_RIGHT: - if (cursor_x < cur_max_x()) { - cursor_x++; - } else if (cursor_y < cur_max_y()) { - cursor_y++; - cursor_x = 0; - } + go_right(); + break; + case '\t': + go_to_next_word(); + break; + case KEY_BTAB: + go_to_prev_word(); + break; + case '\n': + go_to_next_line(); break; case 12: /* ^L */ clear(); @@ -478,7 +541,11 @@ init(void) srandom((unsigned int)time(NULL)); readquote(); encode(); - opencurses(); + + initscr(); + cbreak(); + noecho(); + keypad(stdscr, true); } static void @@ -496,7 +563,8 @@ loop(void) static void clean_up(void) { - closecurses(); + endwin(); + stringarray_cleanup(&sollines); stringarray_cleanup(&lines); } -- cgit v1.2.3-56-ge451