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