From 59bd7c7ea3636100d0984134a0cf7815ddcdc7c2 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 10 Jun 2024 17:18:13 -0400 Subject: [PATCH] lisp/editorconfig: Use new Emacs-30 hooks * lisp/editorconfig.el (editorconfig--get-coding-system) (editorconfig--get-dir-local-variables): New functions. (editorconfig-mode): Use them if possible. (editorconfig-hack-properties-functions only) (editorconfig-after-apply-functions): Define only when the old advice is used, since the new hooks don't support them. (cherry picked from commit 624ba9fce0624fa1c82a52d9852ecd74a9f3c6c1) --- lisp/editorconfig.el | 127 ++++++++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 37 deletions(-) diff --git a/lisp/editorconfig.el b/lisp/editorconfig.el index cf55f0b3218..037d8aee0a4 100644 --- a/lisp/editorconfig.el +++ b/lisp/editorconfig.el @@ -72,16 +72,17 @@ coding styles between different editors and IDEs." :prefix "editorconfig-" :group 'tools) -(define-obsolete-variable-alias - 'edconf-custom-hooks - 'editorconfig-after-apply-functions - "0.5") -(define-obsolete-variable-alias - 'editorconfig-custom-hooks - 'editorconfig-after-apply-functions - "0.7.14") -(defcustom editorconfig-after-apply-functions () - "A list of functions after loading common EditorConfig settings. +(when (< emacs-major-version 30) + (define-obsolete-variable-alias + 'edconf-custom-hooks + 'editorconfig-after-apply-functions + "0.5") + (define-obsolete-variable-alias + 'editorconfig-custom-hooks + 'editorconfig-after-apply-functions + "0.7.14") + (defcustom editorconfig-after-apply-functions () + "A list of functions after loading common EditorConfig settings. Each element in this list is a hook function. This hook function takes one parameter, which is a property hash table. The value @@ -100,10 +101,11 @@ show line numbers on the left: This hook will be run even when there are no matching sections in \".editorconfig\", or no \".editorconfig\" file was found at all." - :type 'hook) + :type 'hook)) -(defcustom editorconfig-hack-properties-functions () - "A list of function to alter property values before applying them. +(when (< emacs-major-version 30) + (defcustom editorconfig-hack-properties-functions () + "A list of function to alter property values before applying them. These functions will be run after loading \".editorconfig\" files and before applying them to current buffer, so that you can alter some properties from @@ -122,12 +124,10 @@ overwrite \"indent_style\" property when current `major-mode' is a This hook will be run even when there are no matching sections in \".editorconfig\", or no \".editorconfig\" file was found at all." - :type 'hook) + :type 'hook)) (make-obsolete-variable 'editorconfig-hack-properties-functions - "Using `editorconfig-after-apply-functions' instead is recommended, - because since 2021/08/30 (v0.9.0) this variable cannot support all properties: - charset values will be referenced before running this hook." - "v0.9.0") + 'editorconfig-get-local-variables-functions + "2024") (define-obsolete-variable-alias 'edconf-indentation-alist @@ -641,30 +641,83 @@ F is that function, and FILENAME and ARGS are arguments passed to F." (format "Error while setting variables from EditorConfig: %S" err)))) ret)) +(defvar editorconfig--getting-coding-system nil) + +(defun editorconfig--get-coding-system (&optional _size) + "Return the coding system to use according to EditorConfig. +Meant to be used on `auto-coding-functions'." + (defvar auto-coding-file-name) ;; Emacs≥30 + (when (and (stringp auto-coding-file-name) + (file-name-absolute-p auto-coding-file-name) + ;; Don't recurse infinitely. + (not (member auto-coding-file-name + editorconfig--getting-coding-system))) + (let* ((editorconfig--getting-coding-system + (cons auto-coding-file-name editorconfig--getting-coding-system)) + (props (editorconfig-call-get-properties-function + auto-coding-file-name))) + (editorconfig-merge-coding-systems (gethash 'end_of_line props) + (gethash 'charset props))))) + +(defun editorconfig--get-dir-local-variables () + "Return the directory local variables specified via EditorConfig. +Meant to be used on `hack-dir-local-get-variables-functions'." + (when (stringp buffer-file-name) + (let* ((props (editorconfig-call-get-properties-function buffer-file-name)) + (alist (editorconfig--get-local-variables props))) + ;; FIXME: If there's `/foo/.editorconfig', `/foo/bar/.dir-locals.el', + ;; and `/foo/bar/baz/.editorconfig', it would be nice to return two + ;; pairs here, so that hack-dir-local can give different priorities + ;; to the `/foo/.editorconfig' settings compared to those of + ;; `/foo/bar/baz/.editorconfig', but we can't just convert the + ;; settings from each file individually and let hack-dir-local merge + ;; them because hack-dir-local doesn't have the notion of "unset", + ;; and because the conversion of `indent_size' depends on `tab_width'. + (when alist + (cons + (file-name-directory (editorconfig-core-get-nearest-editorconfig + buffer-file-name)) + alist))))) ;;;###autoload (define-minor-mode editorconfig-mode "Toggle EditorConfig feature." :global t - (let ((modehooks '(prog-mode-hook - text-mode-hook - ;; Some modes call `kill-all-local-variables' in their init - ;; code, which clears some values set by editorconfig. - ;; For those modes, editorconfig-apply need to be called - ;; explicitly through their hooks. - rpm-spec-mode-hook))) - (if editorconfig-mode - (progn - (advice-add 'find-file-noselect :around 'editorconfig--advice-find-file-noselect) - (advice-add 'insert-file-contents :around 'editorconfig--advice-insert-file-contents) - (dolist (hook modehooks) - (add-hook hook - 'editorconfig-major-mode-hook - t))) - (advice-remove 'find-file-noselect 'editorconfig--advice-find-file-noselect) - (advice-remove 'insert-file-contents 'editorconfig--advice-insert-file-contents) - (dolist (hook modehooks) - (remove-hook hook 'editorconfig-major-mode-hook))))) + (if (boundp 'hack-dir-local-get-variables-functions) ;Emacs≥30 + (if editorconfig-mode + (progn + (add-hook 'hack-dir-local-get-variables-functions + ;; Give them slightly lower precedence than settings from + ;; `dir-locals.el'. + #'editorconfig--get-dir-local-variables t) + ;; `auto-coding-functions' also exists in Emacs<30 but without + ;; access to the file's name via `auto-coding-file-name'. + (add-hook 'auto-coding-functions + #'editorconfig--get-coding-system)) + (remove-hook 'hack-dir-local-get-variables-functions + #'editorconfig--get-dir-local-variables) + (remove-hook 'auto-coding-functions + #'editorconfig--get-coding-system)) + ;; Emacs<30 + (let ((modehooks '(prog-mode-hook + text-mode-hook + ;; Some modes call `kill-all-local-variables' in their init + ;; code, which clears some values set by editorconfig. + ;; For those modes, editorconfig-apply need to be called + ;; explicitly through their hooks. + rpm-spec-mode-hook))) + (if editorconfig-mode + (progn + (advice-add 'find-file-noselect :around #'editorconfig--advice-find-file-noselect) + (advice-add 'insert-file-contents :around #'editorconfig--advice-insert-file-contents) + (dolist (hook modehooks) + (add-hook hook + #'editorconfig-major-mode-hook + t))) + (advice-remove 'find-file-noselect #'editorconfig--advice-find-file-noselect) + (advice-remove 'insert-file-contents #'editorconfig--advice-insert-file-contents) + (dolist (hook modehooks) + (remove-hook hook #'editorconfig-major-mode-hook)))))) ;; (defconst editorconfig--version -- 2.39.2