├── LICENSE.txt ├── README.md └── flycheck-vale.el /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 abingham 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flycheck-vale 2 | 3 | [![MELPA](http://melpa.org/packages/flycheck-vale.svg)](http://melpa.org/#/flycheck-vale) 4 | 5 | This package provides [flycheck](http://www.flycheck.org/) integration 6 | for [vale](https://github.com/ValeLint/vale). Flycheck is an Emacs system for 7 | on-the-fly syntax checking. Vale is a natural language linter. So with 8 | `flycheck-vale` you get on-the-fly natural language linting. 9 | 10 | Right now `flycheck-vale` is very new and unpolished. Ideas, PRs, etc. are welcome! 11 | 12 | ## Quickstart 13 | 14 | Install `flycheck-vale` from MELPA using `package-install` or something equivalent. 15 | 16 | To use `flycheck-vale` just `require` it and run `flycheck-vale-setup`: 17 | 18 | ```emacs-lisp 19 | (require 'flycheck-vale) 20 | (flycheck-vale-setup) 21 | ``` 22 | 23 | ## Dis/enabling `flycheck-vale` for specific buffers 24 | 25 | The buffer-local variable `flycheck-vale-enabled` allows you to enabled or 26 | disable vale linting for specific buffers. If this variable is `t` then vale 27 | linting will be performed (assuming you've got `flycheck-mode` enabled, etc.) 28 | Likewise, if it is `nil` then vale linting will never be performed. 29 | 30 | You can use `flycheck-vale-toggle-enabled` to toggle this variable between `t` 31 | and `nil`. (And of course you can set it other ways if you want.) By default the 32 | variable is `t`. 33 | 34 | ## Enabling `flycheck-vale` for new modes 35 | 36 | By default `flycheck-vale` will only be enabled for the modes in 37 | `flycheck-vale-modes` (currently `text-mode`, `markdown-mode`, `rst-mode`, and 38 | `org-mode`). To enable it for some other mode, use the function 39 | `flycheck-add-mode`. If you think that this mode should be supported by 40 | `flycheck-vale` by default, bring it up in an issue. 41 | -------------------------------------------------------------------------------- /flycheck-vale.el: -------------------------------------------------------------------------------- 1 | ;;; flycheck-vale.el --- flycheck integration for vale -*- lexical-binding: t -*- 2 | ;; Copyright (c) 2017 Austin Bingham 3 | ;; 4 | ;; Author: Austin Bingham 5 | ;; Version: 0.1 6 | ;; URL: https://github.com/abingham/flycheck-vale 7 | ;; Package-Requires: ((emacs "24.4") (flycheck "0.22") (let-alist "1.0.4")) 8 | ;; 9 | ;; This file is not part of GNU Emacs. 10 | ;; 11 | ;;; Commentary: 12 | ;; 13 | ;; Description: 14 | ;; 15 | ;; This provides flycheck integration for vale. It allows flycheck to 16 | ;; use vale to provide natural language linting. 17 | ;; 18 | ;; Basic usage: 19 | ;; 20 | ;; (require 'flycheck-vale) 21 | ;; (flycheck-vale-setup) 22 | ;; 23 | ;;; License: 24 | ;; 25 | ;; Permission is hereby granted, free of charge, to any person 26 | ;; obtaining a copy of this software and associated documentation 27 | ;; files (the "Software"), to deal in the Software without 28 | ;; restriction, including without limitation the rights to use, copy, 29 | ;; modify, merge, publish, distribute, sublicense, and/or sell copies 30 | ;; of the Software, and to permit persons to whom the Software is 31 | ;; furnished to do so, subject to the following conditions: 32 | ;; 33 | ;; The above copyright notice and this permission notice shall be 34 | ;; included in all copies or substantial portions of the Software. 35 | ;; 36 | ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 37 | ;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 38 | ;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 39 | ;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 40 | ;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 41 | ;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 42 | ;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 43 | ;; SOFTWARE. 44 | ;; 45 | ;;; Code: 46 | 47 | (require 'cl-lib) 48 | (require 'flycheck) 49 | (require 'let-alist) 50 | 51 | (defgroup flycheck-vale nil 52 | "Variables related to flycheck-vale." 53 | :prefix "flycheck-vale-" 54 | :group 'tools) 55 | 56 | (defcustom flycheck-vale-program "vale" 57 | "The vale executable to use." 58 | :type '(string) 59 | :group 'flycheck-vale) 60 | 61 | (defconst flycheck-vale-modes '(text-mode markdown-mode rst-mode org-mode)) 62 | 63 | (defcustom flycheck-vale-output-buffer "*flycheck-vale*" 64 | "Buffer where tool output gets written." 65 | :type '(string) 66 | :group 'flycheck-vale) 67 | 68 | (defvar-local flycheck-vale-enabled t 69 | "Buffer-local variable determining if flycheck-vale should be applied.") 70 | 71 | (defconst flycheck-vale--level-map 72 | '(("error" . error) 73 | ("warning" . warning) 74 | ("suggestion" . info))) 75 | 76 | (defun flycheck-vale--issue-to-error (issue) 77 | "Parse a single vale issue, ISSUE, into a flycheck error struct. 78 | 79 | We only fill in what we can get from the vale issue directly. The 80 | rest (e.g. filename) gets filled in elsewhere." 81 | (let-alist issue 82 | (flycheck-error-new 83 | :line .Line 84 | :column (elt .Span 0) 85 | :message .Message 86 | :id .Check 87 | :level (assoc-default .Severity flycheck-vale--level-map 'string-equal 'error)))) 88 | 89 | (defun flycheck-vale--output-to-errors (output) 90 | "Parse the full JSON output of vale, OUTPUT, into a sequence of flycheck error structs." 91 | (let* ((full-results (json-read-from-string output)) 92 | 93 | ;; Get the list of issues for each file. 94 | (result-vecs (mapcar 'cdr full-results)) 95 | 96 | ;; Chain all of the issues together. The point here, really, is that we 97 | ;; don't expect results from more than one file, but we should be 98 | ;; prepared for the theoretical possibility that the issues are somehow 99 | ;; split across multiple files. This is basically a punt in lieu of 100 | ;; more information. 101 | (issues (apply 'append (mapcar 'cdr full-results)))) 102 | (mapcar 'flycheck-vale--issue-to-error issues))) 103 | 104 | (defun flycheck-vale--handle-finished (checker callback buf) 105 | "Parse the contents of the output buffer into flycheck error 106 | structures, attaching CHECKER and BUF to the structures, and 107 | passing the results to CALLBACK." 108 | (let* ((output (with-current-buffer flycheck-vale-output-buffer (buffer-string))) 109 | (errors (flycheck-vale--output-to-errors output))) 110 | ;; Fill in the rest of the error struct database 111 | (cl-loop for err in errors do 112 | (setf 113 | (flycheck-error-buffer err) buf 114 | (flycheck-error-filename err) (buffer-file-name buf) 115 | (flycheck-error-checker err) checker)) 116 | (funcall callback 'finished errors))) 117 | 118 | (defun flycheck-vale--normal-completion? (event) 119 | (or (string-equal event "finished\n") 120 | (string-match "exited abnormally with code 1.*" event))) 121 | 122 | (defun flycheck-vale--start (checker callback) 123 | "Run vale on the current buffer's contents with CHECKER, passing the results to CALLBACK." 124 | 125 | ;; Clear the output buffer 126 | (with-current-buffer (get-buffer-create flycheck-vale-output-buffer) 127 | (read-only-mode 0) 128 | (erase-buffer)) 129 | 130 | (let* ((process-connection-type nil) 131 | (proc (start-process "flycheck-vale-process" 132 | flycheck-vale-output-buffer 133 | flycheck-vale-program 134 | "--output" 135 | "JSON" 136 | buffer-file-name))) 137 | (let ((checker checker) 138 | (callback callback) 139 | (buf (current-buffer))) 140 | (set-process-sentinel 141 | proc 142 | #'(lambda (process event) 143 | (when (flycheck-vale--normal-completion? event) 144 | (flycheck-vale--handle-finished checker callback buf))))) 145 | 146 | (process-send-region proc (point-min) (point-max)) 147 | (process-send-eof proc))) 148 | 149 | ;;;###autoload 150 | (defun flycheck-vale-setup () 151 | "Convenience function to setup the vale flycheck checker. 152 | 153 | This adds the vale checker to the list of flycheck checkers." 154 | (add-to-list 'flycheck-checkers 'vale)) 155 | 156 | ;;;###autoload 157 | (defun flycheck-vale-toggle-enabled () 158 | "Toggle `flycheck-vale-enabled'." 159 | (interactive) 160 | (setq flycheck-vale-enabled (not flycheck-vale-enabled))) 161 | 162 | (flycheck-define-generic-checker 'vale 163 | "A flycheck checker using vale natural language linting." 164 | :start #'flycheck-vale--start 165 | :predicate (lambda () flycheck-vale-enabled) 166 | :modes flycheck-vale-modes) 167 | 168 | (provide 'flycheck-vale) 169 | 170 | ;;; flycheck-vale.el ends here 171 | --------------------------------------------------------------------------------