|
| 1 | +;;; aoc2025-eutro.el --- Advent of Code utilities -*- lexical-binding: t -*- |
| 2 | + |
| 3 | +;;; Code: |
| 4 | + |
| 5 | +(defgroup aoc2025-eutro nil |
| 6 | + "Group for Eutro's Advent of Code 2025" |
| 7 | + :prefix 'aoc2025-eutro- |
| 8 | + :group 'misc) |
| 9 | + |
| 10 | +(defconst aoc-root |
| 11 | + (locate-dominating-file |
| 12 | + (or load-file-name (buffer-file-name)) |
| 13 | + "README.md")) |
| 14 | + |
| 15 | +(defconst aoc-dayfile-pattern "Day\\([0-9]\\{2\\}\\)") |
| 16 | + |
| 17 | +(defvar-local aoc-pinned-day-number nil) |
| 18 | + |
| 19 | +(defun aoc-day-number () |
| 20 | + "Determine the day number of the current file, or the current day." |
| 21 | + (or |
| 22 | + aoc-pinned-day-number |
| 23 | + (when-let ((file-name (buffer-file-name))) |
| 24 | + (and (string-match aoc-dayfile-pattern file-name) |
| 25 | + (string-to-number (match-string 1 file-name)))) |
| 26 | + (progn |
| 27 | + (require 'calendar) |
| 28 | + (cadr (calendar-current-date))))) |
| 29 | + |
| 30 | +(defun aoc-get-out-buffer (&optional clear day) |
| 31 | + "Get the *aoc-output* buffer." |
| 32 | + (let ((buf (get-buffer-create "*aoc-output*"))) |
| 33 | + (when (or clear |
| 34 | + (not (eq 'aoc-run-mode |
| 35 | + (buffer-local-value 'major-mode buf)))) |
| 36 | + (with-current-buffer buf |
| 37 | + (erase-buffer) |
| 38 | + (when day (setq aoc-pinned-day-number day)) |
| 39 | + (aoc-run-mode))) |
| 40 | + buf)) |
| 41 | + |
| 42 | +(defconst aoc--run-script (expand-file-name "run.sh" aoc-root)) |
| 43 | + |
| 44 | +(defconst aoc--display-buffer-action nil |
| 45 | + ;;'display-buffer-use-least-recent-window |
| 46 | + ) |
| 47 | + |
| 48 | +(defun aoc-run (&optional prefix) |
| 49 | + "Run the current day. |
| 50 | +
|
| 51 | +With PREFIX, read input from the buffer." |
| 52 | + (interactive "P") |
| 53 | + (let* ((day (aoc-day-number)) |
| 54 | + (inp-args (when prefix '("--"))) |
| 55 | + (buf (aoc-get-out-buffer t day)) |
| 56 | + (args (cons (number-to-string day) inp-args)) |
| 57 | + (proc (apply #'start-process "aoc-run" buf aoc--run-script args)) |
| 58 | + (win (selected-window))) |
| 59 | + (set-process-sentinel |
| 60 | + proc |
| 61 | + (lambda (_proc msg) |
| 62 | + (when-let ((win (get-buffer-window buf))) |
| 63 | + (with-selected-window win |
| 64 | + (recenter -1))))) |
| 65 | + (unless (eq (window-buffer win) buf) |
| 66 | + (if prefix |
| 67 | + (pop-to-buffer buf aoc--display-buffer-action) |
| 68 | + (display-buffer buf aoc--display-buffer-action))) |
| 69 | + (message "./run.sh %s" (string-join (mapcar #'shell-quote-argument args) " ")))) |
| 70 | + |
| 71 | +(defun aoc-copy-part-answer (part) |
| 72 | + "Copy the answer for the given PART from *aoc-output*." |
| 73 | + (with-current-buffer (aoc-get-out-buffer) |
| 74 | + (goto-char (point-max)) |
| 75 | + (unless (re-search-backward (format "Part %d: " part) nil t) |
| 76 | + (user-error "Part %d not found in buffer" part)) |
| 77 | + (goto-char (match-end 0)) |
| 78 | + (let ((start (point))) |
| 79 | + (end-of-line) |
| 80 | + (copy-region-as-kill start (point)) |
| 81 | + (message "Copied: %s" (current-kill 0 t))))) |
| 82 | + |
| 83 | +(defmacro aoc-copy-n (part) |
| 84 | + `(defun ,(intern (format "aoc-copy-%d" part)) () |
| 85 | + ,(format "Copy the answer for part %d in *aoc-output*." part) |
| 86 | + (interactive) |
| 87 | + (aoc-copy-part-answer ,part))) |
| 88 | + |
| 89 | +(aoc-copy-n 1) |
| 90 | +(aoc-copy-n 2) |
| 91 | + |
| 92 | +(defconst aoc-mode-map |
| 93 | + (let ((keys (make-sparse-keymap))) |
| 94 | + (define-key keys (kbd "C-c C-c") #'aoc-run) |
| 95 | + (define-key keys (kbd "C-c 1") #'aoc-copy-1) |
| 96 | + (define-key keys (kbd "C-c 2") #'aoc-copy-2) |
| 97 | + keys)) |
| 98 | + |
| 99 | +(define-minor-mode aoc-mode |
| 100 | + "Minor mode for Advent of Code utilities" |
| 101 | + :lighter " AoC24") |
| 102 | + |
| 103 | +(defconst aoc-run-mode-map |
| 104 | + (let ((keys (copy-keymap aoc-mode-map))) |
| 105 | + keys)) |
| 106 | + |
| 107 | +(define-derived-mode aoc-run-mode comint-mode "AoC-Run" |
| 108 | + "Major mode for the *aoc-run* buffer.") |
| 109 | + |
| 110 | +;; Local Variables: |
| 111 | +;; read-symbol-shorthands: (("aoc-" . "aoc2025-eutro-")) |
| 112 | +;; End: |
| 113 | + |
| 114 | +(provide 'aoc2025-eutro) |
| 115 | +;;; aoc2025-eutro.el ends here |
0 commit comments