diff --git a/README.md b/README.md index 7f7fa1c..97d6ce5 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,18 @@ -# Learn irregular English verbs in Emacs -## learning-irregular-verbs-in-English.el +# Lirve: Learn irregular English verbs in Emacs + +Lirve helps you learn irregular verbs using the spaced repetition technique. In other words: Lirve remember your mistakes and repeat the challenge in the future. ![Demo](demo.png) ## Install -Add in your `init.el`. +You need to have `straight` installed. + +Then, add it to your `init.el`. ```elisp -(use-package learning-irregular-verbs-in-English - :straight (:host github :repo "tanrax/learning-irregular-verbs-in-English.el" :files ("learning-irregular-verbs-in-English.el")) +(use-package learning-irregular-verbs-in-english + :straight (:host github :repo "tanrax/learning-irregular-verbs-in-English.el" :files ("lirve-verbs.el" "lirve.el")) :ensure t) ``` @@ -19,16 +22,16 @@ Shows the translation of the verb when resolving or failing. ![Demo translation](demo-translation.png) -Only available in Spanish. +Only available in Spanish (at the moment). ```elisp -(setq learning-irregular-verbs-in-English--show-translation 'es) +(setq lirve--show-translation 'es) ``` ## Usage ``` -M-x learning-irregular-verbs-in-English +M-x learning-irregular-verbs-in-english ``` ## Controls @@ -38,4 +41,19 @@ M-x learning-irregular-verbs-in-English | `TAB` | Move to the next field | | `S-TAB` | Move to the previous field | | `RET` | Click on the button | -| `q` | Quit | + +## Collaborate + +If you want to add more languages, make a PR with the translations in `lirve-verbs.el`. + +For example, the verb `beat` in Italian and Spanish: + +```ellisp +( + (infinitive . "beat") + (simple-past . "beat") + (past-participle . "beaten") + (translations + (es . "golpear") + (it . "colpo"))) +``` diff --git a/learning-irregular-verbs-in-English.el b/learning-irregular-verbs-in-English.el deleted file mode 100644 index e18846d..0000000 --- a/learning-irregular-verbs-in-English.el +++ /dev/null @@ -1,321 +0,0 @@ -;;; learning-irregular-verbs-in-English.el --- Application to learn and review irregular verbs in English. -*- lexical-binding: t; -;; -;; Copyright © 2024 Andros Fenollosa -;; Authors: Andros Fenollosa -;; URL: https://github.com/tanrax/learning-irregular-verbs-in-English.el -;; Version: 1.1.0 -;; SPDX-License-Identifier: GPL-3.0-or-later - -;;; Commentary: -;; Application to learn and review irregular verbs in English. - -;;; Code: - -;; Imports -(load-file "verbs.el") -(require 'verbs) -(require 'widget) -(eval-when-compile - (require 'wid-edit)) - -;; Variables -(defvar lire--verbs-shuffle '()) -(defvar lire--file-name-unresolved "unresolved.txt") -(defvar lire--verbs-unresolved '()) -(defvar lire--buffer-name "*Learning irregular verbs in English*") -(defvar lire--state 1) ;; 1: lire--start, 2: playing (before first check), 3: win (show success layout) -(defvar lire--verb-to-learn-infinitive nil) -(defvar lire--verb-to-learn-simple-past nil) -(defvar lire--verb-to-learn-past-participle nil) -(defvar lire--translation "") -(defvar lire--emoji-valid "✅") -(defvar lire--emoji-error "👎") -(defvar lire--widget-title nil) -(defvar lire--text-title " 🧑‍🎓 Learning irregular verbs in English 🇬🇧") -(defvar lire--widget-item-verb nil) -(defvar lire--widget-field-simple-past nil) -(defvar lire--widget-label-check-simple-past nil) -(defvar lire--widget-field-past-participle nil) -(defvar lire--widget-label-check-past-participle nil) -(defvar lire--text-button-check "Check") -(defvar lire--widget-button-check nil) -(defvar lire--widget-item-space-before-check nil) -(defvar lire--text-button-show-solution "Don't know") -(defvar lire--widget-button-show-solution nil) -(defvar lire--widget-message-success nil) -(defvar lire--widget-item-space-before-success nil) -(defvar lire--text-success "Nice!") -(defvar lire--text-fail "Next time you will do better") -(defvar lire--is-resolve t) -(defvar lire--widget-item-space-after-success nil) -(defvar lire--widget-button-quit nil) -(defvar lire--text-button-quit "Quit") -(defvar lire--widget-item-space-between-buttons nil) -(defvar lire--widget-button-lire--replay nil) -(defvar lire--text-button-lire--replay "New challenge") - -;; Functions - -(defun lire--shuffle (originalList &optional shuffledList) - "Applies the Fisher-Yates shuffle algorithm to a list. -Example: (lire--shuffle '(1 2 3 4 5)) => (3 1 5 2 4)" - (if (null originalList) - ;; End recursion, return the shuffled list - shuffledList - ;; Otherwise, continue with the logic - (let* ((randomPosition (random (length originalList))) - (randomElement (nth randomPosition originalList)) - ;; Create a new original list without the randomly selected element - (originalListWithoutRandomElement (append (cl-subseq originalList 0 randomPosition) (nthcdr (1+ randomPosition) originalList))) - ;; Create a new shuffled list with the selected element at the beginning - (newShuffledList (if (null shuffledList) (list randomElement) (cons randomElement shuffledList)))) - ;; Recursively call the shuffle function with the new original list and the new shuffled list - (lire--shuffle originalListWithoutRandomElement newShuffledList)))) - -(defun lire--kill-app () - "Kill the application." - (kill-buffer lire--buffer-name)) - -(defun lire--save-verb-unresolved (infinitive) - "Save the verb unresolved to lire--verbs-unresolved and to the file." - (setq lire--verbs-unresolved (cons infinitive lire--verbs-unresolved)) - (with-temp-file (concat (file-name-directory user-init-file) lire--file-name-unresolved) - (prin1 lire--verbs-unresolved (current-buffer)))) - -(defun lire--value-field-simple-past () - "Get the value of the simple past." - (if (not (eq lire--widget-field-simple-past nil)) (widget-value lire--widget-field-simple-past) "")) - -(defun lire--value-field-past-participle () - "Get the value of the past participle." - (if (not (eq lire--widget-field-past-participle nil)) (widget-value lire--widget-field-past-participle) "")) - -(defun lire--set-verb-to-learn () - "Set the verb to learn." - (when (null lire--verbs-shuffle) - (setq lire--verbs-shuffle (lire--shuffle lire--verbs))) - (let ((verb-to-learn (car lire--verbs-shuffle))) - (setq lire--verb-to-learn-infinitive (alist-get 'infinitive verb-to-learn)) - (setq lire--verb-to-learn-simple-past (alist-get 'simple-past verb-to-learn)) - (setq lire--verb-to-learn-past-participle (alist-get 'past-participle verb-to-learn)) - (when (not (null (boundp 'learning-irregular-verbs-in-English--show-translation))) (setq lire--translation (alist-get learning-irregular-verbs-in-English--show-translation (alist-get 'translations verb-to-learn)))) - ;; Remove the verb from the list - (setq lire--verbs-shuffle (cdr lire--verbs-shuffle)))) - -(defun lire--format-value-infinitive () - "Format the value of the infinitive." - (format "Infinitive ➡️ %s" lire--verb-to-learn-infinitive)) - -(defun lire--format-check-simple-past () - "Format the value of the simple past." - (if (eq lire--state 1) - "" - (format " %s" (if - (and - (string= (lire--value-field-simple-past) lire--verb-to-learn-simple-past) - (not (string= (lire--value-field-simple-past) ""))) - lire--emoji-valid lire--emoji-error)))) - -(defun lire--format-check-past-participle () - "Format the value of the past participle." - (if (eq lire--state 1) - "" - (format " %s" (if - (and - (string= (lire--value-field-past-participle) lire--verb-to-learn-past-participle) - (not (string= (lire--value-field-past-participle) ""))) - lire--emoji-valid lire--emoji-error)))) - -(defun lire--show-translation () - "Show translation if learning-irregular-verbs-in-English--show-translation is t" - (when (not (null lire--translation)) - (widget-value-set lire--widget-item-verb (concat (lire--format-value-infinitive) " 🇪🇸 " lire--translation)))) - -(defun lire--toggle-layout-finish () - "Toggle the layout to success." - (if (eq lire--state 3) - (progn - ;; Show translate - (lire--show-translation) - ;; Cursor to end - (goto-char (point-max)) - ;; Remove check button - (widget-delete lire--widget-button-check) - (setq lire--widget-button-check nil) - ;; Remove space after check button - (widget-delete lire--widget-item-space-before-check) - (setq lire--widget-item-space-before-check nil) - ;; Remove show solution button - (widget-delete lire--widget-button-show-solution) - (setq lire--widget-button-show-solution nil) - ;; Text success - (setq lire--widget-item-space-before-success (widget-create 'item - "")) - (setq lire--widget-message-success (widget-create 'item - (if lire--is-resolve lire--text-success lire--text-fail))) - (setq lire--widget-item-space-after-success (widget-create 'item - "\n")) - ;; Lire--Replay button - (setq lire--widget-button-lire--replay (widget-create 'push-button - :size 20 - :notify (lambda (&rest ignore) - (lire--replay)) - lire--text-button-lire--replay)) - ;; Space - (setq lire--widget-item-space-between-buttons (widget-create 'item - "\n")) - ;; Quit button - (setq lire--widget-button-quit (widget-create 'push-button - :size 20 - :notify (lambda (&rest ignore) - (lire--kill-app)) - lire--text-button-quit)) - (widget-backward 2) - ) - (progn - (when (not (eq lire--widget-item-space-before-success nil)) (widget-delete lire--widget-item-space-before-success)) - (when (not (eq lire--widget-message-success nil)) (widget-delete lire--widget-message-success)) - (when (not (eq lire--widget-item-space-after-success nil)) (widget-delete lire--widget-item-space-after-success)) - (when (not (eq lire--widget-button-lire--replay nil)) (widget-delete lire--widget-button-lire--replay)) - (when (not (eq lire--widget-item-space-between-buttons nil)) (widget-delete lire--widget-item-space-between-buttons)) - (when (not (eq lire--widget-button-quit nil)) (widget-delete lire--widget-button-quit)) - ))) - -(defun lire--make-button-check () - "Make the button check." - (setq lire--widget-button-check (widget-create 'push-button - :notify (lambda (&rest ignore) - (lire--update)) - lire--text-button-check))) -(defun lire--make-space-after-check () - "Add space between Button check and Button show solution" - (setq lire--widget-item-space-before-check (widget-create 'item "\n"))) - - -(defun lire--show-solutions () - "Show solutions" - (widget-value-set lire--widget-field-simple-past lire--verb-to-learn-simple-past) - (widget-value-set lire--widget-field-past-participle lire--verb-to-learn-past-participle) - (lire--save-verb-unresolved lire--verb-to-learn-infinitive)) - -(defun lire--make-button-show-solution () - "Make the button show solution." - (setq lire--widget-button-show-solution (widget-create 'push-button - :notify (lambda (&rest ignore) - (lire--show-solutions) - (lire--update)) - lire--text-button-show-solution))) - - -(defun lire--start () - "Start challenge." - ;; Set the lire--state - (setq lire--state 1) - ;; Get a new verb - (lire--set-verb-to-learn) - ;; Show the verb in infinitive - (widget-value-set lire--widget-item-verb (lire--format-value-infinitive)) - ;; Reset button check - (when (eq lire--widget-button-check nil) (lire--make-button-check)) - ;; Reset space after check - (when (eq lire--widget-item-space-before-check nil) (lire--make-space-after-check)) - ;; Reset button show solution - (when (eq lire--widget-button-show-solution nil) (lire--make-button-show-solution)) - ;; Clear the fields - (widget-value-set lire--widget-field-simple-past "") - (widget-value-set lire--widget-label-check-simple-past "") - (widget-value-set lire--widget-field-past-participle "") - (widget-value-set lire--widget-label-check-past-participle "") - ;; Update labels - (lire--update)) - -(defun lire--replay () - "Replay the challenge." - (interactive) - (lire--start) - (widget-backward 1)) - -(defun lire--update () - "Update state and show temps layouts." - (interactive) - ;; Is playing? - (when (and (eq lire--state 1) - (or - (not (string= (lire--value-field-simple-past) "")) - (not (string= (lire--value-field-past-participle) ""))) - ) - (setq lire--state 2)) - ;; Check the answers - (when (eq lire--state 2) - ;; Is win? - (when (and - (string= (lire--value-field-simple-past) lire--verb-to-learn-simple-past) - (string= (lire--value-field-past-participle) lire--verb-to-learn-past-participle)) - ;; Set the lire--state - (setq lire--state 3)) - ;; Update the check labels - (widget-value-set lire--widget-label-check-simple-past (lire--format-check-simple-past)) - (widget-value-set lire--widget-label-check-past-participle (lire--format-check-past-participle))) - ;; Update the success layout if needed - (lire--toggle-layout-finish) - (setq lire--is-resolve t)) - -(defun lire--main-layout () - "Make widgets for the main layout." - ;; Create the buffer - (switch-to-buffer lire--buffer-name) - ;; Clear the buffer - (kill-all-local-variables) - (let ((inhibit-read-only t)) - (erase-buffer)) - (remove-overlays) - ;; Create the widgets - ;; Title - (insert (propertize (format "\n%s\n\n" lire--text-title) 'face '(:height 1.2 :weight bold))) - ;; Verb in infinitive - (setq lire--widget-item-verb (widget-create 'item - :value "")) - ;; Separator - (insert "\nSimple past ➡️ ") - ;; Simple past - (setq lire--widget-field-simple-past (widget-create 'editable-field - :size 8 - :help-echo "Type a Simple past" - )) - ;; Label check - (insert " ") - (setq lire--widget-label-check-simple-past (widget-create 'item - (lire--format-check-simple-past))) - ;; Separator - (insert "\nPast participle ➡️ ") - ;; Past participle - (setq lire--widget-field-past-participle (widget-create 'editable-field - :size 8 - :help-echo "Type a Past participle")) - ;; Label check - (insert " ") - (setq lire--widget-label-check-past-participle (widget-create 'item - (lire--format-check-past-participle))) - ;; Separator - (insert "\n") - ;; Check button - (lire--make-button-check) - ;; Separator - (lire--make-space-after-check) - ;; Show solution button - (lire--make-button-show-solution) - ;; Display the buffer - (use-local-map widget-keymap) - (widget-setup)) - -;; Init -(defun learning-irregular-verbs-in-English () - "Application to learn and review irregular verbs in English." - (interactive) - (lire--main-layout) - (lire--start) - (widget-backward 4)) - -(provide 'learning-irregular-verbs-in-English) - -;;; learning-irregular-verbs-in-English.el ends here diff --git a/lirve-verbs.el b/lirve-verbs.el new file mode 100644 index 0000000..b0078f1 --- /dev/null +++ b/lirve-verbs.el @@ -0,0 +1,617 @@ +;;; lirve-verbs.el --- Verb list for learning irregular verbs in English -*- lexical-binding: t; -*- +;; +;; Copyright © 2024 Andros Fenollosa +;; Authors: Andros Fenollosa +;; URL: https://github.com/tanrax/learning-irregular-verbs-in-English.el +;; Version: 1.2.0 +;; SPDX-License-Identifier: GPL-3.0-or-later + +;;; Commentary: +;; This file contains a list of irregular verbs in English, with their + +;;; Code: + +(defvar lirve--verbs '( + ( + (infinitive . "beat") + (simple-past . "beat") + (past-participle . "beaten") + (translations + (es . "golpear"))) + ( + (infinitive . "become") + (simple-past . "became") + (past-participle . "become") + (translations + (es . "llegar a ser, convertirse en"))) + ( + (infinitive . "begin") + (simple-past . "began") + (past-participle . "begun") + (translations + (es . "empezar"))) + ( + (infinitive . "bend") + (simple-past . "bent") + (past-participle . "bent") + (translations + (es . "doblar"))) + ( + (infinitive . "bet") + (simple-past . "bet") + (past-participle . "bet") + (translations + (es . "apostar"))) + ( + (infinitive . "bite") + (simple-past . "bit") + (past-participle . "bitten") + (translations + (es . "morder"))) + ( + (infinitive . "bleed") + (simple-past . "bled") + (past-participle . "bled") + (translations + (es . "sangrar"))) + ( + (infinitive . "blow") + (simple-past . "blew") + (past-participle . "blown") + (translations + (es . "soplar"))) + ( + (infinitive . "break") + (simple-past . "broke") + (past-participle . "broken") + (translations + (es . "romper"))) + ( + (infinitive . "bring") + (simple-past . "brought") + (past-participle . "brought") + (translations + (es . "traer"))) + ( + (infinitive . "build") + (simple-past . "built") + (past-participle . "built") + (translations + (es . "construir"))) + ( + (infinitive . "burn") + (simple-past . "burnt") + (past-participle . "burnt") + (translations + (es . "quemar"))) + ( + (infinitive . "buy") + (simple-past . "bought") + (past-participle . "bought") + (translations + (es . "comprar"))) + ( + (infinitive . "catch") + (simple-past . "caught") + (past-participle . "caught") + (translations + (es . "coger"))) + ( + (infinitive . "choose") + (simple-past . "chose") + (past-participle . "chosen") + (translations + (es . "escoger"))) + ( + (infinitive . "come") + (simple-past . "came") + (past-participle . "come") + (translations + (es . "venir"))) + ( + (infinitive . "cost") + (simple-past . "cost") + (past-participle . "cost") + (translations + (es . "costar"))) + ( + (infinitive . "cut") + (simple-past . "cut") + (past-participle . "cut") + (translations + (es . "cortar"))) + ( + (infinitive . "dig") + (simple-past . "dug") + (past-participle . "dug") + (translations + (es . "cavar"))) + ( + (infinitive . "do") + (simple-past . "did") + (past-participle . "done") + (translations + (es . "hacer"))) + ( + (infinitive . "draw") + (simple-past . "drew") + (past-participle . "drawn") + (translations + (es . '"(dibujar, trazar"))) + ( + (infinitive . "dream") + (simple-past . "dreamt") + (past-participle . "dreamt") + (translations + (es . "soñar"))) + ( + (infinitive . "drink") + (simple-past . "drank") + (past-participle . "drunk") + (translations + (es . "beber"))) + ( + (infinitive . "drive") + (simple-past . "drove") + (past-participle . "driven") + (translations + (es . "conducir"))) + ( + (infinitive . "eat") + (simple-past . "ate") + (past-participle . "eaten") + (translations + (es . "comer"))) + ( + (infinitive . "fall") + (simple-past . "fell") + (past-participle . "fallen") + (translations + (es . "caer(se)"))) + ( + (infinitive . "feed") + (simple-past . "fed") + (past-participle . "fed") + (translations + (es . "dar de comer, alimentar"))) + ( + (infinitive . "feel") + (simple-past . "felt") + (past-participle . "felt") + (translations + (es . "sentir"))) + ( + (infinitive . "fight") + (simple-past . "fought") + (past-participle . "fought") + (translations + (es . "pelear, luchar"))) + ( + (infinitive . "find") + (simple-past . "found") + (past-participle . "found") + (translations + (es . "encontrar"))) + ( + (infinitive . "fly") + (simple-past . "flew") + (past-participle . "flown") + (translations + (es . "volar"))) + ( + (infinitive . "forget") + (simple-past . "forgot") + (past-participle . "forgotten") + (translations + (es . "olvidar"))) + ( + (infinitive . "forgive") + (simple-past . "forgave") + (past-participle . "forgiven") + (translations + (es . "perdonar"))) + ( + (infinitive . "freeze") + (simple-past . "froze") + (past-participle . "frozen") + (translations + (es . "helar, congelar"))) + ( + (infinitive . "get") + (simple-past . "got") + (past-participle . "got") + (translations + (es . "conseguir"))) + ( + (infinitive . "give") + (simple-past . "gave") + (past-participle . "given") + (translations + (es . "dar"))) + ( + (infinitive . "go") + (simple-past . "went") + (past-participle . "gone") + (translations + (es . "ir"))) + ( + (infinitive . "grow") + (simple-past . "grew") + (past-participle . "grown") + (translations + (es . "cultivar, crecer"))) + ( + (infinitive . "hang") + (simple-past . "hung") + (past-participle . "hung") + (translations + (es . "colgar"))) + ( + (infinitive . "have") + (simple-past . "had") + (past-participle . "had") + (translations + (es . "tener"))) + ( + (infinitive . "hear") + (simple-past . "heard") + (past-participle . "heard") + (translations + (es . "oír"))) + ( + (infinitive . "hide") + (simple-past . "hid") + (past-participle . "hidden") + (translations + (es . "esconder"))) + ( + (infinitive . "hit") + (simple-past . "hit") + (past-participle . "hit") + (translations + (es . "golpear, pegar"))) + ( + (infinitive . "hold") + (simple-past . "held") + (past-participle . "held") + (translations + (es . "sostener"))) + ( + (infinitive . "hurt") + (simple-past . "hurt") + (past-participle . "hurt") + (translations + (es . "herir"))) + ( + (infinitive . "keep") + (simple-past . "kept") + (past-participle . "kept") + (translations + (es . "mantener"))) + ( + (infinitive . "know") + (simple-past . "knew") + (past-participle . "known") + (translations + (es . "saber, conocer"))) + ( + (infinitive . "lay") + (simple-past . "laid") + (past-participle . "laid") + (translations + (es . "poner (la mesa), colocar"))) + ( + (infinitive . "lead") + (simple-past . "led") + (past-participle . "led") + (translations + (es . "dirigir"))) + ( + (infinitive . "learn") + (simple-past . "learnt") + (past-participle . "learnt") + (translations + (es . "aprender"))) + ( + (infinitive . "leave") + (simple-past . "left") + (past-participle . "left") + (translations + (es . "dejar, marcharse(se)"))) + ( + (infinitive . "lend") + (simple-past . "lent") + (past-participle . "lent") + (translations + (es . "prestar"))) + ( + (infinitive . "let") + (simple-past . "let") + (past-participle . "let") + (translations + (es . "dejar, permitir"))) + ( + (infinitive . "lie") + (simple-past . "lay") + (past-participle . "lain") + (translations + (es . "tumbarse"))) + ( + (infinitive . "light") + (simple-past . "lit") + (past-participle . "lit") + (translations + (es . "iluminar"))) + ( + (infinitive . "lose") + (simple-past . "lost") + (past-participle . "lost") + (translations + (es . "perder"))) + ( + (infinitive . "make") + (simple-past . "made") + (past-participle . "made") + (translations + (es . "hacer"))) + ( + (infinitive . "mean") + (simple-past . "meant") + (past-participle . "meant") + (translations + (es . "significar, querer decir"))) + ( + (infinitive . "meet") + (simple-past . "met") + (past-participle . "met") + (translations + (es . "conocer"))) + ( + (infinitive . "pay") + (simple-past . "paid") + (past-participle . "paid") + (translations + (es . "pagar"))) + ( + (infinitive . "put") + (simple-past . "put") + (past-participle . "put") + (translations + (es . "poner"))) + ( + (infinitive . "read") + (simple-past . "read") + (past-participle . "read") + (translations + (es . "leer"))) + ( + (infinitive . "ride") + (simple-past . "rode") + (past-participle . "ridden") + (translations + (es . "montar"))) + ( + (infinitive . "ring") + (simple-past . "rang") + (past-participle . "rung") + (translations + (es . "sonar, llamar por teléfono"))) + ( + (infinitive . "rise") + (simple-past . "rose") + (past-participle . "risen") + (translations + (es . "levantarse"))) + ( + (infinitive . "run") + (simple-past . "ran") + (past-participle . "run") + (translations + (es . "correr"))) + ( + (infinitive . "say") + (simple-past . "said") + (past-participle . "said") + (translations + (es . "decir"))) + ( + (infinitive . "see") + (simple-past . "saw") + (past-participle . "seen") + (translations + (es . "ver"))) + ( + (infinitive . "sell") + (simple-past . "sold") + (past-participle . "sold") + (translations + (es . "vender"))) + ( + (infinitive . "send") + (simple-past . "sent") + (past-participle . "sent") + (translations + (es . "enviar"))) + ( + (infinitive . "set") + (simple-past . "set") + (past-participle . "set") + (translations + (es . "colocar, fijar, poner la mesa"))) + ( + (infinitive . "shake") + (simple-past . "shook") + (past-participle . "shaken") + (translations + (es . "agitar, sacudir"))) + ( + (infinitive . "shine") + (simple-past . "shone") + (past-participle . "shone") + (translations + (es . "brillar, sacar brillo"))) + ( + (infinitive . "shoot") + (simple-past . "shot") + (past-participle . "shot") + (translations + (es . "disparar"))) + ( + (infinitive . "show") + (simple-past . "showed") + (past-participle . "shown") + (translations + (es . "mostrar"))) + ( + (infinitive . "shut") + (simple-past . "shut") + (past-participle . "shut") + (translations + (es . "cerrar"))) + ( + (infinitive . "sing") + (simple-past . "sang") + (past-participle . "sung") + (translations + (es . "cantar"))) + ( + (infinitive . "sink") + (simple-past . "sank") + (past-participle . "sunk") + (translations + (es . "hundir(se)"))) + ( + (infinitive . "sit") + (simple-past . "sat") + (past-participle . "sat") + (translations + (es . "sentar(se)"))) + ( + (infinitive . "sleep") + (simple-past . "slept") + (past-participle . "slept") + (translations + (es . "dormir"))) + ( + (infinitive . "smell") + (simple-past . "smelt") + (past-participle . "smelt") + (translations + (es . "oler"))) + ( + (infinitive . "speak") + (simple-past . "spoke") + (past-participle . "spoken") + (translations + (es . "hablar"))) + ( + (infinitive . "spell") + (simple-past . "spelt") + (past-participle . "spelt") + (translations + (es . "deletrear"))) + ( + (infinitive . "spend") + (simple-past . "spent") + (past-participle . "spent") + (translations + (es . "gastar"))) + ( + (infinitive . "spill") + (simple-past . "spilt") + (past-participle . "spilt") + (translations + (es . "derramar"))) + ( + (infinitive . "spit") + (simple-past . "spit") + (past-participle . "spit") + (translations + (es . "escupir"))) + ( + (infinitive . "stand") + (simple-past . "stood") + (past-participle . "stood") + (translations + (es . "ponerse/estar de pie"))) + ( + (infinitive . "steal") + (simple-past . "stole") + (past-participle . "stolen") + (translations + (es . "robar"))) + ( + (infinitive . "swim") + (simple-past . "swam") + (past-participle . "swum") + (translations + (es . "nadar"))) + ( + (infinitive . "take") + (simple-past . "took") + (past-participle . "taken") + (translations + (es . "tomar, coger"))) + ( + (infinitive . "teach") + (simple-past . "taught") + (past-participle . "taught") + (translations + (es . "enseñar"))) + ( + (infinitive . "tear") + (simple-past . "tore") + (past-participle . "torn") + (translations + (es . "romper, rasgar"))) + ( + (infinitive . "tell") + (simple-past . "told") + (past-participle . "told") + (translations + (es . "decir, contar"))) + ( + (infinitive . "think") + (simple-past . "thought") + (past-participle . "thought") + (translations + (es . "pensar"))) + ( + (infinitive . "throw") + (simple-past . "threw") + (past-participle . "thrown") + (translations + (es . "lanzar, tirar"))) + ( + (infinitive . "understand") + (simple-past . "understood") + (past-participle . "understood") + (translations + (es . "entender"))) + ( + (infinitive . "wake") + (simple-past . "woke") + (past-participle . "woken") + (translations + (es . "despertar"))) + ( + (infinitive . "wear") + (simple-past . "wore") + (past-participle . "worn") + (translations + (es . "llevar puesto"))) + ( + (infinitive . "win") + (simple-past . "won") + (past-participle . "won") + (translations + (es . "ganar"))) + ( + (infinitive . "write") + (simple-past . "wrote") + (past-participle . "written") + (translations + (es . "escribir"))))) + +(provide 'lirve-verbs) +;;; lirve-verbs.el ends here diff --git a/lirve.el b/lirve.el new file mode 100644 index 0000000..2b36acc --- /dev/null +++ b/lirve.el @@ -0,0 +1,371 @@ +;;; lirve.el --- Application to learn and review irregular verbs in English. -*- lexical-binding: t -*- +;; +;; Copyright © 2024 Andros Fenollosa +;; Authors: Andros Fenollosa +;; URL: https://github.com/tanrax/learning-irregular-verbs-in-English.el +;; Version: 1.2.0 +;; SPDX-License-Identifier: GPL-3.0-or-later + +;;; Commentary: +;; Application to learn and review irregular verbs in English. + +;;; Code: + +;; Imports +(require 'lirve-verbs) +(require 'widget) +(eval-when-compile + (require 'wid-edit)) + +;; Variables +(defvar lirve--count-verbs 0) ;; It's used to know when unresolved verbs are shown +(defvar lirve--interval-unresolved 3) ;; Interval to show unresolved verbs +(defvar lirve--verbs-shuffle '()) +(defvar lirve--file-name-unresolved ".lirve-unresolved") +(defvar lirve--verbs-unresolved '()) +(defvar lirve--buffer-name "*Learning irregular verbs in English*") +(defvar lirve--state 1) ;; 1: lirve--start, 2: playing (before first check), 3: win (show success layout) +(defvar lirve--verb-to-learn-infinitive nil) +(defvar lirve--verb-to-learn-simple-past nil) +(defvar lirve--verb-to-learn-past-participle nil) +(defvar lirve--translation "") +(defvar lirve--emoji-valid "✅") +(defvar lirve--emoji-error "👎") +(defvar lirve--widget-title nil) +(defvar lirve--text-title " 🧑‍🎓 Learning irregular verbs in English 🇬🇧") +(defvar lirve--widget-item-verb nil) +(defvar lirve--widget-field-simple-past nil) +(defvar lirve--widget-label-check-simple-past nil) +(defvar lirve--widget-field-past-participle nil) +(defvar lirve--widget-label-check-past-participle nil) +(defvar lirve--text-button-check "Check") +(defvar lirve--widget-button-check nil) +(defvar lirve--widget-item-space-before-check nil) +(defvar lirve--text-button-show-solution "Don't know") +(defvar lirve--widget-button-show-solution nil) +(defvar lirve--widget-message-success nil) +(defvar lirve--widget-item-space-before-success nil) +(defvar lirve--text-success "Nice!") +(defvar lirve--text-fail "Next time you will do better") +(defvar lirve--is-resolve t) +(defvar lirve--widget-item-space-after-success nil) +(defvar lirve--widget-button-quit nil) +(defvar lirve--text-button-quit "Quit") +(defvar lirve--widget-item-space-between-buttons nil) +(defvar lirve--widget-button-lirve--replay nil) +(defvar lirve--text-button-lirve--replay "New challenge") + +;; Functions + +(defun lirve--kill-app () + "Kill the application." + (interactive) + (kill-buffer lirve--buffer-name)) + +(defun lirve--it-have-decimals (num) + "Return t if NUM is have decimals." + (let ((my-num (if (and + (stringp num) + ) ;; Return 0 if it is not a number + (string-to-number num) num))) + (when my-num (not (or (zerop my-num) ;; Check if it is 0 + (integerp my-num) ;; Check if it is integer + (and (floatp my-num) (equal my-num (float (truncate my-num)))) ;; Check if it is float + ))))) + +(defun lirve--shuffle (originalList &optional shuffledList) + "Applies the Fisher-Yates shuffle algorithm to a list. +Example: (lirve--shuffle '(1 2 3 4 5)) => (3 1 5 2 4)" + (if (null originalList) + ;; End recursion, return the shuffled list + shuffledList + ;; Otherwise, continue with the logic + (let* ((randomPosition (random (length originalList))) + (randomElement (nth randomPosition originalList)) + ;; Create a new original list without the randomly selected element + (originalListWithoutRandomElement (append (cl-subseq originalList 0 randomPosition) (nthcdr (1+ randomPosition) originalList))) + ;; Create a new shuffled list with the selected element at the beginning + (newShuffledList (if (null shuffledList) (list randomElement) (cons randomElement shuffledList)))) + ;; Recursively call the shuffle function with the new original list and the new shuffled list + (lirve--shuffle originalListWithoutRandomElement newShuffledList)))) + +(defun lirve--get-verb-for-infinitive (infinitive) + "Get the verb for the infinitive." + (car (seq-filter + (lambda (verb) (string= infinitive (alist-get 'infinitive verb))) + lirve--verbs + ))) + +(defun lirve--full-path-unresolved () + "Get the full path of the unresolved file." + (concat (file-name-directory user-init-file) lirve--file-name-unresolved)) + +(defun lirve--save-verb-unresolved (infinitive) + "Save the verb unresolved to lirve--verbs-unresolved and to the file." + (when infinitive + (progn + (setq lirve--verbs-unresolved (delete-dups (append lirve--verbs-unresolved (list infinitive)))) + (with-temp-file (lirve--full-path-unresolved) + (prin1 lirve--verbs-unresolved (current-buffer)))))) + +(defun lirve--remove-verb-unresolved (infinitive) + "Remove the verb unresolved from lirve--verbs-unresolved and from the file." + (setq lirve--verbs-unresolved (delete infinitive lirve--verbs-unresolved)) + (with-temp-file (lirve--full-path-unresolved) + (prin1 lirve--verbs-unresolved (current-buffer)))) + +(defun lirve--load-verbs-unresolved () + "Load the unresolved verbs from the file." + (when (file-exists-p (lirve--full-path-unresolved)) + (with-temp-buffer + (insert-file-contents (lirve--full-path-unresolved)) + (setq lirve--verbs-unresolved (read (current-buffer)))))) + +(defun lirve--value-field-simple-past () + "Get the value of the simple past." + (if (not (eq lirve--widget-field-simple-past nil)) (widget-value lirve--widget-field-simple-past) "")) + +(defun lirve--value-field-past-participle () + "Get the value of the past participle." + (if (not (eq lirve--widget-field-past-participle nil)) (widget-value lirve--widget-field-past-participle) "")) + +(defun lirve--set-verb-to-learn () + "Set the verb to learn." + ;; If the list is empty, shuffle it + (when (null lirve--verbs-shuffle) + (setq lirve--verbs-shuffle (lirve--shuffle lirve--verbs))) + ;; Get verb + (let* ((turn-unresolved (not (lirve--it-have-decimals (/ (float lirve--count-verbs) lirve--interval-unresolved)))) ;; Calculate if it is time to show unresolved verbs: Count / Interval. If it isn't a decimal, it is time to show unresolved verbs + (verb-to-learn + (if (and lirve--verbs-unresolved turn-unresolved) + (lirve--get-verb-for-infinitive (car lirve--verbs-unresolved)) + (car lirve--verbs-shuffle)))) + (setq lirve--verb-to-learn-infinitive (alist-get 'infinitive verb-to-learn)) + (setq lirve--verb-to-learn-simple-past (alist-get 'simple-past verb-to-learn)) + (setq lirve--verb-to-learn-past-participle (alist-get 'past-participle verb-to-learn)) + (when (not (null (boundp 'learning-irregular-verbs-in-English--show-translation))) (setq lirve--translation (alist-get learning-irregular-verbs-in-English--show-translation (alist-get 'translations verb-to-learn)))) + ;; Remove the verb from the list + (if turn-unresolved + (lirve--remove-verb-unresolved verb-to-learn) + (setq lirve--verbs-shuffle (cdr lirve--verbs-shuffle)))) + ;; Increase the count of verbs + (setq lirve--count-verbs (1+ lirve--count-verbs))) + +(defun lirve--format-value-infinitive () + "Format the value of the infinitive." + (format "Infinitive ➡️ %s" lirve--verb-to-learn-infinitive)) + +(defun lirve--format-check-simple-past () + "Format the value of the simple past." + (if (eq lirve--state 1) + "" + (format " %s" (if + (and + (string= (lirve--value-field-simple-past) lirve--verb-to-learn-simple-past) + (not (string= (lirve--value-field-simple-past) ""))) + lirve--emoji-valid lirve--emoji-error)))) + +(defun lirve--format-check-past-participle () + "Format the value of the past participle." + (if (eq lirve--state 1) + "" + (format " %s" (if + (and + (string= (lirve--value-field-past-participle) lirve--verb-to-learn-past-participle) + (not (string= (lirve--value-field-past-participle) ""))) + lirve--emoji-valid lirve--emoji-error)))) + +(defun lirve--show-translation () + "Show translation if learning-irregular-verbs-in-English--show-translation is t" + (when (not (null lirve--translation)) + (widget-value-set lirve--widget-item-verb (concat (lirve--format-value-infinitive) " 🇪🇸 " lirve--translation)))) + +(defun lirve--toggle-layout-finish () + "Toggle the layout to success." + (if (eq lirve--state 3) + (progn + ;; Show translate + (lirve--show-translation) + ;; Cursor to end + (goto-char (point-max)) + ;; Remove check button + (widget-delete lirve--widget-button-check) + (setq lirve--widget-button-check nil) + ;; Remove space after check button + (widget-delete lirve--widget-item-space-before-check) + (setq lirve--widget-item-space-before-check nil) + ;; Remove show solution button + (widget-delete lirve--widget-button-show-solution) + (setq lirve--widget-button-show-solution nil) + ;; Text success + (setq lirve--widget-item-space-before-success (widget-create 'item + "")) + (setq lirve--widget-message-success (widget-create 'item + (if lirve--is-resolve lirve--text-success lirve--text-fail))) + (setq lirve--widget-item-space-after-success (widget-create 'item + "\n")) + ;; Lirve--Replay button + (setq lirve--widget-button-lirve--replay (widget-create 'push-button + :size 20 + :notify (lambda (&rest ignore) + (lirve--replay)) + lirve--text-button-lirve--replay)) + ;; Space + (setq lirve--widget-item-space-between-buttons (widget-create 'item + "\n")) + ;; Quit button + (setq lirve--widget-button-quit (widget-create 'push-button + :size 20 + :notify (lambda (&rest ignore) + (lirve--kill-app)) + lirve--text-button-quit)) + (widget-backward 2) + ) + (progn + (when (not (eq lirve--widget-item-space-before-success nil)) (widget-delete lirve--widget-item-space-before-success)) + (when (not (eq lirve--widget-message-success nil)) (widget-delete lirve--widget-message-success)) + (when (not (eq lirve--widget-item-space-after-success nil)) (widget-delete lirve--widget-item-space-after-success)) + (when (not (eq lirve--widget-button-lirve--replay nil)) (widget-delete lirve--widget-button-lirve--replay)) + (when (not (eq lirve--widget-item-space-between-buttons nil)) (widget-delete lirve--widget-item-space-between-buttons)) + (when (not (eq lirve--widget-button-quit nil)) (widget-delete lirve--widget-button-quit)) + ))) + +(defun lirve--make-button-check () + "Make the button check." + (setq lirve--widget-button-check (widget-create 'push-button + :notify (lambda (&rest ignore) + (lirve--update)) + lirve--text-button-check))) +(defun lirve--make-space-after-check () + "Add space between Button check and Button show solution" + (setq lirve--widget-item-space-before-check (widget-create 'item "\n"))) + + +(defun lirve--show-solutions () + "Show solutions" + (widget-value-set lirve--widget-field-simple-past lirve--verb-to-learn-simple-past) + (widget-value-set lirve--widget-field-past-participle lirve--verb-to-learn-past-participle) + (lirve--save-verb-unresolved lirve--verb-to-learn-infinitive)) + +(defun lirve--make-button-show-solution () + "Make the button show solution." + (setq lirve--widget-button-show-solution (widget-create 'push-button + :notify (lambda (&rest ignore) + (lirve--show-solutions) + (lirve--update)) + lirve--text-button-show-solution))) + + +(defun lirve--start () + "Start challenge." + ;; Set the lirve--state + (setq lirve--state 1) + ;; Get a new verb + (lirve--set-verb-to-learn) + ;; Show the verb in infinitive + (widget-value-set lirve--widget-item-verb (lirve--format-value-infinitive)) + ;; Reset button check + (when (eq lirve--widget-button-check nil) (lirve--make-button-check)) + ;; Reset space after check + (when (eq lirve--widget-item-space-before-check nil) (lirve--make-space-after-check)) + ;; Reset button show solution + (when (eq lirve--widget-button-show-solution nil) (lirve--make-button-show-solution)) + ;; Clear the fields + (widget-value-set lirve--widget-field-simple-past "") + (widget-value-set lirve--widget-label-check-simple-past "") + (widget-value-set lirve--widget-field-past-participle "") + (widget-value-set lirve--widget-label-check-past-participle "") + ;; Update labels + (lirve--update)) + +(defun lirve--replay () + "Replay the challenge." + (interactive) + (lirve--start) + (widget-backward 1)) + +(defun lirve--update () + "Update state and show temps layouts." + (interactive) + ;; Is playing? + (when (and (eq lirve--state 1) + (or + (not (string= (lirve--value-field-simple-past) "")) + (not (string= (lirve--value-field-past-participle) ""))) + ) + (setq lirve--state 2)) + ;; Check the answers + (when (eq lirve--state 2) + ;; Is win? + (when (and + (string= (lirve--value-field-simple-past) lirve--verb-to-learn-simple-past) + (string= (lirve--value-field-past-participle) lirve--verb-to-learn-past-participle)) + ;; Set the lirve--state + (setq lirve--state 3)) + ;; Update the check labels + (widget-value-set lirve--widget-label-check-simple-past (lirve--format-check-simple-past)) + (widget-value-set lirve--widget-label-check-past-participle (lirve--format-check-past-participle))) + ;; Update the success layout if needed + (lirve--toggle-layout-finish) + (setq lirve--is-resolve t)) + +(defun lirve--main-layout () + "Make widgets for the main layout." + ;; Create the buffer + (switch-to-buffer lirve--buffer-name) + ;; Clear the buffer + (kill-all-local-variables) + (let ((inhibit-read-only t)) + (erase-buffer)) + (remove-overlays) + ;; Create the widgets + ;; Title + (insert (propertize (format "\n%s\n\n" lirve--text-title) 'face '(:height 1.2 :weight bold))) + ;; Verb in infinitive + (setq lirve--widget-item-verb (widget-create 'item + :value "")) + ;; Separator + (insert "\nSimple past ➡️ ") + ;; Simple past + (setq lirve--widget-field-simple-past (widget-create 'editable-field + :size 8 + :help-echo "Type a Simple past" + )) + ;; Label check + (insert " ") + (setq lirve--widget-label-check-simple-past (widget-create 'item + (lirve--format-check-simple-past))) + ;; Separator + (insert "\nPast participle ➡️ ") + ;; Past participle + (setq lirve--widget-field-past-participle (widget-create 'editable-field + :size 8 + :help-echo "Type a Past participle")) + ;; Label check + (insert " ") + (setq lirve--widget-label-check-past-participle (widget-create 'item + (lirve--format-check-past-participle))) + ;; Separator + (insert "\n") + ;; Check button + (lirve--make-button-check) + ;; Separator + (lirve--make-space-after-check) + ;; Show solution button + (lirve--make-button-show-solution) + ;; Display the buffer + (use-local-map widget-keymap) + (widget-setup)) + +;; Init +(defun learning-irregular-verbs-in-english () + "Application to learn and review irregular verbs in English." + (interactive) + (lirve--load-verbs-unresolved) + (lirve--main-layout) + (lirve--start) + (widget-backward 4)) + +(provide 'lirve) + +;;; lirve.el ends here