From d683d3cbf79797877694483c38992476a6e31aca Mon Sep 17 00:00:00 2001 From: kj Date: Sat, 19 Nov 2022 14:53:04 -0400 Subject: [PATCH] Fix flycheck + eglot integration. --- configs/init-eglot.el | 108 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 9 deletions(-) diff --git a/configs/init-eglot.el b/configs/init-eglot.el index 49a45f8..9e081c6 100644 --- a/configs/init-eglot.el +++ b/configs/init-eglot.el @@ -15,27 +15,117 @@ :config (add-to-list 'eglot-server-programs '(php-mode . ("intelephense" "--stdio"))) + + ;; Integrate flycheck and eglot (code from doomemacs) + (cl-defstruct (flycheck-error + (:constructor flycheck-error-new) + (:constructor flycheck-error-new-at + (line column + &optional level message + &key checker id group beg-pos end-pos end-line end-column + (filename (buffer-file-name)) + (buffer (current-buffer))))) + "Structure representing an error reported by a syntax checker. +Slots: +`buffer' + The buffer that the error was reported for, as buffer object. +`checker' + The syntax checker which reported this error, as symbol. +`filename' + The file name the error refers to, as string. +`line' + The line number the error refers to, as number. +`column' (optional) + The column number the error refers to, as number. + For compatibility with external tools and unlike Emacs + itself (e.g. in Compile Mode) Flycheck uses _1-based_ + columns: The first character on a line is column 1. + Occasionally some tools try to proactively adapt to Emacs + and emit 0-based columns automatically. In these cases, the + columns must be adjusted for Flycheck, see + `flycheck-increment-error-columns'. +`beg-pos' (optional) + The begining position of the error, if provided by the checker. +`end-pos' (optional) + The end position of the error, if provided by the checker. +`end-line' (optional) + The end line of the error, if provided by the checker. +`end-column' (optional) + The end column of the error, if provided by the checker. +`message' (optional) + The error message as a string, if any. +`level' + The error level, as either `info', `warning' or `error'. +`id' (optional) + An ID identifying the kind of error. +`group` (optional) + A symbol identifying the group the error belongs to. + Some tools will emit multiple errors that relate to the same + issue (e.g., lifetime errors in Rust). All related errors + collected by a checker should have the same `group` value, + in order to be able to present them to the user. + See `flycheck-related-errors`." + buffer checker filename line column message level id group beg-pos end-pos end-line end-column) + + (defun flycheck-error-thing-region (thing err) + "Get the region of THING at the column of ERR. +ERR is a Flycheck error whose region to get. THING is a +understood by `thing-at-point'. +If the error has beg-pos and end-pos in it, use them. Otherwise, +return a cons cell `(BEG . END)' where BEG is the beginning of +the THING at the error column, and END the end of the symbol. If +ERR has no error column, or if there is no THING at this column, +return nil." + (-when-let (column (car (flycheck-error-column-region err))) + (flycheck-error-with-buffer err + (save-excursion + (save-restriction + (widen) + (goto-char column) + (or + (and (flycheck-error-end-pos err) + (flycheck-error-beg-pos err) + (cons (flycheck-error-beg-pos err) + (flycheck-error-end-pos err))) + (bounds-of-thing-at-point thing))))))) + (defvar-local flycheck-eglot-current-errors nil) - ;; Use flycheck (https://gist.github.com/purcell/ca33abbea9a98bb0f8a04d790a0cadcd) + (defun flycheck-position-to-line-column (point) + "Return a (LINE . COLUMN) cons corresponding to POINT." + (let ((inhibit-field-text-motion t)) + (save-excursion + (goto-char point) + (cons (line-number-at-pos) (1+ (- (point) (line-beginning-position))))))) + (defun flycheck-eglot-report-fn (diags &rest _) + "Convert flymake eglot errors to flycheck errors. +DIAGS are the diags that flymake provided." (setq flycheck-eglot-current-errors (mapcar (lambda (diag) (save-excursion (goto-char (flymake--diag-beg diag)) - (flycheck-error-new-at (line-number-at-pos) - (1+ (- (point) (line-beginning-position))) + (flycheck-error-new-at (line-number-at-pos) ;; will be ignored + (1+ (current-column)) ;; will be ignored (pcase (flymake--diag-type diag) ('eglot-error 'error) ('eglot-warning 'warning) ('eglot-note 'info) (_ (error "Unknown diag type, %S" diag))) (flymake--diag-text diag) - :checker 'eglot))) + :checker 'eglot + :end-line (car (flycheck-position-to-line-column (flymake--diag-end diag))) + :end-column (cdr (flycheck-position-to-line-column (flymake--diag-end diag))) + :beg-pos (copy-marker (flymake--diag-beg diag) t) + :end-pos (copy-marker (flymake--diag-end diag))))) diags)) (flycheck-buffer)) (defun flycheck-eglot--start (checker callback) + "Clean up errors when done. +CHECKER is the checker, which is unused because we know that it +is eglot. CALLBACK is the function that we need to call when we +are done, on all the errors." (funcall callback 'finished flycheck-eglot-current-errors)) (defun flycheck-eglot--available-p () @@ -49,16 +139,16 @@ (push 'eglot flycheck-checkers) - (defun sanityinc/eglot-prefer-flycheck () + (defun +doom/eglot-prefer-flycheck-h () (when eglot--managed-mode + (when-let ((current-checker (flycheck-get-checker-for-buffer))) + (flycheck-add-next-checker 'eglot current-checker)) (flycheck-add-mode 'eglot major-mode) - (flycheck-select-checker 'eglot) - (flycheck-mode) + (flycheck-mode 1) (flymake-mode -1) (setq eglot--current-flymake-report-fn 'flycheck-eglot-report-fn))) - (add-hook 'eglot--managed-mode-hook 'sanityinc/eglot-prefer-flycheck) - ) + (add-hook 'eglot--managed-mode-hook #'+doom/eglot-prefer-flycheck-h)) ;; Emmet (mientras veo como hacer funcionar emmet-ls) (use-package emmet-mode