The source code.
This commit is contained in:
		
							parent
							
								
									5c8f307491
								
							
						
					
					
						commit
						28a558caff
					
				
							
								
								
									
										308
									
								
								rvimtutor.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										308
									
								
								rvimtutor.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