Initial commit. Old work.
This commit is contained in:
commit
bc574ba0a4
18
README.md
Normal file
18
README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Rtutor
|
||||
|
||||
Rtutor is an application written in python to train yourself to use vim fast way and to learn over 60 shortcuts! Features:
|
||||
- Display question answered right / wrong statitiscs.
|
||||
- Display AVG time spent to answer a question.
|
||||
- Questions with random values to make it less boring.
|
||||
- Repeat question on random moment if you answered it wrong. You have to learn!
|
||||
|
||||
## Usage
|
||||
This application has no dependencies. Instead of cloning this git, you can just do wget or copy the raw source code of [rtutor.py](rtutor.py).
|
||||
```
|
||||
python3 rtutor.py
|
||||
```
|
||||
but since it's executable:
|
||||
```
|
||||
./rtutor.py
|
||||
```
|
||||
will also work.
|
308
rtutor.py
Executable file
308
rtutor.py
Executable file
@ -0,0 +1,308 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# RETOOR
|
||||
|
||||
import sys
|
||||
import termios
|
||||
import tty
|
||||
import random
|
||||
import time
|
||||
import select
|
||||
|
||||
key_mapping = {
|
||||
"[A": "up",
|
||||
"[B": "down",
|
||||
"[C": "right",
|
||||
"[D": "left",
|
||||
"2A": "shift+up",
|
||||
"2B": "shift+down",
|
||||
"2C": "shift+right",
|
||||
"2D": "shift+left",
|
||||
"5A": "ctrl+up",
|
||||
"5B": "ctrl+down",
|
||||
"5C": "ctrl+right",
|
||||
"5D": "ctrl+left",
|
||||
"\x17": "C-w",
|
||||
"\x0f": "C-o",
|
||||
"\x03": "C-c",
|
||||
"\x07": "C-g",
|
||||
}
|
||||
|
||||
|
||||
def get_key(key_previous=None):
|
||||
fd = sys.stdin.fileno()
|
||||
old_settings = termios.tcgetattr(fd)
|
||||
special_char = "\x1b"
|
||||
if key_previous is None:
|
||||
key_previous = special_char
|
||||
try:
|
||||
tty.setraw(fd)
|
||||
key = sys.stdin.read(1)
|
||||
if key in key_mapping:
|
||||
return key_mapping[key]
|
||||
if key == "[":
|
||||
key += sys.stdin.read(1)
|
||||
if key in key_mapping:
|
||||
return key_mapping.get(key, key)
|
||||
if key[-1] == "1": # shift plus special key
|
||||
if sys.stdin.read(1) == ";": # ;followed by key
|
||||
key = sys.stdin.read(2)
|
||||
return key_mapping.get(key, key)
|
||||
if key == special_char:
|
||||
time.sleep(0.1)
|
||||
if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
|
||||
key += sys.stdin.read(2)
|
||||
key = key_mapping.get(key, key)
|
||||
|
||||
finally:
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
|
||||
return key
|
||||
|
||||
|
||||
def clear_terminal():
|
||||
sys.stdout.write("\033[2J")
|
||||
# Move cursor
|
||||
sys.stdout.write("\033[H")
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
class Randoms:
|
||||
|
||||
input_choices = list("abcdefghijklmnopqrstuvwxyz")
|
||||
word_choices = word_list = [
|
||||
"apple",
|
||||
"banana",
|
||||
"cherry",
|
||||
"date",
|
||||
"elderberry",
|
||||
"fig",
|
||||
"grape",
|
||||
"honeydew",
|
||||
"kiwi",
|
||||
"lemon",
|
||||
"mango",
|
||||
"nectarine",
|
||||
"orange",
|
||||
"pear",
|
||||
"quince",
|
||||
"raspberry",
|
||||
"strawberry",
|
||||
"tangerine",
|
||||
"ugli",
|
||||
"vaccine",
|
||||
"watermelon",
|
||||
"xigua",
|
||||
"yam",
|
||||
"zucchini",
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
self.replace = {}
|
||||
self.replace["<randc1>"] = random.choice(self.input_choices)
|
||||
self.replace["<randc2>"] = random.choice(self.input_choices)
|
||||
self.replace["<randc3>"] = random.choice(self.input_choices)
|
||||
self.replace["<rints1>"] = random.randint(2, 5)
|
||||
self.replace["<rints2>"] = random.randint(2, 5)
|
||||
self.replace["<rints3>"] = random.randint(2, 5)
|
||||
self.replace["<w1>"] = random.choice(self.word_choices)
|
||||
self.replace["<w2>"] = random.choice(self.word_choices)
|
||||
self.replace["<w3>"] = random.choice(self.word_choices)
|
||||
|
||||
def apply(self, task):
|
||||
task.question = task.base_question
|
||||
task.keyboard_input = task.base_keyboard_input
|
||||
for key, value in self.replace.items():
|
||||
task.question = task.question.replace(key, str(value))
|
||||
task.keyboard_input = task.keyboard_input.replace(
|
||||
key, ",".join(list(str(value)))
|
||||
)
|
||||
task.applied_random = (
|
||||
task.question != task.base_question
|
||||
or task.keyboard_input != task.base_keyboard_input
|
||||
)
|
||||
|
||||
|
||||
class Task:
|
||||
|
||||
questions_total = 0
|
||||
|
||||
def __init__(self, question, keyboard_input):
|
||||
Task.questions_total += 1
|
||||
self.question_number = Task.questions_total
|
||||
self.base_question = question
|
||||
self.base_keyboard_input = keyboard_input
|
||||
self.question = question
|
||||
self.keyboard_input = keyboard_input
|
||||
self.success = False
|
||||
self.tasks = []
|
||||
self.applied_random = False
|
||||
self.first_time_executed = True
|
||||
r = Randoms()
|
||||
r.apply(self)
|
||||
|
||||
def add_task(self, task):
|
||||
self.tasks.append(task)
|
||||
|
||||
def execute(self):
|
||||
if not self.first_time_executed:
|
||||
r = Randoms()
|
||||
r.apply(self)
|
||||
self.first_time_executed = False
|
||||
print("{}".format(self.question))
|
||||
index = 0
|
||||
mistake = False
|
||||
key_previous = None
|
||||
for expected in self.keyboard_input.split(","):
|
||||
key = get_key(key_previous)
|
||||
key_previous = key
|
||||
if key == "\x1b":
|
||||
key = get_key(key_previous)
|
||||
key_previous = key
|
||||
if key == "C-c":
|
||||
raise KeyboardInterrupt()
|
||||
if key == "\x17":
|
||||
print("CTRL+W")
|
||||
else:
|
||||
print(key, end="", flush=True)
|
||||
if expected == key:
|
||||
index += 1
|
||||
else:
|
||||
mistake = True
|
||||
|
||||
if mistake:
|
||||
print('\n"{}" is incorrect.'.format(repr(key)))
|
||||
print(
|
||||
'\nExpected input: "{}".'.format(
|
||||
self.keyboard_input.replace(",", "")
|
||||
)
|
||||
)
|
||||
print("\nPress any key to continue...")
|
||||
get_key(None)
|
||||
break
|
||||
if key == "q":
|
||||
break
|
||||
if not mistake:
|
||||
self.success = True
|
||||
print("")
|
||||
print(
|
||||
random.choice(
|
||||
["Great!", "Excelent!", "Awesome!", "Keep it up!", "Perfect!"]
|
||||
)
|
||||
)
|
||||
print("")
|
||||
self.success = all([task.execute() for task in self.tasks])
|
||||
time.sleep(0.40)
|
||||
return self.success
|
||||
|
||||
|
||||
tasks = [
|
||||
Task("Open terminal\n", ":,terminal,\r"),
|
||||
Task("Delete from the cursor to the end of the word.", "d,e"),
|
||||
Task("Delete from the cursor to the end of the line.", "d,$"),
|
||||
Task("Delete from the cursor to the beginning of the next word.", "d,w"),
|
||||
Task("Delete <rints1> lines using a numeric value.", "<rints1>,d,d"),
|
||||
Task("Move backward in the search results.", "N"),
|
||||
Task("Move forward in the search results.", "n"),
|
||||
Task("Move to line number <rints1>.", "<rints1>,G"),
|
||||
Task("Undo all changes on the current line.", "U"),
|
||||
Task("Move to the end of the word.", "e"),
|
||||
Task("Move to the beginning of the line.", "0"),
|
||||
Task("Search backward for <w1>.", ":,?,<w1>,\r"),
|
||||
Task("Search forward for <w1>.", ":,/,<w1>,\r"),
|
||||
Task("Display the current location in the status bar.", "C-g"),
|
||||
Task("Indent the selected text.", ">,>"),
|
||||
Task("De-indent the selected text.", "<,<"),
|
||||
Task("Save the document as <w1>.py.", ":,w, ,<w1>,.,p,y,\r"),
|
||||
Task("Replace the first occurrence of <w1> with <w2>.", ":,s,/,<w1>,/,<w2>,/,g"),
|
||||
Task(
|
||||
"Replace all occurrences of <w1> with <w2> in the entire file.",
|
||||
":,%,s,/,<w1>,/,<w2>,/,g",
|
||||
),
|
||||
Task(
|
||||
"Replace all occurrences of <w1> with <w2> in the entire file, with confirmation for each change.",
|
||||
":,%,s,/,<w1>,/,<w2>,/,g,c",
|
||||
),
|
||||
Task(
|
||||
"Select the next five characters and save them to a file.",
|
||||
"v,right,right,right,right,:,w",
|
||||
),
|
||||
Task("Exit Vim.", ":,q"),
|
||||
Task("Split the screen vertically.", ":,v,s,p,l,i,t,\r"),
|
||||
Task("Split the screen horizontally.", ":,s,p,l,i,t,\r"),
|
||||
Task("Merge the file <w1>.txt into the current file.", ":,r, ,<w1>,.,t,x,t,\r"),
|
||||
Task(
|
||||
"Move three words to the left without using numeric values.",
|
||||
"ctrl+left,ctrl+left,ctrl+left",
|
||||
),
|
||||
Task(
|
||||
"Move three words to the right without using numeric values.",
|
||||
"ctrl+right,ctrl+right,ctrl+right",
|
||||
),
|
||||
Task("Return to the previous position.", "C-o"),
|
||||
Task("Type <w1>.", "<w1>"),
|
||||
Task("Indent the current line and the two lines below.", "v,down,down,>,>"),
|
||||
Task("Enable case-sensitive search.", ":,s,e,t, ,n,o,i,c"),
|
||||
Task("Enable case-insensitive search.", ":,s,e,t, ,i,c"),
|
||||
Task("Copy the word under the cursor.", "y,w"),
|
||||
Task("Replace the text under the cursor with <w1>.", "R,<w1>"),
|
||||
Task("Insert text at the end of the line.", "A"),
|
||||
Task("Insert text after the cursor.", "a"),
|
||||
Task("Insert a new line below the current line.", "o"),
|
||||
Task("Insert a new line above the current line.", "O"),
|
||||
Task("Move to the beginning of the document.", "g,g"),
|
||||
Task("Move to the end of the line.", "$"),
|
||||
Task("Move to the end of the document.", "G"),
|
||||
Task(
|
||||
"Select the next four characters and copy them.", "v,right,right,right,right,y"
|
||||
),
|
||||
Task("Switch to the next window.", "C-w,C-w"),
|
||||
Task("Swap the position of the current window with another.", "C-w,r"),
|
||||
Task("Copy the current line.", "y,y"),
|
||||
Task("Copy all content.", "y"),
|
||||
Task("Paste the copied content.", "p"),
|
||||
Task("Replace the character under the cursor with '<randc1>'.", "r,<randc1>"),
|
||||
Task("Delete the character under the cursor.", "x"),
|
||||
Task("Delete the line under the cursor.", "d,d"),
|
||||
Task("Cut the current line.", "c,c"),
|
||||
Task("Type <w1>.", "<w1>"),
|
||||
]
|
||||
|
||||
|
||||
# shift select Move with>>
|
||||
def main():
|
||||
questions_correct = []
|
||||
questions_incorrect = []
|
||||
question_count = 0
|
||||
durations = []
|
||||
while tasks:
|
||||
clear_terminal()
|
||||
if not durations:
|
||||
avg_reaction_time = 0
|
||||
else:
|
||||
avg_reaction_time = sum(durations) / len(durations)
|
||||
num_correct = len(questions_correct)
|
||||
num_incorrect = len(questions_incorrect)
|
||||
avg_time = round(sum(durations) / len(durations), 2) if durations else 0
|
||||
print(
|
||||
"Correct: {}\tIncorrect: {}\tAvg reaction time: {}".format(
|
||||
num_correct, num_incorrect, avg_time
|
||||
)
|
||||
)
|
||||
print("")
|
||||
question_count += 1
|
||||
task = random.choice(tasks)
|
||||
print("{}. ".format(question_count), end="")
|
||||
time_start = time.time()
|
||||
if task.execute():
|
||||
tasks.remove(task)
|
||||
questions_correct.append(task)
|
||||
else:
|
||||
questions_incorrect.append(task)
|
||||
time_end = time.time()
|
||||
durations.append(time_end - time_start)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
Loading…
Reference in New Issue
Block a user