Files
linuxplus/06-linuxplus-quiz-mode.el
T
2026-04-21 15:13:54 -04:00

157 lines
5.8 KiB
EmacsLisp

;;; 06-linuxplus-quiz-mode.el --- linuxplus-quiz-mode
(defvar-local linuxplus-quiz-questions nil
"Questions for the current Linux+ quiz buffer.")
(defvar-local linuxplus-quiz-answers nil
"Correct answers for the current Linux+ quiz buffer.")
(defvar-local linuxplus-quiz-user-answers nil
"User answers for the current Linux+ quiz buffer.")
(defvar-local linuxplus-quiz-current-index 0
"Current question index in the Linux+ quiz buffer.")
(defvar-local linuxplus-quiz-lesson-name nil
"Lesson name associated with the current Linux+ quiz buffer.")
(defun linuxplus-quiz-answer-marker (answer)
"Return a display marker string for ANSWER."
(cond
((eq answer 'y) "[y]")
((eq answer 'n) "[n]")
(t "[ ]")))
(defun linuxplus-quiz-answer-string (answer)
"Return a readable string for ANSWER."
(cond
((eq answer 'y) "y")
((eq answer 'n) "n")
(t "unanswered")))
(defun linuxplus-quiz-result-string (user-answer correct-answer)
"Return a readable result string comparing USER-ANSWER to CORRECT-ANSWER."
(if (eq user-answer correct-answer)
"correct"
"incorrect"))
(defun linuxplus-quiz-render ()
"Render the current Linux+ quiz buffer."
(let ((inhibit-read-only t))
(erase-buffer)
(insert "Linux+ Quiz\n")
(insert "===========\n\n")
(insert "y = yes, n = no, b = back, f = forward, x = finish, q = quit\n\n")
(dotimes (i (length linuxplus-quiz-questions))
(let ((prefix (if (= i linuxplus-quiz-current-index) ">" " "))
(marker (linuxplus-quiz-answer-marker
(nth i linuxplus-quiz-user-answers)))
(question (nth i linuxplus-quiz-questions)))
(insert (format "%s %s %d. %s\n"
prefix marker (1+ i) question)))))
(goto-char (point-min)))
(defun linuxplus-quiz-finish ()
"Finish the current quiz, record the score, and show detailed results."
(interactive)
(let ((score 0)
(total (length linuxplus-quiz-questions)))
(dotimes (i total)
(when (eq (nth i linuxplus-quiz-user-answers)
(nth i linuxplus-quiz-answers))
(setq score (1+ score))))
(linuxplus-record-score linuxplus-quiz-lesson-name score)
(let ((inhibit-read-only t))
(erase-buffer)
(insert "Linux+ Quiz Results\n")
(insert "===================\n\n")
(insert (format "Lesson: %s\n" linuxplus-quiz-lesson-name))
(insert (format "Score: %d/%d\n\n" score total))
(insert "Detailed review:\n\n")
(dotimes (i total)
(let ((question (nth i linuxplus-quiz-questions))
(user-answer (nth i linuxplus-quiz-user-answers))
(correct-answer (nth i linuxplus-quiz-answers)))
(insert (format "%d. %s\n" (1+ i) question))
(insert (format " Your answer: %s\n"
(linuxplus-quiz-answer-string user-answer)))
(insert (format " Correct answer: %s\n"
(linuxplus-quiz-answer-string correct-answer)))
(insert (format " Result: %s\n\n"
(linuxplus-quiz-result-string
user-answer correct-answer))))))
(goto-char (point-min))
(view-mode 1)
(message "Quiz complete. Score: %d/%d" score total)))
(defun linuxplus-quiz-answer-y ()
"Answer yes to the current Linux+ quiz question."
(interactive)
(setf (nth linuxplus-quiz-current-index linuxplus-quiz-user-answers) 'y)
(if (< linuxplus-quiz-current-index
(1- (length linuxplus-quiz-questions)))
(setq linuxplus-quiz-current-index
(1+ linuxplus-quiz-current-index))
(linuxplus-quiz-render))
(when (derived-mode-p 'linuxplus-quiz-mode)
(linuxplus-quiz-render)))
(defun linuxplus-quiz-answer-n ()
"Answer no to the current Linux+ quiz question."
(interactive)
(setf (nth linuxplus-quiz-current-index linuxplus-quiz-user-answers) 'n)
(if (< linuxplus-quiz-current-index
(1- (length linuxplus-quiz-questions)))
(setq linuxplus-quiz-current-index
(1+ linuxplus-quiz-current-index))
(linuxplus-quiz-render))
(when (derived-mode-p 'linuxplus-quiz-mode)
(linuxplus-quiz-render)))
(defun linuxplus-quiz-next ()
"Move to next question without changing answer."
(interactive)
(when (< linuxplus-quiz-current-index
(1- (length linuxplus-quiz-questions)))
(setq linuxplus-quiz-current-index
(1+ linuxplus-quiz-current-index))
(linuxplus-quiz-render)))
(defun linuxplus-quiz-prev ()
"Move to previous question."
(interactive)
(when (> linuxplus-quiz-current-index 0)
(setq linuxplus-quiz-current-index
(1- linuxplus-quiz-current-index))
(linuxplus-quiz-render)))
(defvar linuxplus-quiz-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "y") #'linuxplus-quiz-answer-y)
(define-key map (kbd "n") #'linuxplus-quiz-answer-n)
(define-key map (kbd "f") #'linuxplus-quiz-next)
(define-key map (kbd "b") #'linuxplus-quiz-prev)
(define-key map (kbd "x") #'linuxplus-quiz-finish)
(define-key map (kbd "q") #'quit-window)
map)
"Keymap for `linuxplus-quiz-mode`.")
(define-derived-mode linuxplus-quiz-mode special-mode "LinuxPlus-Quiz"
"Major mode for Linux+ quiz buffers."
(setq buffer-read-only t))
(defun linuxplus-start-quiz (lesson questions answers buffer)
"Start a Linux+ quiz for LESSON using QUESTIONS and ANSWERS in BUFFER."
(let ((buf (get-buffer-create buffer)))
(with-current-buffer buf
(linuxplus-quiz-mode)
(setq linuxplus-quiz-lesson-name lesson)
(setq linuxplus-quiz-questions questions)
(setq linuxplus-quiz-answers answers)
(setq linuxplus-quiz-user-answers (make-list (length questions) nil))
(setq linuxplus-quiz-current-index 0)
(linuxplus-quiz-render))
(pop-to-buffer buf)))
;;; 06-linuxplus-quiz-mode.el ends here