Module Name:    src
Committed By:   rillig
Date:           Mon Feb 22 17:36:42 UTC 2021

Modified Files:
        src/games/cgram: cgram.c

Log Message:
cgram: add advanced cursor movement with tab, shift+tab, return


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/games/cgram/cgram.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/games/cgram/cgram.c
diff -u src/games/cgram/cgram.c:1.12 src/games/cgram/cgram.c:1.13
--- src/games/cgram/cgram.c:1.12	Mon Feb 22 16:28:20 2021
+++ src/games/cgram/cgram.c	Mon Feb 22 17:36:42 2021
@@ -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 <sys/cdefs.h>
 #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 <assert.h>
@@ -73,6 +73,12 @@ ch_islower(char ch)
 }
 
 static bool
+ch_isspace(char ch)
+{
+	return isspace((unsigned char)ch) != 0;
+}
+
+static bool
 ch_isupper(char ch)
 {
 	return isupper((unsigned char)ch) != 0;
@@ -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);
 }

Reply via email to