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