fasttyper/fasttyper/buffer.py
2022-03-07 11:54:54 +01:00

146 lines
4 KiB
Python

from .listener import Action
from enum import Enum
class CharType(Enum):
reference = 0
valid = 1
invalid = 2
class Buffer:
def __init__(self, buffer, text_box, stats):
self.reference_words = buffer.split()
self.user_words = []
self.total_words = len(self.reference_words)
self.current_word = 0
self.current_char = 0
self.text_box = text_box
self.stats = stats
self.text_box.set_buffer(self)
self.stats.set_buffer(self)
def _write(self, char):
while self.current_word >= len(self.user_words):
self.user_words.append("")
valid = False
try:
valid = (
self.reference_words[self.current_word][
len(self.user_words[self.current_word])
]
== char
)
except IndexError:
pass
if valid:
self.stats.signal_valid()
else:
self.stats.signal_invalid()
self.user_words[self.current_word] += char
self.current_char += 1
if self.current_word == self.total_words - 1 and self.current_char >= len(
self.reference_words[self.current_word]
):
self.stats.signal_stop(True)
def _next_word(self):
self.current_word += 1
self.current_char = 0
self.stats.signal_valid() # space is a char after all
if self.current_word >= self.total_words:
self.stats.signal_stop(True)
def _del_char(self):
try:
self.user_words[self.current_word] = self.user_words[self.current_word][:-1]
self.current_char -= 1
assert self.current_char >= 0
except (IndexError, AssertionError):
self.user_words = self.user_words[: self.current_word]
self.current_word = max(0, self.current_word - 1)
if self.current_word < len(self.user_words):
self.current_char = len(self.user_words[self.current_word])
else:
self.current_char = 0
def _del_word(self):
try:
if self.user_words[self.current_word] == "":
self.current_word = max(0, self.current_word - 1)
self.user_words[self.current_word] = ""
self.current_char = 0
except IndexError:
self.current_word = max(0, self.current_word - 1)
try:
self.user_words[self.current_word] = ""
except IndexError:
pass
self.current_char = 0
def handle_action(self, action, char):
if action == Action.add_char:
self._write(char)
elif action == Action.add_space:
self._next_word()
elif action == Action.del_char:
self._del_char()
elif action == Action.del_word:
self._del_word()
if self.stats.running():
self.text_box.update_current_word(self.current_word)
def get_word(self, index):
reference_word = self.reference_words[index]
user_word = ""
try:
user_word = self.user_words[index]
except IndexError:
pass
word = [
(r, CharType.valid if r == u else CharType.invalid)
for r, u in zip(reference_word, user_word)
]
word += [(c, CharType.invalid) for c in user_word[len(word) :]]
word += [(c, CharType.reference) for c in reference_word[len(word) :]]
return word
@property
def correct_words(self):
count = 0
for i, w in enumerate(self.user_words):
if i == self.total_words:
break
if w == self.reference_words[i]:
count += 1
return count
@property
def incorrect_words(self):
count = 0
for i, w in enumerate(self.user_words):
if i == self.total_words:
break
if w != self.reference_words[i]:
count += 1
return count