commit 9fb7d9a0b6ae910e5b64300451cdc1a2fe4024f8
parent 09da1f9bea7fb12e327de2399a62ab3370f4f629
Author: Emma Weaver <emma@waeaves.com>
Date: Sat, 2 May 2026 15:26:54 -0400
Added hardwrapping of long prompts
Diffstat:
5 files changed, 74 insertions(+), 103 deletions(-)
diff --git a/examples/lesson.sh b/examples/lesson.sh
@@ -24,21 +24,21 @@ echo "If it gets too hard, don't be afraid to ctrl+C and redo previous lessons."
echo ""
echo "Introducing the new letters..."
-typie -lf /dev/null "$(./words.sh "$NEW_LETTERS" 6 12)"
-typie -lf /dev/null "$(./words.sh "$NEW_LETTERS" 6 12)"
+typie -lf /dev/null "$(./words-by-letter.sh "$NEW_LETTERS" 6 12)"
+typie -lf /dev/null "$(./words-by-letter.sh "$NEW_LETTERS" 6 12)"
echo "Integrating with some old letters..."
-typie -f /dev/null "$(./words.sh "$(old_letters $EASY)$NEW_LETTERS" 5 8)"
-typie -f /dev/null "$(./words.sh "$(old_letters $EASY)$NEW_LETTERS" 5 8)"
-typie -f /dev/null "$(./words.sh "$(old_letters $EASY)$NEW_LETTERS" 5 8)"
-typie -f /dev/null "$(./words.sh "$(old_letters $MEDIUM)$NEW_LETTERS" 5 8)"
-typie -f /dev/null "$(./words.sh "$(old_letters $MEDIUM)$NEW_LETTERS" 5 8)"
-typie -f /dev/null "$(./words.sh "$(old_letters $HARD)$NEW_LETTERS" 5 8)"
-typie -f /dev/null "$(./words.sh "$(old_letters $HARD)$NEW_LETTERS" 5 8)"
+typie -f /dev/null "$(./words-by-letter.sh "$(old_letters $EASY)$NEW_LETTERS" 5 8)"
+typie -f /dev/null "$(./words-by-letter.sh "$(old_letters $EASY)$NEW_LETTERS" 5 8)"
+typie -f /dev/null "$(./words-by-letter.sh "$(old_letters $EASY)$NEW_LETTERS" 5 8)"
+typie -f /dev/null "$(./words-by-letter.sh "$(old_letters $MEDIUM)$NEW_LETTERS" 5 8)"
+typie -f /dev/null "$(./words-by-letter.sh "$(old_letters $MEDIUM)$NEW_LETTERS" 5 8)"
+typie -f /dev/null "$(./words-by-letter.sh "$(old_letters $HARD)$NEW_LETTERS" 5 8)"
+typie -f /dev/null "$(./words-by-letter.sh "$(old_letters $HARD)$NEW_LETTERS" 5 8)"
echo "All together now!"
-typie -f /dev/null "$(./words.sh "$OLD_LETTERS$NEW_LETTERS" 5 8)"
-typie -f /dev/null "$(./words.sh "$OLD_LETTERS$NEW_LETTERS" 5 8)"
-typie -f /dev/null "$(./words.sh "$OLD_LETTERS$NEW_LETTERS" 5 8)"
+typie -f /dev/null "$(./words-by-letter.sh "$OLD_LETTERS$NEW_LETTERS" 5 8)"
+typie -f /dev/null "$(./words-by-letter.sh "$OLD_LETTERS$NEW_LETTERS" 5 8)"
+typie -f /dev/null "$(./words-by-letter.sh "$OLD_LETTERS$NEW_LETTERS" 5 8)"
echo "All done! :3"
diff --git a/examples/words.sh b/examples/words-by-letter.sh
diff --git a/examples/words.sh b/examples/words.sh
@@ -1,35 +1,5 @@
+#!/bin/sh
-CHARSET=$1
-MIN_LENGTH=$2
-MAX_LENGTH=$3
-DICTFILE="dicts/20k.txt"
-
-if [ $CHARSET = "" ]; then
- echo "Requires charset argument."
- exit 1
-fi
-
-# filter the dictionary for words only involving the characters, len >= 5.
-WORDS="$(cat $DICTFILE | egrep "^[$CHARSET]{5,}$")"
-
-LENGTH="$(seq $MIN_LENGTH $MAX_LENGTH | shuf -n 1)"
-WORD_COUNT="$(echo "$WORDS" | wc -l)"
-FEW_WORDS="false"
-if [ "$WORD_COUNT" -lt "$LENGTH" ]; then
- FEW_WORDS="true"
-fi
-
-get_word() {
- ./letters.sh "$CHARSET" 4 6
-}
-
-if [ $FEW_WORDS = "true" ]; then
- PROMPT="$(get_word)"
- for i in $(seq $LENGTH); do
- PROMPT="$PROMPT $(get_word)"
- done
- echo "$PROMPT"
-else
- echo "$WORDS" | shuf -n $LENGTH | xargs echo
-fi
+cd $(dirname $0)
+./words-by-letter.sh "abcdefghijklmnopqrstuvwxyz" $1 $1
diff --git a/typer.c b/typer.c
@@ -3,6 +3,8 @@
#include "typer.h"
#include "opt.h"
+#define PRINT_CONTROL(literal) printf(literal);
+
void
setup_termios(struct termios term_og)
{
@@ -27,35 +29,29 @@ restore_termios(struct termios term_og)
}
void
-cursor_back(int steps)
+cursor_back(State * state, int steps)
{
+ while (state->column < steps) {
+ steps -= state->column;
+ state->column = 80;
+ state->row--;
+ printf("\r" "\033[1A" "\033[80C"); // cursor up 1 + right 80
+ }
+ state->column -= steps;
printf("\033[" "%d" "D", steps);
}
void
-cursor_forward(int steps)
-{
- printf("\033[" "%d" "C", steps);
-}
-
-void
-cursor_up(int steps)
-{
- printf("\033[" "%d" "A", steps);
-}
-
-void
-cursor_down(int steps)
-{
- printf("\033[" "%d" "B", steps);
-}
-
-void
-print_char(char c)
+print_char(State * state, char c)
{
- /* replace spaces with interpuncts. */
+ if (state->column >= 80) {
+ printf("\n\r");
+ state->column = 0;
+ state->row++;
+ }
if (c == ' ') printf("\u00B7");
else printf("%c", c);
+ state->column++;
}
void
@@ -68,12 +64,13 @@ add_jump(State * state, int size)
int
remove_jump(State * state)
{
- /* returns the size of the most recent jump */
+ /* returns the size of the removed jump */
state->jumps.length--;
return state->jumps.buffer[state->jumps.length];
}
+// TODO refactor this to just be a general print_str method?
void
show_remaining(State * state)
{
@@ -83,7 +80,7 @@ show_remaining(State * state)
int steps = 0;
char c;
- printf(COLOR_RESET "\033[0K"); /* clear to end of line */
+ PRINT_CONTROL(COLOR_RESET CLEAR_TO_LINE_END);
if (prompt[index] == '\0')
return;
@@ -93,11 +90,11 @@ show_remaining(State * state)
if (c == '\0' || c == '\n')
break;
- printf("%c", prompt[index]);
+ print_char(state, prompt[index]);
steps++;
index++;
}
- cursor_back(steps);
+ cursor_back(state, steps);
}
void
@@ -114,12 +111,13 @@ skip(State * state, char input)
if (c == '\0' || IS_BLANK(c) != blankness)
break;
- printf("%c" COLOR_YELLOW, c);
+ print_char(state, c);
+ PRINT_CONTROL(COLOR_YELLOW);
steps++;
state->index++;
}
if (c != '\0') {
- printf("%c", input);
+ print_char(state, input);
steps++;
state->index++;
}
@@ -129,8 +127,8 @@ skip(State * state, char input)
void
on_correct(State * state, char c)
{
- printf(COLOR_GREEN);
- printf("%c", c);
+ PRINT_CONTROL(COLOR_GREEN);
+ print_char(state, c);
add_jump(state, 1);
state->index++;
@@ -144,16 +142,16 @@ on_incorrect(State * state, char c)
char expected_c = prompt[state->index];
int input_blank = IS_BLANK(c), prompt_blank = IS_BLANK(expected_c);
- printf(COLOR_RED);
+ PRINT_CONTROL(COLOR_RED);
if (state->flags & FLAG_LEARN_MODE) {
- print_char(c);
+ print_char(state, c);
show_remaining(state);
- cursor_back(1);
+ cursor_back(state, 1);
return;
}
if (expected_c == '\0') {
- print_char(c);
+ print_char(state, c);
add_jump(state, 0);
return;
}
@@ -163,7 +161,7 @@ on_incorrect(State * state, char c)
(!input_blank && !prompt_blank)
) {
/* correct character type */
- print_char(c);
+ print_char(state, c);
state->index++;
add_jump(state, 1);
return;
@@ -174,7 +172,7 @@ on_incorrect(State * state, char c)
IS_BLANK(prompt[state->index-1]) == input_blank
) {
/* extra letters at the end of a chunk */
- print_char(c);
+ print_char(state, c);
add_jump(state, 0);
show_remaining(state);
return;
@@ -200,12 +198,12 @@ on_backspace(State * state)
jump = remove_jump(state);
if (jump == 0) {
- cursor_back(1);
+ cursor_back(state, 1);
show_remaining(state);
return;
}
- cursor_back(jump);
+ cursor_back(state, jump);
state->index -= jump;
show_remaining(state);
}
@@ -220,8 +218,7 @@ void
start_typing(State * state)
{
state->index = 0;
- printf(COLOR_BOLD "%s" COLOR_RESET "\r", state->prompt);
- // printf("%s" "\n" "\r", state->prompt);
+ show_remaining(state);
}
int
diff --git a/typer.h b/typer.h
@@ -5,32 +5,32 @@
#include <time.h>
-#define COLOR_GREEN "\033[1;32m"
-#define COLOR_YELLOW "\033[1;33m"
-#define COLOR_RED "\033[1;31m"
+#define COLOR_GREEN "\033[1;32m"
+#define COLOR_YELLOW "\033[1;33m"
+#define COLOR_RED "\033[1;31m"
#define COLOR_PALE_RED "\033[0;31m"
-#define COLOR_BOLD "\033[1;37m"
-#define COLOR_RESET "\033[0m"
-#define CLEAR_LINE "\033[0K"
+#define COLOR_BOLD "\033[1;37m"
+#define COLOR_RESET "\033[0m"
+#define CLEAR_TO_LINE_END "\033[0K"
-#define KEY_CTRL_C 3
-#define KEY_CTRL_D 4
-#define KEY_ENTER 13
-#define KEY_ESCAPE 27
-#define KEY_BACKSPACE 127
-#define KEY_SHIFT_BACKSPACE 8
+#define KEY_CTRL_C 3
+#define KEY_CTRL_D 4
+#define KEY_ENTER 13
+#define KEY_ESCAPE 27
+#define KEY_BACKSPACE 127
+#define KEY_SHIFT_BACKSPACE 8
#define IS_BLANK(X) ((X) == ' ' || (X) == '\t')
#define IS_NUMBER(X) ((X) >= '0' && (X) <= '9')
#define IS_LETTER(X) (((X) >= 'a' && (X) <= 'z') || ((X) >= 'A' && (X) <= 'Z'))
#define IS_ALPHANUMERIC(X) (IS_LETTER(X) || IS_NUMBER(X))
-#define KEYPRESS_CORRECT 0
-#define KEYPRESS_INCORRECT 1
-#define KEYPRESS_BACKSPACE 2
-#define KEYPRESS_EXIT 3
-#define KEYPRESS_ENTER 4
-#define KEYPRESS_NONE 5
+#define KEYPRESS_CORRECT 0
+#define KEYPRESS_INCORRECT 1
+#define KEYPRESS_BACKSPACE 2
+#define KEYPRESS_EXIT 3
+#define KEYPRESS_ENTER 4
+#define KEYPRESS_NONE 5
typedef struct {
int * buffer;
@@ -45,9 +45,13 @@ typedef struct {
/* records how many characters are traversed by each keypress */
Jumps jumps;
- /* sum of jumps, current index in prompt */
+ /* sum of jumps, cursor's index in prompt */
int index;
+ /* cursor's position within the terminal */
+ int column;
+ int row;
+
/* keypress tallies */
int chars_correct;
int chars_total;