Advertisement
Guest User

Rtutor, the quick way to master vim!

a guest
Sep 9th, 2024
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.11 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. # RETOOR
  4.  
  5. import sys
  6. import termios
  7. import tty
  8. import random
  9. import time
  10. import select
  11.  
  12. key_mapping = {
  13.     "[A": "up",
  14.     "[B": "down",
  15.     "[C": "right",
  16.     "[D": "left",
  17.     "2A": "shift+up",
  18.     "2B": "shift+down",
  19.     "2C": "shift+right",
  20.     "2D": "shift+left",
  21.     "5A": "ctrl+up",
  22.     "5B": "ctrl+down",
  23.     "5C": "ctrl+right",
  24.     "5D": "ctrl+left",
  25.     "\x17": "C-w",
  26.     "\x0f": "C-o",
  27.     "\x03": "C-c",
  28.     "\x07": "C-g",
  29. }
  30.  
  31.  
  32. def get_key(key_previous=None):
  33.     fd = sys.stdin.fileno()
  34.     old_settings = termios.tcgetattr(fd)
  35.     special_char = "\x1b"
  36.     if key_previous is None:
  37.         key_previous = special_char
  38.     try:
  39.         tty.setraw(fd)
  40.         key = sys.stdin.read(1)
  41.         if key in key_mapping:
  42.             return key_mapping[key]
  43.         if key == "[":
  44.             key += sys.stdin.read(1)
  45.             if key in key_mapping:
  46.                 return key_mapping.get(key, key)
  47.             if key[-1] == "1":  # shift plus special key
  48.                 if sys.stdin.read(1) == ";":  # ;followed by key
  49.                     key = sys.stdin.read(2)
  50.                     return key_mapping.get(key, key)
  51.                 if key == special_char:
  52.                     time.sleep(0.1)
  53.                     if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
  54.                         key += sys.stdin.read(2)
  55.                     key = key_mapping.get(key, key)
  56.  
  57.     finally:
  58.         termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
  59.  
  60.     return key
  61.  
  62.  
  63. def clear_terminal():
  64.     sys.stdout.write("\033[2J")
  65.     # Move cursor
  66.     sys.stdout.write("\033[H")
  67.     sys.stdout.flush()
  68.  
  69.  
  70. class Randoms:
  71.    
  72.     input_choices = list("abcdefghijklmnopqrstuvwxyz")
  73.     word_choices = word_list = [
  74.         "apple",
  75.         "banana",
  76.         "cherry",
  77.         "date",
  78.         "elderberry",
  79.         "fig",
  80.         "grape",
  81.         "honeydew",
  82.         "kiwi",
  83.         "lemon",
  84.         "mango",
  85.         "nectarine",
  86.         "orange",
  87.         "pear",
  88.         "quince",
  89.         "raspberry",
  90.         "strawberry",
  91.         "tangerine",
  92.         "ugli",
  93.         "vaccine",
  94.         "watermelon",
  95.         "xigua",
  96.         "yam",
  97.         "zucchini",
  98.     ]
  99.  
  100.     def __init__(self):
  101.         self.replace = {}
  102.         self.replace["<randc1>"] = random.choice(self.input_choices)
  103.         self.replace["<randc2>"] = random.choice(self.input_choices)
  104.         self.replace["<randc3>"] = random.choice(self.input_choices)
  105.         self.replace["<rints1>"] = random.randint(2, 5)
  106.         self.replace["<rints2>"] = random.randint(2, 5)
  107.         self.replace["<rints3>"] = random.randint(2, 5)
  108.         self.replace["<w1>"] = random.choice(self.word_choices)
  109.         self.replace["<w2>"] = random.choice(self.word_choices)
  110.         self.replace["<w3>"] = random.choice(self.word_choices)
  111.  
  112.     def apply(self, task):
  113.         task.question = task.base_question
  114.         task.keyboard_input = task.base_keyboard_input
  115.         for key, value in self.replace.items():
  116.             task.question = task.question.replace(key, str(value))
  117.             task.keyboard_input = task.keyboard_input.replace(
  118.                 key, ",".join(list(str(value)))
  119.             )
  120.         task.applied_random = (
  121.             task.question != task.base_question
  122.             or task.keyboard_input != task.base_keyboard_input
  123.         )
  124.  
  125.  
  126. class Task:
  127.  
  128.     questions_total = 0
  129.  
  130.     def __init__(self, question, keyboard_input):
  131.         Task.questions_total += 1
  132.         self.question_number = Task.questions_total
  133.         self.base_question = question
  134.         self.base_keyboard_input = keyboard_input
  135.         self.question = question
  136.         self.keyboard_input = keyboard_input
  137.         self.success = False
  138.         self.tasks = []
  139.         self.applied_random = False
  140.         self.first_time_executed = True
  141.         r = Randoms()
  142.         r.apply(self)
  143.  
  144.     def add_task(self, task):
  145.         self.tasks.append(task)
  146.  
  147.     def execute(self):
  148.         if not self.first_time_executed:
  149.             r = Randoms()
  150.             r.apply(self)
  151.         self.first_time_executed = False
  152.         print("{}".format(self.question))
  153.         index = 0
  154.         mistake = False
  155.         key_previous = None
  156.         for expected in self.keyboard_input.split(","):
  157.             key = get_key(key_previous)
  158.             key_previous = key
  159.             if key == "\x1b":
  160.                 key = get_key(key_previous)
  161.                 key_previous = key
  162.             if key == "C-c":
  163.                 raise KeyboardInterrupt()
  164.             if key == "\x17":
  165.                 print("CTRL+W")
  166.             else:
  167.                 print(key, end="", flush=True)
  168.             if expected == key:
  169.                 index += 1
  170.             else:
  171.                 mistake = True
  172.  
  173.             if mistake:
  174.                 print('\n"{}" is incorrect.'.format(repr(key)))
  175.                 print(
  176.                     '\nExpected input: "{}".'.format(
  177.                         self.keyboard_input.replace(",", "")
  178.                     )
  179.                 )
  180.                 print("\nPress any key to continue...")
  181.                 get_key(None)
  182.                 break
  183.             if key == "q":
  184.                 break
  185.         if not mistake:
  186.             self.success = True
  187.             print("")
  188.             print(
  189.                 random.choice(
  190.                     ["Great!", "Excelent!", "Awesome!", "Keep it up!", "Perfect!"]
  191.                 )
  192.             )
  193.             print("")
  194.             self.success = all([task.execute() for task in self.tasks])
  195.             time.sleep(0.40)
  196.         return self.success
  197.  
  198.  
  199. tasks = [
  200.     Task("Open terminal\n", ":,terminal,\r"),
  201.     Task("Delete from the cursor to the end of the word.", "d,e"),
  202.     Task("Delete from the cursor to the end of the line.", "d,$"),
  203.     Task("Delete from the cursor to the beginning of the next word.", "d,w"),
  204.     Task("Delete <rints1> lines using a numeric value.", "<rints1>,d,d"),
  205.     Task("Move backward in the search results.", "N"),
  206.     Task("Move forward in the search results.", "n"),
  207.     Task("Move to line number <rints1>.", "<rints1>,G"),
  208.     Task("Undo all changes on the current line.", "U"),
  209.     Task("Move to the end of the word.", "e"),
  210.     Task("Move to the beginning of the line.", "0"),
  211.     Task("Search backward for <w1>.", ":,?,<w1>,\r"),
  212.     Task("Search forward for <w1>.", ":,/,<w1>,\r"),
  213.     Task("Display the current location in the status bar.", "C-g"),
  214.     Task("Indent the selected text.", ">,>"),
  215.     Task("De-indent the selected text.", "<,<"),
  216.     Task("Save the document as <w1>.py.", ":,w, ,<w1>,.,p,y,\r"),
  217.     Task("Replace the first occurrence of <w1> with <w2>.", ":,s,/,<w1>,/,<w2>,/,g"),
  218.     Task(
  219.         "Replace all occurrences of <w1> with <w2> in the entire file.",
  220.         ":,%,s,/,<w1>,/,<w2>,/,g",
  221.     ),
  222.     Task(
  223.         "Replace all occurrences of <w1> with <w2> in the entire file, with confirmation for each change.",
  224.         ":,%,s,/,<w1>,/,<w2>,/,g,c",
  225.     ),
  226.     Task(
  227.         "Select the next five characters and save them to a file.",
  228.         "v,right,right,right,right,:,w",
  229.     ),
  230.     Task("Exit Vim.", ":,q"),
  231.     Task("Split the screen vertically.", ":,v,s,p,l,i,t,\r"),
  232.     Task("Split the screen horizontally.", ":,s,p,l,i,t,\r"),
  233.     Task("Merge the file <w1>.txt into the current file.", ":,r, ,<w1>,.,t,x,t,\r"),
  234.     Task(
  235.         "Move three words to the left without using numeric values.",
  236.         "ctrl+left,ctrl+left,ctrl+left",
  237.     ),
  238.     Task(
  239.         "Move three words to the right without using numeric values.",
  240.         "ctrl+right,ctrl+right,ctrl+right",
  241.     ),
  242.     Task("Return to the previous position.", "C-o"),
  243.     Task("Type <w1>.", "<w1>"),
  244.     Task("Indent the current line and the two lines below.", "v,down,down,>,>"),
  245.     Task("Enable case-sensitive search.", ":,s,e,t, ,n,o,i,c"),
  246.     Task("Enable case-insensitive search.", ":,s,e,t, ,i,c"),
  247.     Task("Copy the word under the cursor.", "y,w"),
  248.     Task("Replace the text under the cursor with <w1>.", "R,<w1>"),
  249.     Task("Insert text at the end of the line.", "A"),
  250.     Task("Insert text after the cursor.", "a"),
  251.     Task("Insert a new line below the current line.", "o"),
  252.     Task("Insert a new line above the current line.", "O"),
  253.     Task("Move to the beginning of the document.", "g,g"),
  254.     Task("Move to the end of the line.", "$"),
  255.     Task("Move to the end of the document.", "G"),
  256.     Task(
  257.         "Select the next four characters and copy them.", "v,right,right,right,right,y"
  258.     ),
  259.     Task("Switch to the next window.", "C-w,C-w"),
  260.     Task("Swap the position of the current window with another.", "C-w,r"),
  261.     Task("Copy the current line.", "y,y"),
  262.     Task("Copy all content.", "y"),
  263.     Task("Paste the copied content.", "p"),
  264.     Task("Replace the character under the cursor with '<randc1>'.", "r,<randc1>"),
  265.     Task("Delete the character under the cursor.", "x"),
  266.     Task("Delete the line under the cursor.", "d,d"),
  267.     Task("Cut the current line.", "c,c"),
  268.     Task("Type <w1>.", "<w1>"),
  269. ]
  270.  
  271.  
  272. # shift select Move with>>
  273. def main():
  274.     questions_correct = []
  275.     questions_incorrect = []
  276.     question_count = 0
  277.     durations = []
  278.     while tasks:
  279.         clear_terminal()
  280.         if not durations:
  281.             avg_reaction_time = 0
  282.         else:
  283.             avg_reaction_time = sum(durations) / len(durations)
  284.         num_correct = len(questions_correct)
  285.         num_incorrect = len(questions_incorrect)
  286.         avg_time = round(sum(durations) / len(durations), 2) if durations else 0
  287.         print(
  288.             "Correct: {}\tIncorrect: {}\tAvg reaction time: {}".format(
  289.                 num_correct, num_incorrect, avg_time
  290.             )
  291.         )
  292.         print("")
  293.         question_count += 1
  294.         task = random.choice(tasks)
  295.         print("{}. ".format(question_count), end="")
  296.         time_start = time.time()
  297.         if task.execute():
  298.             tasks.remove(task)
  299.             questions_correct.append(task)
  300.         else:
  301.             questions_incorrect.append(task)
  302.         time_end = time.time()
  303.         durations.append(time_end - time_start)
  304.  
  305.  
  306. if __name__ == "__main__":
  307.     main()
  308.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement