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

This commit is contained in:
rillig 2021-02-22 17:36:42 +00:00
parent 47c6585f93
commit f7c85ecb67
1 changed files with 117 additions and 49 deletions

View File

@ -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>
@ -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++;
}
if (cursor_x == cur_max_x())
go_to_next_line();
}
} 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++;
}
} 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);
}