diff --git a/.config.d/10-completion.el b/.config.d/10-completion.el index 8aefc72..3c41292 100644 --- a/.config.d/10-completion.el +++ b/.config.d/10-completion.el @@ -225,8 +225,8 @@ consult-theme :preview-key '(:debounce 0.2 any) consult-ripgrep consult-git-grep consult-grep consult-bookmark consult-recent-file consult-xref - consult--source-bookmark consult--source-file-register - consult--source-recent-file consult--source-project-recent-file + consult-source-bookmark consult-source-file-register + consult-source-recent-file consult-source-project-recent-file ;; :preview-key "M-." :preview-key '(:debounce 0.4 any)) (setq consult-narrow-key "<")) diff --git a/.config.d/15-lsp.el b/.config.d/15-lsp.el index 6121b88..45cc223 100644 --- a/.config.d/15-lsp.el +++ b/.config.d/15-lsp.el @@ -170,7 +170,7 @@ control codes are not supported." ;; Configure Tempel (use-package tempel - :bind (("M-+" . tempel-complete) ;; Alternative tempel-expand + :bind (("C-S-e" . tempel-complete) ;; Alternative tempel-expand ("M-*" . tempel-insert)) :init diff --git a/.config.d/99-external-misc.el b/.config.d/99-external-misc.el new file mode 100644 index 0000000..200cfbd --- /dev/null +++ b/.config.d/99-external-misc.el @@ -0,0 +1,178 @@ +;;; 99-external-misc.el --- Miscellaneous functions made by others -*- lexical-binding: t -*- + +;; This file is not part of GNU Emacs + +;;; Commentary: + +;; This file contains various useful functions and macros that I definitely +;; didn't write and took from somewhere as-is. + +;;; Code: + +(defun second (item) + (nth 1 item)) + +(defun third (item) + (nth 2 item)) + +(defun fourth (item) + (nth 3 item)) + +;; Source: https://phillord.github.io/m-buffer-el/#sec-5-1-2 +;;;###autoload +(cl-defmacro bench (&optional (times 100000) &rest body) + "Call `benchmark-run-compiled' on BODY with TIMES iterations, returning list suitable for Org source block evaluation. +Garbage is collected before calling `benchmark-run-compiled' to +avoid counting existing garbage which needs collection." + (declare (indent defun)) + `(progn + (garbage-collect) + (list '("Total runtime" "# of GCs" "Total GC runtime") + 'hline + (benchmark-run-compiled ,times + (progn + ,@body))))) + +;; Source: alphapapa.github.io/emacs-package-dev-handbook/#outline-container-bench-multi-macros +;;;###autoload +(cl-defmacro bench-multi (&key (times 1) forms ensure-equal raw) + "Return Org table as a list with benchmark results for FORMS. +Runs FORMS with `benchmark-run-compiled' for TIMES iterations. + +When ENSURE-EQUAL is non-nil, the results of FORMS are compared, +and an error is raised if they aren't `equal'. If the results are +sequences, the difference between them is shown with +`seq-difference'. + +When RAW is non-nil, the raw results from +`benchmark-run-compiled' are returned instead of an Org table +list. + +If the first element of a form is a string, it's used as the +form's description in the bench-multi-results; otherwise, forms +are numbered from 0. + +Before each form is run, `garbage-collect' is called. + +See source for a usage example." + ;; MAYBE: Since `bench-multi-lexical' byte-compiles the file, I'm not sure if + ;; `benchmark-run-compiled' is necessary over `benchmark-run', or if it matters. + (declare (indent defun)) + (let*((keys (gensym "keys")) + (result-times (gensym "result-times")) + (header '(("Form" "x fastest" "Total runtime" "# of GCs" "Total GC runtime") + hline)) + ;; Copy forms so that a subsequent call of the macro will get the original forms. + (forms (cl-copy-list forms)) + (descriptions (cl-loop for form in forms + for i from 0 + collect (if (stringp (car form)) + (prog1 (car form) + (setf (nth i forms) (cadr (nth i forms)))) + i)))) + `(unwind-protect + (progn + (defvar bench-multi-results nil) + (let* ((bench-multi-results (make-hash-table)) + (,result-times (sort (list ,@(cl-loop for form in forms + for i from 0 + for description = (nth i descriptions) + collect `(progn + (garbage-collect) + (cons ,description + (benchmark-run-compiled ,times + ,(if ensure-equal + `(puthash ,description ,form bench-multi-results) + form)))))) + (lambda (a b) + (< (nth 1 a) (nth 1 b)))))) + ,(when ensure-equal + `(cl-loop with ,keys = (hash-table-keys bench-multi-results) + for i from 0 to (- (length ,keys) 2) + unless (equal (gethash (nth i ,keys) bench-multi-results) + (gethash (nth (1+ i) ,keys) bench-multi-results)) + do (if (sequencep (gethash (car (hash-table-keys bench-multi-results)) bench-multi-results)) + (let* ((k1) (k2) + ;; If the difference in one order is nil, try in other order. + (difference (or (setq k1 (nth i ,keys) + k2 (nth (1+ i) ,keys) + difference (seq-difference (gethash k1 bench-multi-results) + (gethash k2 bench-multi-results))) + (setq k1 (nth (1+ i) ,keys) + k2 (nth i ,keys) + difference (seq-difference (gethash k1 bench-multi-results) + (gethash k2 bench-multi-results)))))) + (user-error "Forms' bench-multi-results not equal: difference (%s - %s): %S" + k1 k2 difference)) + ;; Not a sequence + (user-error "Forms' bench-multi-results not equal: %s:%S %s:%S" + (nth i ,keys) (nth (1+ i) ,keys) + (gethash (nth i ,keys) bench-multi-results) + (gethash (nth (1+ i) ,keys) bench-multi-results))))) + ;; Add factors to times and return table + (if ,raw + ,result-times + (append ',header + (bench-multi-process-results ,result-times))))) + (unintern 'bench-multi-results nil)))) + +;; Use like this: +;; (bench-multi +;; :forms (("org-map-entries" (sort (org-map-entries (lambda () +;; (nth 4 (org-heading-components))) +;; "/+MAYBE" 'agenda) +;; #'string<)) +;; ("regexp" (sort (-flatten +;; (-non-nil +;; (mapcar (lambda (file) +;; (let ((case-fold-search t)) +;; (with-current-buffer (find-buffer-visiting file) +;; (org-with-wide-buffer +;; (goto-char (point-min)) +;; (cl-loop with regexp = (format org-heading-keyword-regexp-format "MAYBE") +;; while (re-search-forward regexp nil t) +;; collect (nth 4 (org-heading-components))))))) +;; (org-agenda-files)))) +;; #'string<)))) + +(defun bench-multi-process-results (results) + "Return sorted RESULTS with factors added." + (setq results (sort results (-on #'< #'second))) + (cl-loop with length = (length results) + for i from 0 below length + for description = (car (nth i results)) + for factor = (pcase i + (0 "fastest") + (_ (format "%.2f" (/ (second (nth i results)) + (second (nth 0 results)))))) + collect (append (list description factor) + (list (format "%.6f" (second (nth i results))) + (third (nth i results)) + (if (> (fourth (nth i results)) 0) + (format "%.6f" (fourth (nth i results))) + 0))))) + +;;;###autoload +(cl-defmacro bench-multi-lexical (&key (times 1) forms ensure-equal raw) + "Return Org table as a list with benchmark results for FORMS. +Runs FORMS from a byte-compiled temp file with `lexical-binding' +enabled, using `bench-multi', which see. + +Afterward, the temp file is deleted and the function used to run +the benchmark is uninterned." + (declare (indent defun)) + `(let* ((temp-file (concat (make-temp-file "bench-multi-lexical-") ".el")) + (fn (gensym "bench-multi-lexical-run-"))) + (with-temp-file temp-file + (insert ";; -*- lexical-binding: t; -*-" "\n\n" + "(defvar bench-multi-results)" "\n\n" + (format "(defun %s () (bench-multi :times %d :ensure-equal %s :raw %s :forms %S))" + fn ,times ,ensure-equal ,raw ',forms))) + (unwind-protect + (if (byte-compile-file temp-file 'load) + (funcall (intern (symbol-name fn))) + (user-error "Error byte-compiling and loading temp file")) + (delete-file temp-file) + (unintern (symbol-name fn) nil)))) + +;;; 99-external-misc.el ends here diff --git a/.config.d/99-external-misc.elc b/.config.d/99-external-misc.elc new file mode 100644 index 0000000..e75bdf8 Binary files /dev/null and b/.config.d/99-external-misc.elc differ diff --git a/.gitignore b/.gitignore index 0202525..77202c3 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ !.config.d/ !.config.d/* !templates +!load/ diff --git a/templates b/templates index 6a09549..6538397 100644 --- a/templates +++ b/templates @@ -1,3 +1,10 @@ emacs-lisp-mode (up "(use-package " p n> ":ensure t" n> ":defer t" n ")") + +rust-mode + +(str "struct " p " {" n> p n> "}") +(imp "impl " p " {" n> p n> "}") +(impf "impl " p " for " p " {" n> p n> "}") +(trt "trait " p " {" n> p n> "}")