Skip to content

Latest commit

 

History

History
292 lines (223 loc) · 7.93 KB

wal-fix.org

File metadata and controls

292 lines (223 loc) · 7.93 KB

Fixing Things

Please let me know when I screwed up. I promise I will learn.

Header

;;; wal-fix.el --- Fixing things. -*- lexical-binding: t -*-

;;; Commentary:
;;
;; Provide fixing packages.

;;; Code:

(eval-when-compile
  (require 'wal-useful nil t)
  (require 'wal-key-bindings nil t))

(declare-function ambassador "wal-key-bindings.el")
(declare-function flycheck-buffer-nonempty-p "ext:flycheck.el")
(declare-function flycheck-error-line "ext:flycheck.el")
(declare-function flycheck-error-message "ext:flycheck.el")
(declare-function flycheck-mode "ext:flycheck.el")
(declare-function flycheck-parse-stylelint "ext:flycheck.el")
(declare-function wal-key-combo-for-leader "wal-key-bindings.el")
(declare-function wdb-nearby "wal-useful.el")

(defvar flycheck-checkers)
(defvar flycheck-checkers)
(defvar flycheck-error-list-buffer)

Packages

flymake

flymake uses backends to check your code, one for each mode. It ships with a few (and so do some other packages like lsp-mode).

(defvar wal-flymake-map (make-sparse-keymap))

(use-package flymake
  :config
  (that-key "flymake" :key "C-c f")

  (defvar-keymap wal-flymake-repeat-map
    :doc "Repeat map for `flymake'."
    :repeat t
    "n" 'flymake-goto-next-error
    "p" 'flymake-goto-prev-error)

  :custom
  (flymake-mode-line-lighter "flm")

  :bind
  (:map wal-flymake-map
   ("n" . flymake-goto-next-error)
   ("p" . flymake-goto-prev-error)
   ("l" . flymake-show-buffer-diagnostics))

  :bind-keymap
  ("C-c f" . wal-flymake-map))

flycheck

flycheck is for all of our linting/code quality needs. It’s a bit easier to setup than the built-in flymake although that one has come a long way itself.

This provides functionality to run a check on a file from a batch process.

(defconst wal-flycheck-file--buffer "*wal-flycheck-file*")

(defun wal-flycheck-file--get-buffer ()
  "Get a buffer for FILENAME to display errors in."
  (unless (get-buffer wal-flycheck-file--buffer)
    (with-current-buffer (get-buffer-create wal-flycheck-file--buffer)
      (view-mode 1)))
  (get-buffer wal-flycheck-file--buffer))

(defun wal-flycheck-file--erase ()
  "Erase the flycheck buffer."
  (with-current-buffer (wal-flycheck-file--get-buffer)
    (setq buffer-read-only nil)
    (erase-buffer)
    (setq buffer-read-only t)))

(defun wal-flycheck-file--write (message &optional skip-newline)
  "Write MESSAGE to the file check buffer.

Optionally don't concat a newline char if SKIP-NEWLINE is t."
  (let ((buffer (wal-flycheck-file--get-buffer)))

    (with-current-buffer buffer
      (setq buffer-read-only nil)
      (goto-char (point-max))
      (insert  message)
      (unless skip-newline (insert "\n"))
      (setq buffer-read-only t))))

(defun wal-flycheck-file--callback (file buffer &optional defer-display kill-buffer)
  "Show errors in FILE in a distinct buffer.

Unless DEFER-DISPLAY is t, show it.

If KILL-BUFFER is t, also kill its BUFFER."
  (lambda (_status &optional errors)
    (let* ((output-buffer (wal-flycheck-file--get-buffer))
           (filename (file-name-nondirectory file)))

      (if (null errors)
          (wal-flycheck-file--write (format "No errors in '%s'." filename))
        (wal-flycheck-file--write (format "Errors in file '%s':" filename))
        (seq-do (lambda (err)
                  (when-let ((err-message (flycheck-error-message err))
                             (line (flycheck-error-line err)))

                    (wal-flycheck-file--write (format "line %d: %s\n" line err-message))))
                errors))

      (unless defer-display (display-buffer output-buffer))

      (when kill-buffer (kill-buffer buffer)))))

(defun wal-flycheck-file (file &optional defer-display kill-buffer)
  "Check FILE with flycheck.

Display it afterwards unless DEFER-DISPLAY is t.

If KILL-BUFFER is t, kill the file's buffer."
  (interactive "fSelect file: ")

  (declare-function flycheck-get-checker-for-buffer "ext:flycheck.el")
  (declare-function flycheck-syntax-check-new "ext:flycheck.el")
  (declare-function flycheck-compute-working-directory "ext:flycheck.el")
  (declare-function flycheck-syntax-check-start "ext:flycheck.el")

  (with-current-buffer (find-file-noselect file)
    (let ((checker (flycheck-get-checker-for-buffer)))

      (if checker
          (let* ((check (flycheck-syntax-check-new
                         :buffer (current-buffer)
                         :checker checker
                         :context nil
                         :working-directory (flycheck-compute-working-directory checker)))
                 (callback (wal-flycheck-file--callback file (current-buffer) defer-display kill-buffer)))

            (flycheck-syntax-check-start check callback))
        (user-error "Couldn't determine checker for file")))))

(use-package flycheck
  :init
  (that-key "flycheck" :leader (ambassador :key "f"))

  :config
  (wdb-nearby flycheck-error-list-buffer :side 'bottom)

  (defvar-keymap wal-flycheck-repeat-map
    :doc "Repeat map for `flycheck'."
    :repeat t
    "n" 'flycheck-next-error
    "p" 'flycheck-previous-error
    "h" 'flycheck-display-error-at-point)

  :custom
  (flycheck-mode-line-prefix "flc")
  (flycheck-disabled-checkers '(proselint))
  (flycheck-keymap-prefix (wal-key-combo-for-leader 'ambassador :key "f" :translate t)))

flyspell

My spelling is bad. Uses American English for flyspell.

(defun wal-flyspell ()
  "(De-)Activate the appropriate `flyspell' mode."
  (interactive)

  (if flyspell-mode
      (flyspell-mode -1)
    (if (derived-mode-p 'prog-mode)
        (flyspell-prog-mode)
      (flyspell-mode))))

(defun wal-flyspell-goto-previous-error ()
  "Go to previous `flyspell-error'."
  (interactive)

  (flyspell-goto-next-error t))

(use-package flyspell
  :init
  (defvar wal-flyspell-map (make-sparse-keymap))

  (that-key "flyspell" :key "C-c s")

  :config
  ;; Override the map to not remove zealous bindings.
  (setq flyspell-mode-map wal-flyspell-map)
  (setf (cdr (assoc 'flyspell-mode minor-mode-map-alist)) (make-sparse-keymap))

  (defvar-keymap flyspell-repeat-map
    :doc "Keymap to repeat various `flyspell' commands."
    :repeat t
    "n" 'flyspell-goto-next-error
    "p" 'wal-flyspell-goto-previous-error
    "i" 'ispell-word
    "a" 'flyspell-auto-correct-word)

  :custom
  (flyspell-issue-message-flag nil)
  (flyspell-mode-line-string " fsp")
  (flyspell-default-dictionary "american")

  :bind
  (:map wal-flyspell-map
   ("s" . wal-flyspell)
   ("b" . flyspell-buffer)
   ("r" . flyspell-region)
   ("n" . flyspell-goto-next-error)
   ("i" . ispell-word)
   ("a" . flyspell-auto-correct-word)
   ("c" . ispell-change-dictionary))

  :bind-keymap
  (("C-c s" . flyspell-mode-map)))

jinx

Just-in-time spell-checking using enchant-2.

(use-package jinx
  :if (executable-find "enchant-2")

  :hook (emacs-startup . global-jinx-mode)

  :bind
  (:map jinx-repeat-map
   ("j" . jinx-next)
   ("c" . jinx-correct))

  :general
  (editors "j" 'jinx-next 'jinx-correct))

consult-flycheck

Find errors by severity.

(use-package consult-flycheck
  :defer 2
  :after (consult flycheck))

Footer

(provide 'wal-fix)

;;; wal-fix.el ends here