init-elisp.el (5566B)
1 ;;; init-elisp.el --- elisp tools -*- lexical-binding: t -*- 2 3 ;;; Commentary: 4 5 ;;; Code: 6 7 ;; find the source of elisp symbol 8 (use-package consult-symbol 9 :straight 10 (consult-symbol :type git 11 :host nil 12 :repo "https://git.trogloxene.org/consult-symbol.git") 13 :init 14 (defun my-consult-symbol-hack (fun) 15 (let ((find-file-visit-truename t)) 16 (funcall fun))) 17 (advice-add #'consult-symbol :around #'my-consult-symbol-hack)) 18 19 ;; from Purcell's Emacs configuration 20 ;; enable some features for lisp files 21 (defun my-maybe-set-readonly () 22 "If this elisp appears to be part of Emacs, then disallow editing." 23 (when-let* ((file (buffer-file-name)) 24 (part-of-emacs-p (or (string-match-p "\\.el\\.gz\\'" file) 25 (string-match-p find-function-C-source-directory file)))) 26 (read-only-mode 1))) 27 (add-hook 'find-file-hook #'my-maybe-set-readonly) 28 29 (defun my-enable-check-parens-on-save () 30 "Run `check-parens' when the current buffer is saved." 31 (add-hook 'after-save-hook #'check-parens nil t)) 32 33 (defvar my-lispy-modes-hook 34 '(my-enable-check-parens-on-save) 35 "Hook run in all Lisp modes.") 36 37 (defun my-lisp-setup () 38 "Enable features useful in any Lisp mode." 39 (run-hooks 'my-lispy-modes-hook)) 40 41 (dolist (hook '(emacs-lisp-mode-hook 42 ielm-mode-hook lisp-mode-hook 43 inferior-lisp-mode-hook lisp-interaction-mode-hook)) 44 (add-hook hook 'my-lisp-setup)) 45 (when (boundp 'eval-expression-minibuffer-setup-hook) 46 (add-hook 'eval-expression-minibuffer-setup-hook #'eldoc-mode)) 47 48 ;; from Purcell's Emacs configuration 49 (my-use-package ielm 50 :straight nil 51 :init 52 ;; jump between ielm and elisp file 53 (defvar-local my-repl-original-buffer nil 54 "Buffer from which we jumped to this REPL.") 55 56 (defvar my-repl-switch-function 'switch-to-buffer) 57 58 (defun my-switch-to-ielm () 59 (interactive) 60 (let ((orig-buffer (current-buffer))) 61 (if (get-buffer "*ielm*") 62 (funcall my-repl-switch-function "*ielm*") 63 (ielm)) 64 (setq my-repl-original-buffer orig-buffer))) 65 66 (defun my-repl-switch-back () 67 "Switch back to the buffer from which we reached this REPL." 68 (interactive) 69 (if my-repl-original-buffer 70 (funcall my-repl-switch-function my-repl-original-buffer) 71 (error "No original buffer")))) 72 73 ;; from Purcell's Emacs configuration 74 (defun my-elisp-headerise () 75 "Add minimal header and footer to an elisp buffer in order to placate flycheck." 76 (interactive) 77 (let ((fname (if (buffer-file-name) 78 (file-name-nondirectory (buffer-file-name)) 79 (error "This buffer is not visiting a file")))) 80 (save-excursion 81 (goto-char (point-min)) 82 (insert ";;; " fname 83 (format " --- %s -*- lexical-binding: t -*-\n\n" (file-name-base fname)) 84 ";;; Commentary:\n\n" 85 ";;; Code:\n\n") 86 (goto-char (point-max)) 87 (insert "\n;;; " fname " ends here\n")))) 88 89 (defun my-elisp-load-this-file () 90 "Load the current file or buffer. 91 The current directory is temporarily added to `load-path'. When there 92 is no current file, eval the current buffer." 93 (interactive) 94 (let ((load-path (cons default-directory load-path)) 95 (file (buffer-file-name))) 96 (if file 97 (progn 98 (let ((buf (current-buffer))) 99 (save-some-buffers nil (lambda () (eq (current-buffer) buf)))) 100 (load-file (buffer-file-name)) 101 (message "Loaded %s" file)) 102 (eval-buffer) 103 (message "Evaluated %s" (current-buffer))))) 104 105 ;; from Protesilaos's Emacs configuration 106 (defun my-elisp-eval-and-print-last-sexp () 107 "Evaluate and print expression before point like `eval-print-last-sexp'. 108 Prepend a comment to the return value. Also copy the return value to 109 the `kill-ring' and set the mark to where point was before inserting the 110 return value." 111 (declare (interactive-only t)) 112 (interactive) 113 (if-let* ((string (thing-at-point 'sexp :no-properties)) 114 (_ (not (string-prefix-p ";" string))) 115 (expression (read string))) 116 (let ((return-value (eval expression))) 117 (kill-new (format "%S" return-value)) 118 (message "Copied: `%S'" return-value) 119 (push-mark (point)) 120 (insert (format "\n%S\n" return-value)) 121 (string-insert-rectangle (+ (mark) 1) (- (point) 1) ";; => ")) 122 (user-error "No expression at point"))) 123 124 (defvar-keymap my-elisp-macroexpand-mode-map 125 :doc "keymap for `my-elisp-macroexpand-mode'." 126 :parent special-mode-map 127 "C-c C-l p" #'my-elisp-pp-macroexpand-last-sexp) 128 129 (define-derived-mode my-elisp-macroexpand-mode emacs-lisp-mode "MacroExpand" 130 "Like `emacs-lisp-mode' but for macroexpanded forms." 131 :interactive nil 132 (read-only-mode 1) 133 (display-line-numbers-mode 1)) 134 135 (defun my-elisp-pp-macroexpand-last-sexp () 136 "Like `pp-macroexpand-last-sexp' but with a generic `display-buffer'. 137 Now use `display-buffer-alist' like the Lisp gods intended." 138 (declare (interactive-only t)) 139 (interactive) 140 (if-let* ((thing (thing-at-point 'sexp :no-properties)) 141 (expression (read thing)) 142 (buffer (get-buffer-create "*my-elisp-macroexpand*")) 143 (inhibit-read-only t)) 144 (progn 145 (with-current-buffer buffer 146 (erase-buffer) 147 (insert (format "%S" (macroexpand-1 expression))) 148 (my-elisp-macroexpand-mode) 149 (pp-buffer)) 150 (display-buffer buffer)) 151 (user-error "No expression to macroexpand"))) 152 153 (provide 'init-elisp) 154 ;;; init-elisp.el ends here