From: Amin Bandali Date: Sun, 6 May 2018 01:44:26 +0000 (-0400) Subject: [emacs] assimilate flycheck-haskell X-Git-Url: https://git.shemshak.org/gitweb.cgi/~bandali/configs/commitdiff_plain/f76bdaa8303e6353103e94792e4275a6a6bab58c [emacs] assimilate flycheck-haskell Only use 'haskell-hlint checker and disable the other two. Also, add a copy of hs-lint.el, but leave it disabled (I tried it before deciding to use flycheck-haskell). --- diff --git a/.gitmodules b/.gitmodules index a288425..eaf8b58 100644 --- a/.gitmodules +++ b/.gitmodules @@ -49,6 +49,9 @@ [submodule "flycheck"] path = lib/flycheck url = git@github.com:flycheck/flycheck.git +[submodule "flycheck-haskell"] + path = lib/flycheck-haskell + url = git@github.com:flycheck/flycheck-haskell.git [submodule "ghub"] path = lib/ghub url = git@github.com:magit/ghub.git diff --git a/init.org b/init.org index cf0a96c..6be9194 100644 --- a/init.org +++ b/init.org @@ -961,7 +961,8 @@ TODO: break this giant source block down into individual org sections. :config (setq haskell-indentation-layout-offset 4 haskell-indentation-left-offset 4 - haskell-indentation-ifte-offset 4)) + flycheck-checker 'haskell-hlint + flycheck-disabled-checkers '(haskell-stack-ghc haskell-ghc))) #+end_src *** [[https://github.com/mpickering/hlint-refactor-mode][hlint-refactor]] @@ -977,6 +978,157 @@ executable from [[https://github.com/mpickering/apply-refact][apply-refact]]. :hook (haskell-mode . hlint-refactor-mode)) #+end_src +*** [[https://github.com/flycheck/flycheck-haskell][flycheck-haskell]] + +#+begin_src emacs-lisp +(use-package flycheck-haskell) +#+end_src + +*** [[https://github.com/ndmitchell/hlint/blob/20e116a043f2073c57b17b24ae6364b5e433ba7e/data/hs-lint.el][hs-lint.el]] +:PROPERTIES: +:header-args+: :tangle lisp/hs-lint.el :mkdirp yes +:END: + +Currently using =flycheck-haskell= with the =haskell-hlint= checker +instead. + +#+begin_src emacs-lisp :tangle no +;;; hs-lint.el --- minor mode for HLint code checking + +;; Copyright 2009 (C) Alex Ott +;; +;; Author: Alex Ott +;; Keywords: haskell, lint, HLint +;; Requirements: +;; Status: distributed under terms of GPL2 or above + +;; Typical message from HLint looks like: +;; +;; /Users/ott/projects/lang-exp/haskell/test.hs:52:1: Eta reduce +;; Found: +;; count1 p l = length (filter p l) +;; Why not: +;; count1 p = length . filter p + + +(require 'compile) + +(defgroup hs-lint nil + "Run HLint as inferior of Emacs, parse error messages." + :group 'tools + :group 'haskell) + +(defcustom hs-lint-command "hlint" + "The default hs-lint command for \\[hlint]." + :type 'string + :group 'hs-lint) + +(defcustom hs-lint-save-files t + "Save modified files when run HLint or no (ask user)" + :type 'boolean + :group 'hs-lint) + +(defcustom hs-lint-replace-with-suggestions nil + "Replace user's code with suggested replacements" + :type 'boolean + :group 'hs-lint) + +(defcustom hs-lint-replace-without-ask nil + "Replace user's code with suggested replacements automatically" + :type 'boolean + :group 'hs-lint) + +(defun hs-lint-process-setup () + "Setup compilation variables and buffer for `hlint'." + (run-hooks 'hs-lint-setup-hook)) + +;; regex for replace suggestions +;; +;; ^\(.*?\):\([0-9]+\):\([0-9]+\): .* +;; Found: +;; \s +\(.*\) +;; Why not: +;; \s +\(.*\) + +(defvar hs-lint-regex + "^\\(.*?\\):\\([0-9]+\\):\\([0-9]+\\): .*[\n\C-m]Found:[\n\C-m]\\s +\\(.*\\)[\n\C-m]Why not:[\n\C-m]\\s +\\(.*\\)[\n\C-m]" + "Regex for HLint messages") + +(defun make-short-string (str maxlen) + (if (< (length str) maxlen) + str + (concat (substring str 0 (- maxlen 3)) "..."))) + +(defun hs-lint-replace-suggestions () + "Perform actual replacement of suggestions" + (goto-char (point-min)) + (while (re-search-forward hs-lint-regex nil t) + (let* ((fname (match-string 1)) + (fline (string-to-number (match-string 2))) + (old-code (match-string 4)) + (new-code (match-string 5)) + (msg (concat "Replace '" (make-short-string old-code 30) + "' with '" (make-short-string new-code 30) "'")) + (bline 0) + (eline 0) + (spos 0) + (new-old-code "")) + (save-excursion + (switch-to-buffer (get-file-buffer fname)) + (goto-char (point-min)) + (forward-line (1- fline)) + (beginning-of-line) + (setf bline (point)) + (when (or hs-lint-replace-without-ask + (yes-or-no-p msg)) + (end-of-line) + (setf eline (point)) + (beginning-of-line) + (setf old-code (regexp-quote old-code)) + (while (string-match "\\\\ " old-code spos) + (setf new-old-code (concat new-old-code + (substring old-code spos (match-beginning 0)) + "\\ *")) + (setf spos (match-end 0))) + (setf new-old-code (concat new-old-code (substring old-code spos))) + (remove-text-properties bline eline '(composition nil)) + (when (re-search-forward new-old-code eline t) + (replace-match new-code nil t))))))) + +(defun hs-lint-finish-hook (buf msg) + "Function, that is executed at the end of HLint execution" + (if hs-lint-replace-with-suggestions + (hs-lint-replace-suggestions) + (next-error 1 t))) + +(define-compilation-mode hs-lint-mode "HLint" + "Mode for check Haskell source code." + (set (make-local-variable 'compilation-process-setup-function) + 'hs-lint-process-setup) + (set (make-local-variable 'compilation-disable-input) t) + (set (make-local-variable 'compilation-scroll-output) nil) + (set (make-local-variable 'compilation-finish-functions) + (list 'hs-lint-finish-hook)) + ) + +(defun hs-lint () + "Run HLint for current buffer with haskell source" + (interactive) + (save-some-buffers hs-lint-save-files) + (compilation-start (concat hs-lint-command " \"" buffer-file-name "\"") + 'hs-lint-mode)) + +(provide 'hs-lint) +;;; hs-lint.el ends here +#+end_src + +#+begin_src emacs-lisp :tangle no +(use-package hs-lint + :load-path "lisp/" + :bind (:map haskell-mode-map + ("C-c l l" . hs-lint))) +#+end_src + * Post initialization :PROPERTIES: :CUSTOM_ID: post-initialization diff --git a/lib/flycheck-haskell b/lib/flycheck-haskell new file mode 160000 index 0000000..ef91cfd --- /dev/null +++ b/lib/flycheck-haskell @@ -0,0 +1 @@ +Subproject commit ef91cfd2766724adf6dd48f7d1dfaeed46dde570