[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] emacs-26 09944d4 2/4: Add Rubocop Flymake backend
From: |
Dmitry Gutov |
Subject: |
[Emacs-diffs] emacs-26 09944d4 2/4: Add Rubocop Flymake backend |
Date: |
Tue, 21 Nov 2017 18:57:32 -0500 (EST) |
branch: emacs-26
commit 09944d499a361044d81eb6afaa29ffda885b2076
Author: Dmitry Gutov <address@hidden>
Commit: Dmitry Gutov <address@hidden>
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'.
---
lisp/progmodes/ruby-mode.el | 118 +++++++++++++++++++++++++++++++++++++-------
1 file changed, 100 insertions(+), 18 deletions(-)
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index da08bb0..18ed6ee 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -2254,23 +2254,12 @@ See `font-lock-syntax-table'.")
(ruby-match-expression-expansion limit)))))
;;; Flymake support
-(defcustom ruby-flymake-command '("ruby" "-w" "-c")
- "External tool used to check Ruby source code.
-This is a non empty list of strings, the checker tool possibly
-followed by required arguments. Once launched it will receive
-the Ruby source to be checked as its standard input."
- :group 'ruby
- :type '(repeat string))
-
(defvar-local ruby--flymake-proc nil)
-(defun ruby-flymake (report-fn &rest _args)
- "Ruby backend for Flymake. Launches
-`ruby-flymake-command' (which see) and passes to its standard
-input the contents of the current buffer. The output of this
-command is analyzed for error and warning messages."
- (unless (executable-find (car ruby-flymake-command))
- (error "Cannot find a suitable checker"))
+(defun ruby-flymake-simple (report-fn &rest _args)
+ "`ruby -wc' backend for Flymake."
+ (unless (executable-find "ruby")
+ (error "Cannot find the ruby executable"))
(when (process-live-p ruby--flymake-proc)
(kill-process ruby--flymake-proc))
@@ -2281,9 +2270,9 @@ command is analyzed for error and warning messages."
(setq
ruby--flymake-proc
(make-process
- :name "ruby-flymake" :noquery t :connection-type 'pipe
+ :name "ruby-flymake-simple" :noquery t :connection-type 'pipe
:buffer (generate-new-buffer " *ruby-flymake*")
- :command ruby-flymake-command
+ :command '("ruby" "-w" "-c")
:sentinel
(lambda (proc _event)
(when (eq 'exit (process-status proc))
@@ -2315,6 +2304,99 @@ command is analyzed for error and warning messages."
(process-send-region ruby--flymake-proc (point-min) (point-max))
(process-send-eof ruby--flymake-proc))))
+(defcustom ruby-flymake-use-rubocop-if-available t
+ "Non-nil to use the Rubocop Flymake backend.
+Only takes effect if Rubocop is installed."
+ :type 'boolean
+ :group 'ruby
+ :safe 'booleanp)
+
+(defvar-local ruby--rubocop-flymake-proc nil)
+
+(defcustom ruby-rubocop-config ".rubocop.yml"
+ "Configuration file for `ruby-flymake-rubocop'."
+ :type 'string
+ :group 'ruby
+ :safe 'stringp)
+
+(defun ruby-flymake-rubocop (report-fn &rest _args)
+ "Rubocop backend for Flymake."
+ (unless (executable-find "rubocop")
+ (error "Cannot find the rubocop executable"))
+
+ (when (process-live-p ruby--rubocop-flymake-proc)
+ (kill-process ruby--rubocop-flymake-proc))
+
+ (let ((source (current-buffer))
+ (command (list "rubocop" "--stdin" buffer-file-name "--format" "emacs"
+ "--cache" "false" ; Work around a bug in old version.
+ "--display-cop-names"))
+ config-dir)
+ (when buffer-file-name
+ (setq config-dir (locate-dominating-file buffer-file-name
+ ruby-rubocop-config))
+ (when config-dir
+ (setq command (append command (list "--config"
+ (expand-file-name
ruby-rubocop-config
+ config-dir)))))
+ (save-restriction
+ (widen)
+ (setq
+ ruby--rubocop-flymake-proc
+ (make-process
+ :name "rubocop-flymake" :noquery t :connection-type 'pipe
+ :buffer (generate-new-buffer " *rubocop-flymake*")
+ :command command
+ :sentinel
+ (lambda (proc _event)
+ (when (eq 'exit (process-status proc))
+ (unwind-protect
+ (if (with-current-buffer source (eq proc
ruby--rubocop-flymake-proc))
+ (with-current-buffer (process-buffer proc)
+ ;; Finding the executable is no guarantee of
+ ;; rubocop working, especially in the presence
+ ;; of rbenv shims (which cross ruby versions).
+ (unless (zerop (process-exit-status proc))
+ (flymake-log :warning "Rubocop returned non-zero
status: %s"
+ (buffer-string)))
+ (goto-char (point-min))
+ (cl-loop
+ while (search-forward-regexp
+
"^\\(?:.*.rb\\|-\\):\\([0-9]+\\):\\([0-9]<<+\\): \\(.*\\)$"
+ nil t)
+ for msg = (match-string 3)
+ for (beg . end) = (flymake-diag-region
+ source
+ (string-to-number (match-string 1))
+ (string-to-number (match-string
2)))
+ for type = (cond
+ ((string-match "^[EF]: " msg)
+ :error)
+ ((string-match "^W: " msg)
+ :warning)
+ (t :note))
+ collect (flymake-make-diagnostic source
+ beg
+ end
+ type
+ (substring msg 3))
+ into diags
+ finally (funcall report-fn diags)))
+ (flymake-log :debug "Canceling obsolete check %s"
+ proc))
+ (kill-buffer (process-buffer proc)))))))
+ (process-send-region ruby--rubocop-flymake-proc (point-min)
(point-max))
+ (process-send-eof ruby--rubocop-flymake-proc)))))
+
+(defun ruby-flymake-auto (report-fn &rest args)
+ (apply
+ (if (and ruby-flymake-use-rubocop-if-available
+ (executable-find "rubocop"))
+ #'ruby-flymake-rubocop
+ #'ruby-flymake-simple)
+ report-fn
+ args))
+
;;;###autoload
(define-derived-mode ruby-mode prog-mode "Ruby"
"Major mode for editing Ruby code."
@@ -2327,7 +2409,7 @@ command is analyzed for error and warning messages."
(add-hook 'after-save-hook 'ruby-mode-set-encoding nil 'local)
(add-hook 'electric-indent-functions 'ruby--electric-indent-p nil 'local)
- (add-hook 'flymake-diagnostic-functions 'ruby-flymake nil 'local)
+ (add-hook 'flymake-diagnostic-functions 'ruby-flymake-auto nil 'local)
(setq-local font-lock-defaults '((ruby-font-lock-keywords) nil nil))
(setq-local font-lock-keywords ruby-font-lock-keywords)