mirror of
https://github.com/jimeh/rubocopfmt.el.git
synced 2026-02-19 09:06:41 +00:00
Merge pull request #1 from jimeh/remove-rubocopfmt-gem-dependency
Remove extermal rubocopfmt command dependency
This commit is contained in:
28
LICENSE
Normal file
28
LICENSE
Normal file
@@ -0,0 +1,28 @@
|
||||
Copyright (c) 2014 The go-mode Authors. All rights reserved.
|
||||
Portions Copyright (c) 2018 Jim Myhrberg.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
46
README.md
46
README.md
@@ -1,20 +1,12 @@
|
||||
# rubocopfmt-mode
|
||||
|
||||
Emacs minor-mode to format Ruby code with [rubocopfmt][] on save.
|
||||
|
||||
Core parts of `rubocopfmt-mode` are borrowed from [`go-mode`][go-mode] and it's
|
||||
invocation of `gofmt`.
|
||||
Emacs minor-mode to format Ruby code with [RuboCop][] on save via it's
|
||||
`--auto-correct` option.
|
||||
|
||||
## Installing
|
||||
|
||||
Install [rubocopfmt][]:
|
||||
|
||||
```
|
||||
gem install rubocopfmt --pre
|
||||
```
|
||||
|
||||
Drop `rubocopfmt.el` somewhere into you `load-path`. I favour the folder
|
||||
`~/.emacs.d/vendor`:
|
||||
Drop `rubocopfmt.el` somewhere into you `load-path` and require it. Personally I
|
||||
favour the folder `~/.emacs.d/vendor`:
|
||||
|
||||
```lisp
|
||||
(add-to-list 'load-path "~/.emacs.d/vendor")
|
||||
@@ -23,8 +15,8 @@ Drop `rubocopfmt.el` somewhere into you `load-path`. I favour the folder
|
||||
|
||||
## Usage
|
||||
|
||||
To enable formatting `ruby-mode` buffers with rubocopfmt on save, simply enable
|
||||
`rubocop-mode` within `ruby-mode` with something like this in your config:
|
||||
To enable formatting `ruby-mode` buffers on save with rubocopfmt, simply enable
|
||||
`rubocopfmt-mode` within `ruby-mode` with something like this in your config:
|
||||
|
||||
```lisp
|
||||
(add-hook 'ruby-mode-hook #'rubocopfmt-mode)
|
||||
@@ -32,30 +24,8 @@ To enable formatting `ruby-mode` buffers with rubocopfmt on save, simply enable
|
||||
|
||||
## Commands
|
||||
|
||||
- `rubocopfmt` - Format current buffer with rubocopfmt.
|
||||
- `rubocopfmt` - Format current buffer with RuboCop.
|
||||
- `rubocopfmt-mode` - Toggle formatting on save on/off.
|
||||
|
||||
## License
|
||||
|
||||
Copyright (C) 2017 Jim Myhrberg
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
[rubocopfmt]: https://github.com/jimeh/rubocopfmt
|
||||
[rubocop]: https://github.com/bbatsov/rubocop
|
||||
[go-mode]: https://github.com/dominikh/go-mode.el
|
||||
|
||||
207
rubocopfmt.el
207
rubocopfmt.el
@@ -1,75 +1,193 @@
|
||||
;;; rubocopfmt.el --- Format ruby code with rubocopfmt.
|
||||
;;; rubocopfmt.el --- Format ruby code with rubocop
|
||||
|
||||
;; Copyright (C) 2017 Jim Myhrberg
|
||||
|
||||
;; Author: Jim Myhrberg
|
||||
;; Keywords: ruby rubocop rubocopfmt
|
||||
;; URL: https://github.com/jimeh/rubocopfmt-emacs
|
||||
;; Version: 0.1.0
|
||||
;; Keywords: convenience wp edit ruby rubocop
|
||||
;; URL: https://github.com/jimeh/rubocopfmt.el
|
||||
;; Author: Jim Myhrberg
|
||||
|
||||
;; This file is not part of GNU Emacs.
|
||||
|
||||
;;; License:
|
||||
;;
|
||||
;; Permission is hereby granted, free of charge, to any person obtaining a
|
||||
;; copy of this software and associated documentation files (the "Software"),
|
||||
;; to deal in the Software without restriction, including without limitation
|
||||
;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
;; and/or sell copies of the Software, and to permit persons to whom the
|
||||
;; Software is furnished to do so, subject to the following conditions:
|
||||
;; Copyright (c) 2014 The go-mode Authors. All rights reserved.
|
||||
;; Portions Copyright (c) 2018 Jim Myhrberg.
|
||||
;;
|
||||
;; The above copyright notice and this permission notice shall be included in
|
||||
;; all copies or substantial portions of the Software.
|
||||
;; Redistribution and use in source and binary forms, with or without
|
||||
;; modification, are permitted provided that the following conditions are
|
||||
;; met:
|
||||
;;
|
||||
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
;; DEALINGS IN THE SOFTWARE.
|
||||
;; * Redistributions of source code must retain the above copyright
|
||||
;; notice, this list of conditions and the following disclaimer.
|
||||
;; * Redistributions in binary form must reproduce the above
|
||||
;; copyright notice, this list of conditions and the following disclaimer
|
||||
;; in the documentation and/or other materials provided with the
|
||||
;; distribution.
|
||||
;; * Neither the name of the copyright holder nor the names of its
|
||||
;; contributors may be used to endorse or promote products derived from
|
||||
;; this software without specific prior written permission.
|
||||
;;
|
||||
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; The core parts of rubocopfmt.el are borrowed from the gofmt related parts of
|
||||
;; go-mode.el 1.4.0. So most credit goes to The Go Authors.
|
||||
;; This library formats Ruby code by using rubocop and it's --auto-correct
|
||||
;; option.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defgroup rubocopfmt nil
|
||||
"Minor mode for formatting Ruby buffers with rubocopfmt."
|
||||
"Minor mode for formatting Ruby buffers with rubocop."
|
||||
:group 'languages
|
||||
:link '(url-link "https://github.com/jimeh/rubocopfmt.el"))
|
||||
|
||||
(defcustom rubocopfmt-command "rubocopfmt"
|
||||
"The 'rubocopfmt' command."
|
||||
(defcustom rubocopfmt-rubocop-command "rubocop"
|
||||
"Name of rubocop executable."
|
||||
:type 'string
|
||||
:group 'rubocopfmt)
|
||||
|
||||
(defcustom rubocopfmt-disabled-cops
|
||||
'("Lint/Debugger" ; Don't remove debugger calls.
|
||||
"Lint/UnusedBlockArgument" ; Don't rename unused block arguments.
|
||||
"Lint/UnusedMethodArgument" ; Don't rename unused method arguments.
|
||||
"Style/EmptyMethod" ; Don't remove blank line in empty methods.
|
||||
)
|
||||
"A list of RuboCop cops to disable during auto-correction.
|
||||
These cops are disabled because they cause confusion during
|
||||
interactive use within a text-editor."
|
||||
:type '(repeat string)
|
||||
:group 'rubocopfmt)
|
||||
|
||||
(defcustom rubocopfmt-show-errors 'buffer
|
||||
"Where to display rubocopfmt error output.
|
||||
It can either be displayed in its own buffer, in the echo area,
|
||||
or not at all.
|
||||
|
||||
Please note that Emacs outputs to the echo area when writing
|
||||
files and will overwrite rubocopfmt's echo output if used from
|
||||
inside a `before-save-hook'."
|
||||
:type '(choice
|
||||
(const :tag "Own buffer" buffer)
|
||||
(const :tag "Echo area" echo)
|
||||
(const :tag "None" nil))
|
||||
:group 'rubocopfmt)
|
||||
|
||||
;;;###autoload
|
||||
(defun rubocopfmt ()
|
||||
"Format the current buffer with rubocopfmt."
|
||||
"Format the current buffer with rubocop."
|
||||
(interactive)
|
||||
(let ((patchbuf (get-buffer-create "*Rubocopfmt patch*"))
|
||||
(coding-system-for-read 'utf-8)
|
||||
(coding-system-for-write 'utf-8)
|
||||
(rubocopfmt-args
|
||||
(list "--diff-format" "rcs"
|
||||
"--interactive"
|
||||
"--src-file" (file-truename buffer-file-name))))
|
||||
(let* ((coding-system-for-read 'utf-8)
|
||||
(coding-system-for-write 'utf-8)
|
||||
(tmpfile (make-temp-file "rubocopfmt" nil ".rb"))
|
||||
(resultbuf (get-buffer-create "*Rubocopfmt result*"))
|
||||
(patchbuf (get-buffer-create "*Rubocopfmt patch*"))
|
||||
(buffer-file (file-truename buffer-file-name))
|
||||
(src-dir (file-name-directory buffer-file))
|
||||
(src-file (file-name-nondirectory buffer-file))
|
||||
(fmt-command rubocopfmt-rubocop-command)
|
||||
(fmt-args (list "--stdin" src-file
|
||||
"--auto-correct"
|
||||
"--format" "emacs")))
|
||||
|
||||
(if (rubocopfmt--bundled-path-p src-dir)
|
||||
(setq fmt-command "bundle"
|
||||
fmt-args (append (list "exec" rubocopfmt-rubocop-command)
|
||||
fmt-args)))
|
||||
|
||||
(if rubocopfmt-disabled-cops
|
||||
(setq fmt-args (append fmt-args (list "--except"
|
||||
(combine-and-quote-strings
|
||||
rubocopfmt-disabled-cops ",")))))
|
||||
|
||||
(unwind-protect
|
||||
(save-restriction
|
||||
(widen)
|
||||
(write-region nil nil tmpfile)
|
||||
(with-current-buffer resultbuf (erase-buffer))
|
||||
(with-current-buffer patchbuf (erase-buffer))
|
||||
(message "Calling rubocopfmt: %s %s"
|
||||
rubocopfmt-command rubocopfmt-args)
|
||||
(apply #'call-process-region (point-min) (point-max)
|
||||
rubocopfmt-command nil patchbuf nil rubocopfmt-args)
|
||||
|
||||
(let ((current-directory src-dir))
|
||||
(message "Calling rubocop from directory \"%s\": %s %s"
|
||||
src-dir fmt-command (mapconcat 'identity fmt-args " "))
|
||||
(apply #'call-process-region (point-min) (point-max)
|
||||
fmt-command nil resultbuf nil fmt-args)
|
||||
(if (rubocopfmt--parse-result resultbuf tmpfile)
|
||||
(call-process-region (point-min) (point-max) "diff"
|
||||
nil patchbuf nil "-n" "-" tmpfile)))
|
||||
|
||||
(if (= (buffer-size patchbuf) 0)
|
||||
(message "Buffer is already rubocopfmted")
|
||||
(progn
|
||||
(rubocopfmt--apply-rcs-patch patchbuf)
|
||||
(message "Applied rubocopfmt")))))
|
||||
(kill-buffer patchbuf)))
|
||||
(rubocopfmt--apply-rcs-patch patchbuf)
|
||||
(message "Applied rubocopfmt")))
|
||||
|
||||
(delete-file tmpfile)
|
||||
(kill-buffer resultbuf)
|
||||
(kill-buffer patchbuf))))
|
||||
|
||||
(defun rubocopfmt--parse-result (resultbuf tmpfile)
|
||||
"Parse Rubocop result in RESULTBUF and write corrections to TMPFILE."
|
||||
(let ((split 0))
|
||||
(with-current-buffer resultbuf
|
||||
(goto-char (point-min))
|
||||
;; Only find the separator when RuboCop has printed complaints.
|
||||
(setq split (search-forward "\n====================\n" nil t))
|
||||
|
||||
;; If no RuboCop complaints were printed, we need to find the separator at
|
||||
;; the beginning of the buffer. This separation helps prevent false
|
||||
;; positive separator matches.
|
||||
(unless split
|
||||
(setq split (search-forward "====================\n" nil t)))
|
||||
|
||||
(if split
|
||||
(when (> split 22)
|
||||
(goto-char (point-min))
|
||||
(when (search-forward "[Corrected]" split t)
|
||||
(write-region split (point-max) tmpfile)
|
||||
t))
|
||||
(rubocopfmt--process-errors resultbuf)
|
||||
nil))))
|
||||
|
||||
(defun rubocopfmt--process-errors (resultbuf)
|
||||
"Display contents of RESULTBUF as errors."
|
||||
(if (eq rubocopfmt-show-errors 'echo)
|
||||
(with-current-buffer resultbuf
|
||||
(message (buffer-string))))
|
||||
|
||||
(if (eq rubocopfmt-show-errors 'buffer)
|
||||
(let ((errbuf (get-buffer-create "*Rubocopfmt errors*")))
|
||||
(with-current-buffer errbuf
|
||||
(erase-buffer)
|
||||
(goto-char (point-min))
|
||||
(insert-buffer-substring resultbuf))
|
||||
(display-buffer errbuf))))
|
||||
|
||||
(defun rubocopfmt--bundled-path-p (directory)
|
||||
"Check if there is a Gemfile in DIRECTORY, or any parent directory."
|
||||
(rubocopfmt--file-search-upward directory "Gemfile"))
|
||||
|
||||
(defun rubocopfmt--file-search-upward (directory file)
|
||||
"Search DIRECTORY for FILE and return its full path if found, or NIL if not.
|
||||
|
||||
If FILE is not found in DIRECTORY, the parent of DIRECTORY will be searched."
|
||||
(let ((parent-dir (file-truename (concat (file-name-directory directory) "../")))
|
||||
(current-path (if (not (string= (substring directory (- (length directory) 1)) "/"))
|
||||
(concat directory "/" file)
|
||||
(concat directory file))))
|
||||
|
||||
(if (file-exists-p current-path)
|
||||
current-path
|
||||
(when (and (not (string= (file-truename directory) parent-dir))
|
||||
(< (length parent-dir) (length (file-truename directory))))
|
||||
(rubocopfmt--file-search-upward parent-dir file)))))
|
||||
|
||||
(defun rubocopfmt--apply-rcs-patch (patch-buffer)
|
||||
"Apply an RCS-formatted diff from PATCH-BUFFER to the current buffer."
|
||||
@@ -90,7 +208,7 @@
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(unless (looking-at "^\\([ad]\\)\\([0-9]+\\) \\([0-9]+\\)")
|
||||
(error "invalid rcs patch or internal error in rubocopfmt--apply-rcs-patch"))
|
||||
(error "Invalid rcs patch or internal error in rubocopfmt--apply-rcs-patch"))
|
||||
(forward-line)
|
||||
(let ((action (match-string 1))
|
||||
(from (string-to-number (match-string 2)))
|
||||
@@ -111,7 +229,7 @@
|
||||
(cl-incf line-offset len)
|
||||
(rubocopfmt--delete-whole-line len)))
|
||||
(t
|
||||
(error "invalid rcs patch or internal error in rubocopfmt--apply-rcs-patch")))))))))
|
||||
(error "Invalid rcs patch or internal error in rubocopfmt--apply-rcs-patch")))))))))
|
||||
|
||||
(defun rubocopfmt--delete-whole-line (&optional arg)
|
||||
"Delete the current line without putting it in the `kill-ring'.
|
||||
@@ -140,6 +258,7 @@ function."
|
||||
(progn (forward-visible-line arg) (point))))))
|
||||
|
||||
(defun rubocopfmt--goto-line (line)
|
||||
"Move cursor to LINE."
|
||||
(goto-char (point-min))
|
||||
(forward-line (1- line)))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user