diff --git a/modules/lang/emacs-lisp/autoload.el b/modules/lang/emacs-lisp/autoload.el index 2191695c2..896cf574a 100644 --- a/modules/lang/emacs-lisp/autoload.el +++ b/modules/lang/emacs-lisp/autoload.el @@ -22,50 +22,6 @@ to a pop up buffer." (error (error-message-string e)))) (current-buffer))) -(defvar +emacs-lisp--face nil) -;;;###autoload -(defun +emacs-lisp-highlight-vars-and-faces (end) - "Match defined variables and functions. - -Functions are differentiated into special forms, built-in functions and -library/userland functions" - (catch 'matcher - (while (re-search-forward "\\(?:\\sw\\|\\s_\\)+" end t) - (let ((ppss (save-excursion (syntax-ppss)))) - (cond ((nth 3 ppss) ; strings - (search-forward "\"" end t)) - ((nth 4 ppss) ; comments - (forward-line +1)) - ((let ((symbol (intern-soft (match-string-no-properties 0)))) - (and (cond ((null symbol) nil) - ((eq symbol t) nil) - ((special-variable-p symbol) - (setq +emacs-lisp--face 'font-lock-variable-name-face)) - ((and (fboundp symbol) - (eq (char-before (match-beginning 0)) ?\() - (not (memq (char-before (1- (match-beginning 0))) - (list ?\' ?\`)))) - (let ((unaliased (indirect-function symbol))) - (unless (or (macrop unaliased) - (special-form-p unaliased)) - (let (unadvised) - (while (not (eq (setq unadvised (ad-get-orig-definition unaliased)) - (setq unaliased (indirect-function unadvised))))) - unaliased) - (setq +emacs-lisp--face - (if (subrp unaliased) - 'font-lock-constant-face - 'font-lock-function-name-face)))))) - (throw 'matcher t))))))) - nil)) - -;; `+emacs-lisp-highlight-vars-and-faces' is a potentially expensive function -;; and should be byte-compiled, no matter what, to ensure it runs as fast as -;; possible: -(unless (byte-code-function-p (symbol-function '+emacs-lisp-highlight-vars-and-faces)) - (with-no-warnings - (byte-compile #'+emacs-lisp-highlight-vars-and-faces))) - ;; ;;; Handlers @@ -230,6 +186,14 @@ https://emacs.stackexchange.com/questions/10230/how-to-indent-keywords-aligned" ;; ;;; Hooks +(autoload 'straight-register-file-modification "straight") +;;;###autoload +(defun +emacs-lisp-init-straight-maybe-h () + "Make sure straight sees modifications to installed packages." + (when (file-in-directory-p (or buffer-file-name default-directory) doom-local-dir) + (add-hook 'after-save-hook #'straight-register-file-modification + nil 'local))) + ;;;###autoload (defun +emacs-lisp-extend-imenu-h () "Improve imenu support in `emacs-lisp-mode', including recognition for Doom's API." @@ -277,6 +241,10 @@ verbosity when editing a file in `doom-private-dir' or `doom-emacs-dir'." (default-value 'flycheck-emacs-lisp-check-form) ")")))) + +;; +;;; Fontification + ;;;###autoload (defun +emacs-lisp-truncate-pin () "Truncates long SHA1 hashes in `package!' :pin's." @@ -290,3 +258,47 @@ verbosity when editing a file in `doom-private-dir' or `doom-emacs-dir'." (when (and start finish) (put-text-property start finish 'display "..."))))) nil) + +(defvar +emacs-lisp--face nil) +;;;###autoload +(defun +emacs-lisp-highlight-vars-and-faces (end) + "Match defined variables and functions. + +Functions are differentiated into special forms, built-in functions and +library/userland functions" + (catch 'matcher + (while (re-search-forward "\\(?:\\sw\\|\\s_\\)+" end t) + (let ((ppss (save-excursion (syntax-ppss)))) + (cond ((nth 3 ppss) ; strings + (search-forward "\"" end t)) + ((nth 4 ppss) ; comments + (forward-line +1)) + ((let ((symbol (intern-soft (match-string-no-properties 0)))) + (and (cond ((null symbol) nil) + ((eq symbol t) nil) + ((special-variable-p symbol) + (setq +emacs-lisp--face 'font-lock-variable-name-face)) + ((and (fboundp symbol) + (eq (char-before (match-beginning 0)) ?\() + (not (memq (char-before (1- (match-beginning 0))) + (list ?\' ?\`)))) + (let ((unaliased (indirect-function symbol))) + (unless (or (macrop unaliased) + (special-form-p unaliased)) + (let (unadvised) + (while (not (eq (setq unadvised (ad-get-orig-definition unaliased)) + (setq unaliased (indirect-function unadvised))))) + unaliased) + (setq +emacs-lisp--face + (if (subrp unaliased) + 'font-lock-constant-face + 'font-lock-function-name-face)))))) + (throw 'matcher t))))))) + nil)) + +;; HACK Fontification is already expensive enough. We byte-compile +;; `+emacs-lisp-highlight-vars-and-faces' and `+emacs-lisp-truncate-pin' to +;; ensure they run as fast as possible: +(dolist (fn '(+emacs-lisp-highlight-vars-and-faces +emacs-lisp-truncate-pin)) + (unless (byte-code-function-p (symbol-function fn)) + (with-no-warnings (byte-compile fn)))) diff --git a/modules/lang/emacs-lisp/config.el b/modules/lang/emacs-lisp/config.el index b3748b337..d8b690fd3 100644 --- a/modules/lang/emacs-lisp/config.el +++ b/modules/lang/emacs-lisp/config.el @@ -47,40 +47,39 @@ This marks a foldable marker for `outline-minor-mode' in elisp buffers.") ;; Fixed indenter that intends plists sensibly. lisp-indent-function #'+emacs-lisp-indent-function) - ;; variable-width indentation is superior in elisp - (add-to-list 'doom-detect-indentation-excluded-modes 'emacs-lisp-mode nil #'eq) + ;; variable-width indentation is superior in elisp. Otherwise, `dtrt-indent' + ;; and `editorconfig' would force fixed indentation on elisp. + (add-to-list 'doom-detect-indentation-excluded-modes 'emacs-lisp-mode) (add-hook! 'emacs-lisp-mode-hook + ;; Allow folding of outlines in comments #'outline-minor-mode - ;; fontificiation + ;; Make parenthesis depth easier to distinguish at a glance #'rainbow-delimiters-mode + ;; Make quoted symbols easier to distinguish from free variables #'highlight-quoted-mode - ;; initialization - #'+emacs-lisp-extend-imenu-h) - - (autoload 'straight-register-file-modification "straight") - (add-hook! 'emacs-lisp-mode-hook - (defun +emacs-lisp-init-straight-h () - (when (file-in-directory-p (or buffer-file-name default-directory) doom-local-dir) - (add-hook 'after-save-hook #'straight-register-file-modification - nil 'local)))) + ;; Extend imenu support to Doom constructs + #'+emacs-lisp-extend-imenu-h + ;; Ensure straight sees modifications to installed packages + #'+emacs-lisp-init-straight-maybe-h) ;; Flycheck's two emacs-lisp checkers produce a *lot* of false positives in ;; emacs configs, so we disable `emacs-lisp-checkdoc' and reduce the ;; `emacs-lisp' checker's verbosity. (add-hook 'flycheck-mode-hook #'+emacs-lisp-reduce-flycheck-errors-in-emacs-config-h) - ;; Special syntax highlighting for elisp... + ;; Enhance elisp syntax highlighting, by highlighting Doom-specific + ;; constructs, defined symbols, and truncating :pin's in `package!' calls. (font-lock-add-keywords 'emacs-lisp-mode (append `(;; custom Doom cookies ("^;;;###\\(autodef\\|if\\|package\\)[ \n]" (1 font-lock-warning-face t))) + ;; Shorten the :pin of `package!' statements to 10 characters + `(("(package!\\_>" (0 (+emacs-lisp-truncate-pin)))) ;; highlight defined, special variables & functions (when +emacs-lisp-enable-extra-fontification - `((+emacs-lisp-highlight-vars-and-faces . +emacs-lisp--face))) - - `(("(package!\\_>" (0 (+emacs-lisp-truncate-pin)))))) - + `((+emacs-lisp-highlight-vars-and-faces . +emacs-lisp--face))))) + ;; Recenter window after following definition (advice-add #'elisp-def :after #'doom-recenter-a) @@ -90,17 +89,13 @@ This marks a foldable marker for `outline-minor-mode' in elisp buffers.") (when-let (ret (funcall orig-fn sym)) (concat ret " " (let* ((truncated " [...]") - (limit (- (frame-width) (length ret) (length truncated) 1)) + (print-escape-newlines t) (str (symbol-value sym)) - (str (prin1-to-string - (if (stringp str) - (replace-regexp-in-string "\n" " " str) - str))) - (str-length (length str)) - (short (< str-length limit))) - (concat (substring (propertize str 'face 'warning) - 0 (if short str-length limit)) - (unless short truncated)))))) + (str (prin1-to-string str)) + (limit (- (frame-width) (length ret) (length truncated) 1))) + (format (format "%%0.%ds%%s" limit) + (propertize str 'face 'warning) + (if (< (length str) limit) "" truncated)))))) (map! :localleader :map emacs-lisp-mode-map @@ -145,6 +140,7 @@ This marks a foldable marker for `outline-minor-mode' in elisp buffers.") ;;;###package overseer (autoload 'overseer-test "overseer" nil t) +;; Properly lazy load overseer by not loading it so early: (remove-hook 'emacs-lisp-mode-hook #'overseer-enable-mode)