;;; yapfify.el --- (automatically) format python buffers using YAPF. ;; Copyright (C) 2016 Joris Engbers ;; Author: Joris Engbers ;; Homepage: https://github.com/JorisE/yapfify ;; Version: 0.0.6 ;; Package-Version: 20180830.733 ;; 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 . ;;; 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) (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) "yapf" 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 (generate-new-buffer "*yapfify*")) (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) (mapcar* 'set-window-start buffer-windows original-window-pos))) ;;;###autoload (defun yapfify-buffer () "Yapfify whole buffer." (interactive) (yapfify-region (point-min) (point-max))) ;;;###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