-
Notifications
You must be signed in to change notification settings - Fork 9
/
yapfify.el
122 lines (106 loc) · 4.33 KB
/
yapfify.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
;;; yapfify.el --- (automatically) format python buffers using YAPF.
;; Copyright (C) 2016 Joris Engbers
;; Author: Joris Engbers <[email protected]>
;; Homepage: https://github.com/JorisE/yapfify
;; Version: 1.0.0
;; Package-Requires: ()
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published
;; by the Free Software Foundation; either version 3, or (at your
;; option) any later version.
;;
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; For a full copy of the GNU General Public License
;; see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Yapfify uses yapf to format a Python buffer. It can be called explicitly on a
;; certain buffer, but more conveniently, a minor-mode 'yapf-mode' is provided
;; that turns on automatically running YAPF on a buffer before saving.
;;
;; Installation:
;;
;; Add yapfify.el to your load-path.
;;
;; To automatically format all Python buffers before saving, add the function
;; yapf-mode to python-mode-hook:
;;
;; (add-hook 'python-mode-hook 'yapf-mode)
;;
;;; Code:
(require 'cl-lib)
(defcustom yapfify-executable "yapf"
"Executable used to start yapf."
:type 'string
:group 'yapfify)
(defun yapfify-call-bin (input-buffer output-buffer start-line end-line)
"Call process yapf on INPUT-BUFFER saving the output to OUTPUT-BUFFER.
Return the exit code. START-LINE and END-LINE specify region to
format."
(with-current-buffer input-buffer
(call-process-region (point-min) (point-max)
yapfify-executable nil output-buffer
nil "-l" (concat (number-to-string start-line) "-"
(number-to-string end-line)))))
(defun get-buffer-string (buffer)
"Return the contents of BUFFER."
(with-current-buffer buffer
(buffer-string)))
;;;###autoload
(defun yapfify-region (beginning end)
"Try to yapfify the current region.
If yapf exits with an error, the output will be shown in a help-window."
(interactive "r")
(let* ((original-buffer (current-buffer))
(original-point (point)) ; Because we are replacing text, save-excursion does not always work.
(buffer-windows (get-buffer-window-list original-buffer nil t))
(original-window-pos (mapcar 'window-start buffer-windows))
(start-line (line-number-at-pos beginning))
(end-line (line-number-at-pos (if (or (= (char-before end) 10)
(= (char-before end) 13))
(- end 1)
end)))
(tmpbuf (get-buffer-create "*yapfify*"))
(dummy (with-current-buffer tmpbuf (erase-buffer)))
(exit-code (yapfify-call-bin original-buffer tmpbuf start-line end-line)))
(deactivate-mark)
;; There are three exit-codes defined for YAPF:
;; 0: Exit with success (change or no change on yapf >=0.11)
;; 1: Exit with error
;; 2: Exit with success and change (Backward compatibility)
;; anything else would be very unexpected.
(cond ((or (eq exit-code 0) (eq exit-code 2))
(with-current-buffer tmpbuf
(copy-to-buffer original-buffer (point-min) (point-max))))
((eq exit-code 1)
(error "Yapf failed, see %s buffer for details" (buffer-name tmpbuf))))
;; Clean up tmpbuf
(kill-buffer tmpbuf)
;; restore window to similar state
(goto-char original-point)
(cl-mapcar 'set-window-start buffer-windows original-window-pos)))
;;;###autoload
(defun yapfify-buffer ()
"Yapfify whole buffer."
(interactive)
(yapfify-region (point-min) (point-max)))
;;;###autoload
(defun yapfify-region-or-buffer ()
"Yapfify the region if it is active. Otherwise, yapfify the buffer"
(interactive)
(if (region-active-p)
(yapfify-region (region-beginning) (region-end))
(yapfify-buffer)))
;;;###autoload
(define-minor-mode yapf-mode
"Automatically run YAPF before saving."
:lighter " YAPF"
(if yapf-mode
(add-hook 'before-save-hook 'yapfify-buffer nil t)
(remove-hook 'before-save-hook 'yapfify-buffer t)))
(provide 'yapfify)
;;; yapfify.el ends here