diff options
| -rw-r--r-- | modules/config-utilities.el | 452 |
1 files changed, 134 insertions, 318 deletions
diff --git a/modules/config-utilities.el b/modules/config-utilities.el index aff27ab5..a3eae73c 100644 --- a/modules/config-utilities.el +++ b/modules/config-utilities.el @@ -4,42 +4,13 @@ ;;; Commentary: ;; Development and debugging utilities for Emacs configuration maintenance. ;; -;; Features include: -;; - reloading and recompiling configuration (native/byte compilation) -;; - inspecting loaded packages and features -;; - reporting on Emacs version build configuration -;; - validating org-agenda timestamp integrity -;; - debugging org-alert timers -;; - SQLite database tracing and finalizer debugging -;; - auth-source cache management -;; -;; Key commands: -;; - ~cj/reload-init-file~ to reload init.el. -;; - ~cj/recompile-emacs-home~ to recompile all Elisp files. -;; - ~cj/list-loaded-packages~ to show currently loaded packages. -;; - ~cj/check-org-agenda-invalid-timestamps~ to scan for invalid timestamps. -;; - ~cj/sqlite-tracing-enable~ to enable SQLite debugging. -;; - ~cj/emacs-build-summary~ to build a buffer containing information about the Emacs version. -;; ;;; Code: (require 'cl-lib) +(require 'find-lisp) (require 'profiler) -;; Declare functions from lazy-loaded packages to suppress byte-compiler warnings. -;; These packages are required at runtime when their respective functions are called. -(declare-function find-lisp-find-files "find-lisp" (directory regexp)) -(declare-function org-element-parse-buffer "org-element" (&optional granularity visible-only)) -(declare-function org-element-map "org-element" (data types fun &optional info first-match no-recursion with-affiliated)) -(declare-function org-element-property "org-element" (property element)) -(declare-function org-time-string-to-absolute "org" (s &optional daynr prefer buffer pos)) -(declare-function org-alert-check "org-alert" nil) - -;; Declare variables from lazy-loaded packages -(defvar org-agenda-files) -(defvar org-ts-regexp) - -;; -------------------------------- Debug Keymap ------------------------------- +;;; -------------------------------- Debug Keymap ------------------------------- (defvar-keymap cj/debug-config-keymap :doc "config debugging utilities keymap.") @@ -47,7 +18,7 @@ (with-eval-after-load 'which-key (which-key-add-key-based-replacements "C-c d" "Config debugging utilities.")) -;; --------------------------------- Profiling --------------------------------- +;;; --------------------------------- Profiling --------------------------------- (with-eval-after-load 'which-key (which-key-add-key-based-replacements "C-c d p" "profiler menu.")) @@ -55,7 +26,11 @@ (keymap-set cj/debug-config-keymap "p h" #'profiler-stop) (keymap-set cj/debug-config-keymap "p r" #'profiler-report) -;; -------------------------------- Benchmarking ------------------------------- +;;; --------------------------- Toggle Debug On Error --------------------------- + +(keymap-set cj/debug-config-keymap "t" #'toggle-debug-on-error) + +;;; -------------------------------- Benchmarking ------------------------------- (defmacro with-timer (title &rest forms) "Run the given FORMS, counting the elapsed time. @@ -79,42 +54,40 @@ time is displayed." #'fboundp t))) (let ((method-symbol (intern-soft method-name))) (if (and method-symbol (fboundp method-symbol)) - (with-timer title + (with-timer title (funcall method-symbol)) - (message "Invalid method name: %s" method-name))))) + (message "Invalid method name: %s" method-name))))) (keymap-set cj/debug-config-keymap "b" #'cj/benchmark-this-method) -;; ----------------------------- Config Compilation ---------------------------- - -(defvar comp-async-report-warnings-errors) +;;; ----------------------------- Config Compilation ---------------------------- (defun cj/recompile-emacs-home() "Delete all compiled files in the Emacs home before recompiling. Recompile natively when supported, otherwise fall back to byte compilation." (interactive) (let* ((native-comp-supported (boundp 'native-compile-async)) - (elt-dir - (expand-file-name (if native-comp-supported "eln" "elc") - user-emacs-directory)) - (message-format - (format "Please confirm recursive %s recompilation of %%s: " - (if native-comp-supported "native" "byte"))) - (compile-message (format "%scompiling all emacs-lisp files in %%s" - (if native-comp-supported "Natively " "Byte-")))) - (if (yes-or-no-p (format message-format user-emacs-directory)) - (progn - (message "Deleting all compiled files in %s" user-emacs-directory) - (dolist (file (directory-files-recursively user-emacs-directory - "\\(\\.elc\\|\\.eln\\)$")) - (delete-file file)) - (when (file-directory-p elt-dir) - (delete-directory elt-dir t t)) - (message compile-message user-emacs-directory) - (if native-comp-supported - (progn - (setq comp-async-report-warnings-errors nil) - (native-compile-async user-emacs-directory 'recursively)) - (byte-recompile-directory user-emacs-directory 0))) + (elt-dir + (expand-file-name (if native-comp-supported "eln" "elc") + user-emacs-directory)) + (message-format + (format "Please confirm recursive %s recompilation of %%s: " + (if native-comp-supported "native" "byte"))) + (compile-message (format "%scompiling all emacs-lisp files in %%s" + (if native-comp-supported "Natively " "Byte-")))) + (if (yes-or-no-p (format message-format user-emacs-directory)) + (progn + (message "Deleting all compiled files in %s" user-emacs-directory) + (dolist (file (directory-files-recursively user-emacs-directory + "\\(\\.elc\\|\\.eln\\)$")) + (delete-file file)) + (when (file-directory-p elt-dir) + (delete-directory elt-dir t t)) + (message compile-message user-emacs-directory) + (if native-comp-supported + (progn + (setq comp-async-report-warnings-errors nil) + (native-compile-async user-emacs-directory 'recursively)) + (byte-recompile-directory user-emacs-directory 0))) (message "Cancelled recompilation of %s" user-emacs-directory)))) (keymap-set cj/debug-config-keymap "c h" 'cj/recompile-emacs-home) @@ -125,12 +98,12 @@ Recompile natively when supported, otherwise fall back to byte compilation." "Delete all compiled files recursively in \='user-emacs-directory\='." (interactive) (message "Deleting compiled files under %s. This may take a while." - user-emacs-directory) + user-emacs-directory) (require 'find-lisp) ;; make sure the package is required (mapc (lambda (path) - (when (or (string-suffix-p ".elc" path) - (string-suffix-p ".eln" path)) - (delete-file path))) + (when (or (string-suffix-p ".elc" path) + (string-suffix-p ".eln" path)) + (delete-file path))) (find-lisp-find-files user-emacs-directory "")) (message "Done. Compiled files removed under %s" user-emacs-directory)) (keymap-set cj/debug-config-keymap "c d" 'cj/delete-emacs-home-compiled-files) @@ -162,18 +135,13 @@ Recompile natively when supported, otherwise fall back to byte compilation." (message "Byte-compiled -> %s" out) (message "Byte-compilation failed for %s" file)))) ;; Neither facility available - (otherwise + (t (message "No compilation available (no native-compile, no byte-compile)"))))) (keymap-set cj/debug-config-keymap "c ." 'cj/compile-this-elisp-buffer) -;; ---------------------------- Emacs Build Summary ---------------------------- -;; builds a buffer with information about this version of Emacs - -(defun cj--yes-no (flag) - "Return \"yes\" if FLAG is non-nil, otherwise return \"no\"." - (if flag "yes" "no")) +;; --------------------------- Information Reporting --------------------------- -(defun cj--format-build-time (tval) +(defun cj/emacs-build--format-build-time (tval) "Return a human-readable build time from TVAL." (cond ((null tval) "unknown") @@ -184,7 +152,7 @@ Recompile natively when supported, otherwise fall back to byte compilation." (format-time-string "%Y-%m-%d %H:%M:%S %Z" (seconds-to-time tval))) (t (format "%s" tval)))) -(defun cj/emacs-build-summary-string () +(defun cj/emacs-build--summary-string () "Return a concise multi-line string describing this Emacs build." (let ((build-time (and (boundp 'emacs-build-time) emacs-build-time)) (build-system (and (boundp 'emacs-build-system) emacs-build-system)) @@ -195,7 +163,7 @@ Recompile natively when supported, otherwise fall back to byte compilation." (concat (format "Version: %s\n" emacs-version) (format "System: %s\n" system-configuration) - (format "Build date: %s\n" (cj--format-build-time build-time)) + (format "Build date: %s\n" (cj/emacs-build--format-build-time build-time)) (when build-system (format "Build system: %s\n" build-system)) (when branch @@ -204,45 +172,50 @@ Recompile natively when supported, otherwise fall back to byte compilation." (format "Git commit: %s\n" (or commit "n/a"))) "\nCapabilities:\n" (format "- Native compilation: %s\n" - (cj--yes-no (and (fboundp 'native-comp-available-p) - (native-comp-available-p)))) + (if (and (fboundp 'native-comp-available-p) + (native-comp-available-p)) + "yes" "no")) (format "- Dynamic modules: %s\n" - (cj--yes-no (and (boundp 'module-file-suffix) - module-file-suffix))) + (if (and (boundp 'module-file-suffix) + module-file-suffix) + "yes" "no")) (format "- GnuTLS: %s\n" - (cj--yes-no (and (fboundp 'gnutls-available-p) - (gnutls-available-p)))) + (if (and (fboundp 'gnutls-available-p) + (gnutls-available-p)) + "yes" "no")) (format "- libxml2: %s\n" - (cj--yes-no (fboundp 'libxml-parse-html-region))) + (if (fboundp 'libxml-parse-html-region) + "yes" "no")) (format "- ImageMagick: %s\n" - (cj--yes-no (and (fboundp 'image-type-available-p) - (image-type-available-p 'imagemagick)))) + (if (and (fboundp 'image-type-available-p) + (image-type-available-p 'imagemagick)) + "yes" "no" )) (format "- SQLite: %s\n" - (cj--yes-no (and (fboundp 'sqlite-available-p) - (sqlite-available-p)))) + (if (and (fboundp 'sqlite-available-p) + (sqlite-available-p)) + "yes" "no")) (when features (format "\nConfigured features:\n%s\n" features)) (when options (format "\nConfiguration arguments:\n%s\n" options))))) -(defun cj/emacs-build-summary () +(defun cj/info-emacs-build () "Display a buffer with the Emacs build summary." (interactive) (let ((buf (get-buffer-create "*Emacs-Build-Summary*"))) (with-current-buffer buf (setq buffer-read-only nil) (erase-buffer) - (insert (cj/emacs-build-summary-string)) + (insert (cj/emacs-build--summary-string)) (goto-char (point-min)) (help-mode) (setq-local truncate-lines nil)) (pop-to-buffer buf))) -(keymap-set cj/debug-config-keymap "i b" 'cj/emacs-build-summary) +(keymap-set cj/debug-config-keymap "i b" 'cj/info-emacs-build) (with-eval-after-load 'which-key (which-key-add-key-based-replacements "C-c d i" "info on build/features/packages.")) -;; ---------------------- List Loaded Packages --------------------- (defvar cj--loaded-file-paths nil "All file paths that are loaded.") @@ -251,31 +224,29 @@ Recompile natively when supported, otherwise fall back to byte compilation." (defvar cj--loaded-features-buffer "*loaded-features*" "Buffer name for data about loaded features.") -(defun cj/list-loaded-packages() +(defun cj/info-loaded-packages() "List all currently loaded packages." (interactive) (with-current-buffer (get-buffer-create cj--loaded-packages-buffer) - (erase-buffer) - (pop-to-buffer (current-buffer)) + (erase-buffer) + (pop-to-buffer (current-buffer)) - (insert "* Live Packages Exploration\n\n") + (insert "* Live Packages Exploration\n\n") - ;; Extract data from builtin variable `load-history'. - (setq cj--loaded-file-paths - (seq-filter #'stringp - (mapcar #'car load-history))) - (setq cj--loaded-file-paths (cl-sort cj--loaded-file-paths 'string-lessp)) - (insert (format "%s total packages currently loaded\n" - (length cj--loaded-file-paths))) - (cl-loop for file in cj--loaded-file-paths - do (insert "\n" file)) + ;; Extract data from builtin variable `load-history'. + (setq cj--loaded-file-paths + (seq-filter #'stringp + (mapcar #'car load-history))) + (setq cj--loaded-file-paths (cl-sort cj--loaded-file-paths 'string-lessp)) + (insert (format "%s total packages currently loaded\n" + (length cj--loaded-file-paths))) + (cl-loop for file in cj--loaded-file-paths + do (insert "\n" file)) (goto-char (point-min)))) -(keymap-set cj/debug-config-keymap "i p" 'cj/list-loaded-packages) +(keymap-set cj/debug-config-keymap "i p" 'cj/info-loaded-packages) -;; ---------------------------- List Loaded Features --------------------------- - -(defun cj/list-loaded-features() +(defun cj/info-loaded-features() "List all currently loaded features." (interactive) (with-current-buffer (get-buffer-create cj--loaded-features-buffer) @@ -289,10 +260,9 @@ Recompile natively when supported, otherwise fall back to byte compilation." (setq features-vec (cl-sort features-vec 'string-lessp)) (cl-loop for x across features-vec do (insert (format " - %-25s: %s\n" x - (locate-library (symbol-name x)))))) + (locate-library (symbol-name x)))))) (goto-char (point-min)))) -(keymap-set cj/debug-config-keymap "i f" 'cj/list-loaded-features) - +(keymap-set cj/debug-config-keymap "i f" 'cj/info-loaded-features) ;; ------------------------------ Reload Init File ----------------------------- ;; it does what it says it does. @@ -314,7 +284,7 @@ Recompile natively when supported, otherwise fall back to byte compilation." ;; ------------------------ Validate Org Agenda Entries ------------------------ -(defun cj/check-org-agenda-invalid-timestamps () +(defun cj/validate-org-agenda-timestamps () "Scan all files in \='org-agenda-files\=' for invalid timestamps. Checks DEADLINE, SCHEDULED, TIMESTAMP properties and inline timestamps in headline contents. Generates an Org-mode report buffer with links to problematic @@ -323,46 +293,46 @@ entries, property/type, and raw timestamp string." (require 'org) (require 'org-element) (let ((report-buffer (get-buffer-create "*Org Invalid Timestamps Report*"))) - (with-current-buffer report-buffer - (erase-buffer) - (org-mode) - (insert "#+TITLE: Org Invalid Timestamps Report\n\n") - (insert "* Overview\nScan of org-agenda-files for invalid timestamps.\n\n")) - (dolist (file org-agenda-files) - (with-current-buffer (find-file-noselect file) - (let ((invalid-entries '()) - (props '("DEADLINE" "SCHEDULED" "TIMESTAMP")) - (parse-tree (org-element-parse-buffer 'headline))) - (org-element-map parse-tree 'headline - (lambda (hl) - (let ((headline-text (org-element-property :raw-value hl)) - (begin-pos (org-element-property :begin hl))) - (dolist (prop props) - (let ((timestamp (org-element-property (intern (downcase prop)) hl))) - (when timestamp - (let ((time-str (org-element-property :raw-value timestamp))) - (unless (ignore-errors (org-time-string-to-absolute time-str)) - (push (list file begin-pos headline-text prop time-str) invalid-entries)))))) - (let ((contents-begin (org-element-property :contents-begin hl)) - (contents-end (org-element-property :contents-end hl))) - (when (and contents-begin contents-end) - (save-excursion - (goto-char contents-begin) - (while (re-search-forward org-ts-regexp contents-end t) - (let ((ts-string (match-string 0))) - (unless (ignore-errors (org-time-string-to-absolute ts-string)) - (push (list file begin-pos headline-text "inline timestamp" ts-string) invalid-entries)))))))))) - - (with-current-buffer report-buffer - (insert (format "* %s\n" file)) - (if invalid-entries - (dolist (entry (reverse invalid-entries)) - (cl-destructuring-bind (f pos head prop ts) entry - (insert (format "- [[file:%s::%d][%s]]\n - Property/Type: %s\n - Invalid timestamp: \"%s\"\n" - f pos head prop ts)))) - (insert "No invalid timestamps found.\n"))) - (with-current-buffer report-buffer (insert "\n"))))) - (pop-to-buffer report-buffer))) + (with-current-buffer report-buffer + (erase-buffer) + (org-mode) + (insert "#+TITLE: Org Invalid Timestamps Report\n\n") + (insert "* Overview\nScan of org-agenda-files for invalid timestamps.\n\n")) + (dolist (file org-agenda-files) + (with-current-buffer (find-file-noselect file) + (let ((invalid-entries '()) + (props '("DEADLINE" "SCHEDULED" "TIMESTAMP")) + (parse-tree (org-element-parse-buffer 'headline))) + (org-element-map parse-tree 'headline + (lambda (hl) + (let ((headline-text (org-element-property :raw-value hl)) + (begin-pos (org-element-property :begin hl))) + (dolist (prop props) + (let ((timestamp (org-element-property (intern (downcase prop)) hl))) + (when timestamp + (let ((time-str (org-element-property :raw-value timestamp))) + (unless (ignore-errors (org-time-string-to-absolute time-str)) + (push (list file begin-pos headline-text prop time-str) invalid-entries)))))) + (let ((contents-begin (org-element-property :contents-begin hl)) + (contents-end (org-element-property :contents-end hl))) + (when (and contents-begin contents-end) + (save-excursion + (goto-char contents-begin) + (while (re-search-forward org-ts-regexp contents-end t) + (let ((ts-string (match-string 0))) + (unless (ignore-errors (org-time-string-to-absolute ts-string)) + (push (list file begin-pos headline-text "inline timestamp" ts-string) invalid-entries)))))))))) + + (with-current-buffer report-buffer + (insert (format "* %s\n" file)) + (if invalid-entries + (dolist (entry (reverse invalid-entries)) + (cl-destructuring-bind (f pos head prop ts) entry + (insert (format "- [[file:%s::%d][%s]]\n - Property/Type: %s\n - Invalid timestamp: \"%s\"\n" + f pos head prop ts)))) + (insert "No invalid timestamps found.\n"))) + (with-current-buffer report-buffer (insert "\n"))))) + (pop-to-buffer report-buffer))) ;; --------------------------- Org-Alert-Check Timers -------------------------- @@ -370,174 +340,20 @@ entries, property/type, and raw timestamp string." "List all active timers running `org-alert-check' with next run time." (interactive) (let ((timers (cl-remove-if-not - (lambda (timer) - (eq (timer--function timer) #'org-alert-check)) - timer-list))) - (if timers - (let ((lines - (mapcar - (lambda (timer) - (let* ((next-run (timer--time timer)) - (next-run-str (format-time-string "%Y-%m-%d %H:%M:%S" next-run))) - (format "Timer next runs at: %s" next-run-str))) - timers))) - (message "org-alert-check timers:\n%s" (string-join lines "\n"))) - (message "No org-alert-check timers found.")))) - -;; ------------------------------- Sqlite Tracing ------------------------------ - -(defvar cj/sqlite-tracing-enabled nil) -(defvar cj/sqlite--db-origins (make-hash-table :test 'eq :weakness 'key)) - -(defun cj/capture-backtrace () - "Capture and return the current stack trace as a list of function names. -Returns a list containing function names from the backtrace, or a fallback -message if backtrace capture fails or is unavailable." - (condition-case nil - (if (fboundp 'backtrace-frames) - (mapcar (lambda (fr) (car fr)) (backtrace-frames)) - (list "no-backtrace-frames")) - (error (list "failed-to-capture-backtrace")))) - -(defun cj/take (n xs) - "Return the first N elements from list XS. -If XS has fewer than N elements, return all elements." - (cl-subseq xs 0 (min n (length xs)))) - -(defun cj--ad-sqlite-open (orig file &rest opts) - "Advice function wrapping \='sqlite-open\=' to track database origins. -ORIG is the original function, FILE is the database file path, and OPTS are -additional options. Records database handle with metadata (file, time, location, -and backtrace) in \='cj/sqlite--db-origins\=' for debugging purposes." - (let ((db (apply orig file opts))) - (puthash db - (list :file file - :opts opts - :where (or load-file-name buffer-file-name) - :time (current-time-string) - :stack (cj/capture-backtrace)) - cj/sqlite--db-origins) - db)) - -(defun cj--ad-sqlite-close (orig db &rest args) - "Advice function wrapping \='sqlite-close\=' to log database closure. -ORIG is the original function, DB is the database handle, and ARGS are -additional arguments. Logs information about when and where the database was -originally opened before closing it." - (let ((info (gethash db cj/sqlite--db-origins))) - (when info - (message "cj/sqlite: closing %s opened at %s by %s" - (plist-get info :file) - (plist-get info :time) - (or (plist-get info :where) "unknown")))) - (apply orig db args)) - -(defun cj--ad-set-finalizer (orig obj fn) - "Advice function wrapping \='set-finalizer\=' to debug finalizer failures. -ORIG is the original function, OBJ is the object to finalize, and FN is the -finalizer function. Wraps the finalizer to capture and log detailed diagnostic -information (creation time, location, call stack, and SQLite database info if -applicable) when finalizers fail, then re-signals the error." - (let* ((origin (list :time (current-time-string) - :where (or load-file-name buffer-file-name) - :stack (cj/capture-backtrace) - :sqlite-open (when (and (fboundp 'sqlitep) - (ignore-errors (sqlitep obj))) - (gethash obj cj/sqlite--db-origins)))) - (wrapped - (lambda (&rest args) - (condition-case err - (apply fn args) - (error - (let* ((stack (cj/take 8 (plist-get origin :stack))) - (dbi (plist-get origin :sqlite-open)) - (extra (if dbi - (format " db=%s opened at %s by %s" - (plist-get dbi :file) - (plist-get dbi :time) - (or (plist-get dbi :where) "unknown")) - ""))) - (message "cj/finalizer: failed; created at %s (%s); callers=%S;%s; error=%S" - (plist-get origin :time) - (or (plist-get origin :where) "unknown") - stack extra err)) - ;; Re-signal so Emacs still shows the standard finalizer message. - (signal (car err) (cdr err))))))) - (funcall orig obj wrapped))) - -(defun cj/sqlite-tracing-enable () - "Enable tracing of sqlite opens/closes and annotate failing finalizers." - (interactive) - (unless cj/sqlite-tracing-enabled - (setq cj/sqlite-tracing-enabled t) - (advice-add 'set-finalizer :around #'cj--ad-set-finalizer) - (when (fboundp 'sqlite-open) - (advice-add 'sqlite-open :around #'cj--ad-sqlite-open) - (advice-add 'sqlite-close :around #'cj--ad-sqlite-close)) - (message "cj/sqlite tracing enabled"))) - -(defun cj/sqlite-tracing-disable () - "Disable sqlite/finalizer tracing and clear recorded origins." - (interactive) - (setq cj/sqlite-tracing-enabled nil) - (ignore-errors (advice-remove 'set-finalizer #'cj--ad-set-finalizer)) - (when (fboundp 'sqlite-open) - (ignore-errors (advice-remove 'sqlite-open #'cj--ad-sqlite-open)) - (ignore-errors (advice-remove 'sqlite-close #'cj--ad-sqlite-close))) - (clrhash cj/sqlite--db-origins) - (message "cj/sqlite tracing disabled")) - -(cj/sqlite-tracing-enable) -(setq debug-on-message (rx bos "finalizer failed")) - -;; ----------------------------- Explain Pause Mode ---------------------------- -;; Performance profiling tool to identify what's causing Emacs to pause/hang -;; Usage: -;; 1. Enable: M-x explain-pause-mode -;; 2. Perform the slow operation (e.g., press F8 for agenda) -;; 3. View report: M-x explain-pause-top -;; 4. Disable when done: M-x explain-pause-mode - -;; (add-to-list 'load-path (expand-file-name "~/code/explain-pause-mode")) - -;; (use-package explain-pause-mode -;; :ensure nil ;; local package -;; :init -;; (keymap-global-unset "<f2>") -;; :demand t -;; :commands (explain-pause-mode explain-pause-top) -;; :bind -;; ("<f2>" . explain-pause-mode) -;; ("C-<f2>" . explain-pause-top) -;; :config -;; ;; Consider commands slow if they take longer than 40ms (default) -;; (setq explain-pause-slow-too-long-ms 40) - -;; ;; Auto-refresh the top buffer every 2 seconds -;; (setq explain-pause-top-auto-refresh-interval 2)) - -;; ;; Quick access function for profiling org-agenda -;; (defun profile-agenda-with-explain-pause () -;; "Enable explain-pause-mode, run org-agenda, and show the report." -;; (interactive) -;; (unless explain-pause-mode -;; (explain-pause-mode 1)) -;; (message "explain-pause-mode enabled. Generating agenda...") -;; (sit-for 0.5) ;; brief pause so message is visible -;; (org-agenda nil "d") -;; (sit-for 1) ;; let agenda finish rendering -;; (explain-pause-top)) - - -;; --------------------- Debug Code For Package Signatures --------------------- -;; from https://emacs.stackexchange.com/questions/233/how-to-proceed-on-package-el-signature-check-failure - -;; Set package-check-signature to nil, e.g., M-: (setq package-check-signature nil) RET. -;; Download the package gnu-elpa-keyring-update and run the function with the same name, e.g., M-x package-install RET gnu-elpa-keyring-update RET. -;; Reset package-check-signature to the default value allow-unsigned, e.g., M-: (setq package-check-signature 'allow-unsigned) RET. - -;; (setq package-check-signature nil) -;; (setq package-check-signature 'allow-unsigned) + (lambda (timer) + (eq (timer--function timer) #'org-alert-check)) + timer-list))) + (if timers + (let ((lines + (mapcar + (lambda (timer) + (let* ((next-run (timer--time timer)) + (next-run-str (format-time-string "%Y-%m-%d %H:%M:%S" next-run))) + (format "Timer next runs at: %s" next-run-str))) + timers))) + (message "org-alert-check timers:\n%s" (string-join lines "\n"))) + (message "No org-alert-check timers found.")))) + (provide 'config-utilities) ;;; config-utilities.el ends here |
