diff options
| author | Dmitry Gutov | 2017-11-22 01:04:27 +0200 |
|---|---|---|
| committer | Dmitry Gutov | 2017-11-22 01:53:37 +0200 |
| commit | 09944d499a361044d81eb6afaa29ffda885b2076 (patch) | |
| tree | 8689c0b6ba3bcd95e30528a87227709df62378fa | |
| parent | c65a0ae7c4592d7fd9a47de3231e6ed07807f8af (diff) | |
| download | emacs-09944d499a361044d81eb6afaa29ffda885b2076.tar.gz emacs-09944d499a361044d81eb6afaa29ffda885b2076.zip | |
Add Rubocop Flymake backend
* lisp/progmodes/ruby-mode.el (ruby-flymake-command):
Inline the value. There are no known substitutes.
(ruby-flymake): Rename to `ruby-flymake-simple' and simplify
the docstring.
(ruby-flymake-use-rubocop-if-available): New option.
(ruby--rubocop-flymake-proc): New variable.
(ruby-rubocop-config): New option.
(ruby-flymake-rubocop, ruby-flymake-auto): New functions.
(ruby-mode): Use `ruby-flymake-auto'.
| -rw-r--r-- | lisp/progmodes/ruby-mode.el | 118 |
1 files changed, 100 insertions, 18 deletions
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index da08bb0788e..18ed6ee5e79 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el | |||
| @@ -2254,23 +2254,12 @@ See `font-lock-syntax-table'.") | |||
| 2254 | (ruby-match-expression-expansion limit))))) | 2254 | (ruby-match-expression-expansion limit))))) |
| 2255 | 2255 | ||
| 2256 | ;;; Flymake support | 2256 | ;;; Flymake support |
| 2257 | (defcustom ruby-flymake-command '("ruby" "-w" "-c") | ||
| 2258 | "External tool used to check Ruby source code. | ||
| 2259 | This is a non empty list of strings, the checker tool possibly | ||
| 2260 | followed by required arguments. Once launched it will receive | ||
| 2261 | the Ruby source to be checked as its standard input." | ||
| 2262 | :group 'ruby | ||
| 2263 | :type '(repeat string)) | ||
| 2264 | |||
| 2265 | (defvar-local ruby--flymake-proc nil) | 2257 | (defvar-local ruby--flymake-proc nil) |
| 2266 | 2258 | ||
| 2267 | (defun ruby-flymake (report-fn &rest _args) | 2259 | (defun ruby-flymake-simple (report-fn &rest _args) |
| 2268 | "Ruby backend for Flymake. Launches | 2260 | "`ruby -wc' backend for Flymake." |
| 2269 | `ruby-flymake-command' (which see) and passes to its standard | 2261 | (unless (executable-find "ruby") |
| 2270 | input the contents of the current buffer. The output of this | 2262 | (error "Cannot find the ruby executable")) |
| 2271 | command is analyzed for error and warning messages." | ||
| 2272 | (unless (executable-find (car ruby-flymake-command)) | ||
| 2273 | (error "Cannot find a suitable checker")) | ||
| 2274 | 2263 | ||
| 2275 | (when (process-live-p ruby--flymake-proc) | 2264 | (when (process-live-p ruby--flymake-proc) |
| 2276 | (kill-process ruby--flymake-proc)) | 2265 | (kill-process ruby--flymake-proc)) |
| @@ -2281,9 +2270,9 @@ command is analyzed for error and warning messages." | |||
| 2281 | (setq | 2270 | (setq |
| 2282 | ruby--flymake-proc | 2271 | ruby--flymake-proc |
| 2283 | (make-process | 2272 | (make-process |
| 2284 | :name "ruby-flymake" :noquery t :connection-type 'pipe | 2273 | :name "ruby-flymake-simple" :noquery t :connection-type 'pipe |
| 2285 | :buffer (generate-new-buffer " *ruby-flymake*") | 2274 | :buffer (generate-new-buffer " *ruby-flymake*") |
| 2286 | :command ruby-flymake-command | 2275 | :command '("ruby" "-w" "-c") |
| 2287 | :sentinel | 2276 | :sentinel |
| 2288 | (lambda (proc _event) | 2277 | (lambda (proc _event) |
| 2289 | (when (eq 'exit (process-status proc)) | 2278 | (when (eq 'exit (process-status proc)) |
| @@ -2315,6 +2304,99 @@ command is analyzed for error and warning messages." | |||
| 2315 | (process-send-region ruby--flymake-proc (point-min) (point-max)) | 2304 | (process-send-region ruby--flymake-proc (point-min) (point-max)) |
| 2316 | (process-send-eof ruby--flymake-proc)))) | 2305 | (process-send-eof ruby--flymake-proc)))) |
| 2317 | 2306 | ||
| 2307 | (defcustom ruby-flymake-use-rubocop-if-available t | ||
| 2308 | "Non-nil to use the Rubocop Flymake backend. | ||
| 2309 | Only takes effect if Rubocop is installed." | ||
| 2310 | :type 'boolean | ||
| 2311 | :group 'ruby | ||
| 2312 | :safe 'booleanp) | ||
| 2313 | |||
| 2314 | (defvar-local ruby--rubocop-flymake-proc nil) | ||
| 2315 | |||
| 2316 | (defcustom ruby-rubocop-config ".rubocop.yml" | ||
| 2317 | "Configuration file for `ruby-flymake-rubocop'." | ||
| 2318 | :type 'string | ||
| 2319 | :group 'ruby | ||
| 2320 | :safe 'stringp) | ||
| 2321 | |||
| 2322 | (defun ruby-flymake-rubocop (report-fn &rest _args) | ||
| 2323 | "Rubocop backend for Flymake." | ||
| 2324 | (unless (executable-find "rubocop") | ||
| 2325 | (error "Cannot find the rubocop executable")) | ||
| 2326 | |||
| 2327 | (when (process-live-p ruby--rubocop-flymake-proc) | ||
| 2328 | (kill-process ruby--rubocop-flymake-proc)) | ||
| 2329 | |||
| 2330 | (let ((source (current-buffer)) | ||
| 2331 | (command (list "rubocop" "--stdin" buffer-file-name "--format" "emacs" | ||
| 2332 | "--cache" "false" ; Work around a bug in old version. | ||
| 2333 | "--display-cop-names")) | ||
| 2334 | config-dir) | ||
| 2335 | (when buffer-file-name | ||
| 2336 | (setq config-dir (locate-dominating-file buffer-file-name | ||
| 2337 | ruby-rubocop-config)) | ||
| 2338 | (when config-dir | ||
| 2339 | (setq command (append command (list "--config" | ||
| 2340 | (expand-file-name ruby-rubocop-config | ||
| 2341 | config-dir))))) | ||
| 2342 | (save-restriction | ||
| 2343 | (widen) | ||
| 2344 | (setq | ||
| 2345 | ruby--rubocop-flymake-proc | ||
| 2346 | (make-process | ||
| 2347 | :name "rubocop-flymake" :noquery t :connection-type 'pipe | ||
| 2348 | :buffer (generate-new-buffer " *rubocop-flymake*") | ||
| 2349 | :command command | ||
| 2350 | :sentinel | ||
| 2351 | (lambda (proc _event) | ||
| 2352 | (when (eq 'exit (process-status proc)) | ||
| 2353 | (unwind-protect | ||
| 2354 | (if (with-current-buffer source (eq proc ruby--rubocop-flymake-proc)) | ||
| 2355 | (with-current-buffer (process-buffer proc) | ||
| 2356 | ;; Finding the executable is no guarantee of | ||
| 2357 | ;; rubocop working, especially in the presence | ||
| 2358 | ;; of rbenv shims (which cross ruby versions). | ||
| 2359 | (unless (zerop (process-exit-status proc)) | ||
| 2360 | (flymake-log :warning "Rubocop returned non-zero status: %s" | ||
| 2361 | (buffer-string))) | ||
| 2362 | (goto-char (point-min)) | ||
| 2363 | (cl-loop | ||
| 2364 | while (search-forward-regexp | ||
| 2365 | "^\\(?:.*.rb\\|-\\):\\([0-9]+\\):\\([0-9]<<+\\): \\(.*\\)$" | ||
| 2366 | nil t) | ||
| 2367 | for msg = (match-string 3) | ||
| 2368 | for (beg . end) = (flymake-diag-region | ||
| 2369 | source | ||
| 2370 | (string-to-number (match-string 1)) | ||
| 2371 | (string-to-number (match-string 2))) | ||
| 2372 | for type = (cond | ||
| 2373 | ((string-match "^[EF]: " msg) | ||
| 2374 | :error) | ||
| 2375 | ((string-match "^W: " msg) | ||
| 2376 | :warning) | ||
| 2377 | (t :note)) | ||
| 2378 | collect (flymake-make-diagnostic source | ||
| 2379 | beg | ||
| 2380 | end | ||
| 2381 | type | ||
| 2382 | (substring msg 3)) | ||
| 2383 | into diags | ||
| 2384 | finally (funcall report-fn diags))) | ||
| 2385 | (flymake-log :debug "Canceling obsolete check %s" | ||
| 2386 | proc)) | ||
| 2387 | (kill-buffer (process-buffer proc))))))) | ||
| 2388 | (process-send-region ruby--rubocop-flymake-proc (point-min) (point-max)) | ||
| 2389 | (process-send-eof ruby--rubocop-flymake-proc))))) | ||
| 2390 | |||
| 2391 | (defun ruby-flymake-auto (report-fn &rest args) | ||
| 2392 | (apply | ||
| 2393 | (if (and ruby-flymake-use-rubocop-if-available | ||
| 2394 | (executable-find "rubocop")) | ||
| 2395 | #'ruby-flymake-rubocop | ||
| 2396 | #'ruby-flymake-simple) | ||
| 2397 | report-fn | ||
| 2398 | args)) | ||
| 2399 | |||
| 2318 | ;;;###autoload | 2400 | ;;;###autoload |
| 2319 | (define-derived-mode ruby-mode prog-mode "Ruby" | 2401 | (define-derived-mode ruby-mode prog-mode "Ruby" |
| 2320 | "Major mode for editing Ruby code." | 2402 | "Major mode for editing Ruby code." |
| @@ -2327,7 +2409,7 @@ command is analyzed for error and warning messages." | |||
| 2327 | 2409 | ||
| 2328 | (add-hook 'after-save-hook 'ruby-mode-set-encoding nil 'local) | 2410 | (add-hook 'after-save-hook 'ruby-mode-set-encoding nil 'local) |
| 2329 | (add-hook 'electric-indent-functions 'ruby--electric-indent-p nil 'local) | 2411 | (add-hook 'electric-indent-functions 'ruby--electric-indent-p nil 'local) |
| 2330 | (add-hook 'flymake-diagnostic-functions 'ruby-flymake nil 'local) | 2412 | (add-hook 'flymake-diagnostic-functions 'ruby-flymake-auto nil 'local) |
| 2331 | 2413 | ||
| 2332 | (setq-local font-lock-defaults '((ruby-font-lock-keywords) nil nil)) | 2414 | (setq-local font-lock-defaults '((ruby-font-lock-keywords) nil nil)) |
| 2333 | (setq-local font-lock-keywords ruby-font-lock-keywords) | 2415 | (setq-local font-lock-keywords ruby-font-lock-keywords) |