1;;; google-java-format.el --- Format code with google-java-format -*- lexical-binding: t; -*- 2;; 3;; Copyright 2015 Google, Inc. All Rights Reserved. 4;; 5;; Package-Requires: ((emacs "24")) 6;; 7;; Licensed under the Apache License, Version 2.0 (the "License"); 8;; you may not use this file except in compliance with the License. 9;; You may obtain a copy of the License at 10;; 11;; http://www.apache.org/licenses/LICENSE-2.0 12;; 13;; Unless required `by applicable law or agreed to in writing, software 14;; distributed under the License is distributed on an "AS-IS" BASIS, 15;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16;; See the License for the specific language governing permissions and 17;; limitations under the License. 18 19;; Keywords: tools, Java 20 21;;; Commentary: 22 23;; This package allows a user to filter code through 24;; google-java-format, fixing its formatting. 25 26;; To use it, ensure the directory of this file is in your `load-path' 27;; and add 28;; 29;; (require 'google-java-format) 30;; 31;; to your .emacs configuration. 32 33;; You may also want to bind `google-java-format-region' to a key: 34;; 35;; (global-set-key [C-M-tab] #'google-java-format-region) 36 37;;; Code: 38 39(defgroup google-java-format nil 40 "Format code using google-java-format." 41 :group 'tools) 42 43(defcustom google-java-format-executable 44 "/usr/bin/google-java-format" 45 "Location of the google-java-format executable. 46 47A string containing the name or the full path of the executable." 48 :group 'google-java-format 49 :type '(file :must-match t :match (lambda (widget file) (file-executable-p file))) 50 :risky t) 51 52;;;###autoload 53(defun google-java-format-region (start end) 54 "Use google-java-format to format the code between START and END. 55If called interactively, uses the region, if there is one. If 56there is no region, then formats the current line." 57 (interactive 58 (if (use-region-p) 59 (list (region-beginning) (region-end)) 60 (list (point) (1+ (point))))) 61 (let ((cursor (point)) 62 (temp-buffer (generate-new-buffer " *google-java-format-temp*")) 63 (stderr-file (make-temp-file "google-java-format"))) 64 (unwind-protect 65 (let ((status (call-process-region 66 ;; Note that emacs character positions are 1-indexed, 67 ;; and google-java-format is 0-indexed, so we have to 68 ;; subtract 1 from START to line it up correctly. 69 (point-min) (point-max) 70 google-java-format-executable 71 nil (list temp-buffer stderr-file) t 72 "--offset" (number-to-string (1- start)) 73 "--length" (number-to-string (- end start)) 74 "-")) 75 (stderr 76 (with-temp-buffer 77 (insert-file-contents stderr-file) 78 (when (> (point-max) (point-min)) 79 (insert ": ")) 80 (buffer-substring-no-properties 81 (point-min) (line-end-position))))) 82 (cond 83 ((stringp status) 84 (error "google-java-format killed by signal %s%s" status stderr)) 85 ((not (zerop status)) 86 (error "google-java-format failed with code %d%s" status stderr)) 87 (t (message "google-java-format succeeded%s" stderr) 88 (delete-region (point-min) (point-max)) 89 (insert-buffer-substring temp-buffer) 90 (goto-char cursor)))) 91 (delete-file stderr-file) 92 (when (buffer-name temp-buffer) (kill-buffer temp-buffer))))) 93 94;;;###autoload 95(defun google-java-format-buffer () 96 "Use google-java-format to format the current buffer." 97 (interactive) 98 (google-java-format-region (point-min) (point-max))) 99 100;;;###autoload 101(defalias 'google-java-format 'google-java-format-region) 102 103(provide 'google-java-format) 104 105;;; google-java-format.el ends here 106