#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import curses class Word(): def __init__(self, target, x, y): self.target = target self.input = "" self.x = x self.y = y def get_words(text, max_x, max_y): curr_x = 0 curr_y = 0 words = [] for word in text.split(): if curr_x + len(word) > max_x: curr_y += 1 curr_x = 0 if curr_y > max_y: print("text too long, scrolling not implemented.") exit(1) words.append(Word(word, curr_x, curr_y)) curr_x += len(word) + 1 return words def main_curses(stdscr, text): curses.use_default_colors() curses.init_pair(1, curses.COLOR_GREEN, -1) curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_RED) key = old_max_y = old_max_x = curr_word = 0 while True: # rewrap words on screen size change max_y, max_x = stdscr.getmaxyx() if max_y != old_max_y or max_x != old_max_x: words = get_words(text, max_x, max_y) old_max_x = max_x old_max_y = max_y if key in (curses.KEY_BACKSPACE, 'KEY_BACKSPACE', '\b', '\x7f', 127): # fml words[curr_word].input = words[curr_word].input[:-1] elif key >= 32 and key <= 126: words[curr_word].input += chr(key) # increment current word if its completed if words[curr_word].input == words[curr_word].target: curr_word += 1 # text complete if curr_word == len(words): break stdscr.clear() for word in words: if word.input == word.target: stdscr.addstr(word.y, word.x, word.target, curses.A_DIM) elif word == words[curr_word]: stdscr.addstr(word.y, word.x, word.target, curses.A_UNDERLINE) else: stdscr.addstr(word.y, word.x, word.target) for i, c in enumerate(words[curr_word].input): if i >= len(words[curr_word].target) or words[curr_word].input[i] != words[curr_word].target[i]: stdscr.addstr(words[curr_word].y, words[curr_word].x + i, c, curses.color_pair(2) | curses.A_BOLD) else: stdscr.addstr(words[curr_word].y, words[curr_word].x + i, c, curses.color_pair(1)) stdscr.move(words[curr_word].y, words[curr_word].x + len(words[curr_word].input)) key = stdscr.getch() def main(argv): from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("input") args = parser.parse_args(argv[1:]) text = open(args.input).read() curses.wrapper(main_curses, text) if __name__ == "__main__": main(sys.argv)