1 ;;; JDE-CHECKSTYLE.EL --- Checkstyle interface for JDE
2 ;; $Revision: 1.20 $ $Date: 2004/12/29 05:01:29 $
4 ;; Copyright (C) 2001, 2002, 2003, 2004 Markus Mohnen and Paul Kinnucan
6 ;; Authors: Markus Mohnen and Paul Kinnucan
7 ;; Maintainers: Markus Mohnen and Paul Kinnucan
8 ;; Created: 06 Jun 2001
11 ;; Keywords: Java coding standard checker Emacs
13 ;; This program is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; This program is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; A copy of the GNU General Public License can be obtained from this
24 ;; program's author (send electronic mail to
25 ;; ) or from the Free Software
26 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 ;; jde-checkstyle|Markus Mohnen|
30 ;; |Checkstyle interface for JDE
31 ;; |$Date: 2004/12/29 05:01:29 $|$Revision: 1.20 $|~/packages/jde-checkstyle.el
35 ;;; This package provides an interface from JDE (see
36 ;;; http://jde.sunsite.dk/) to Oliver Burn's CheckStyle (see
37 ;;; http://checkstyle.sourceforge.net/) a development tool
38 ;;; to help programmers write Java code that adheres to a coding
43 ;; Put this file on your Emacs-Lisp load path and add following into your
44 ;; ~/.emacs startup file
46 ;; (require 'jde-checkstyle)
50 ;; M-x `jde-checkstyle' to check the java file in the current buffer.
55 ;; M-x `jde-checkstyle-customize' to customize all the jde-checkstyle options.
59 (require 'jde-compile)
61 (defconst jde-checkstyle-version "3.1")
63 (defgroup jde-checkstyle nil
64 "This group specifies options for the JDEE's interface to the CheckStyle
65 package (http://checkstyle.sourceforge.net). The CheckStyle package
66 checks Java source files for conformity to a specified coding
70 (defcustom jde-checkstyle-class "com.puppycrawl.tools.checkstyle.Main"
72 Specifies the class of the the program to be used to check the source
73 in the current buffer. The default is the checkstyle program."
74 :group 'jde-checkstyle
77 (defcustom jde-checkstyle-classpath nil
78 "*Specify paths of classes required to run the jde-checkstyle application.
79 The JDE uses the specified paths to construct a -classpath
80 argument to pass to the Java interpreter. This option overrides the
81 `jde-global-classpath' option."
82 :group 'jde-checkstyle
83 :type '(repeat (file :tag "Path")))
85 (defcustom jde-checkstyle-read-args nil
86 "*Specify whether to prompt for additional checker arguments.
87 If this variable is non-nil, the jde-checkstyle command prompts
88 you to enter additional checker arguments in the minibuffer.
89 These arguments are appended to those specified by customization
90 variables. The JDE maintains a history list of arguments
91 entered in the minibuffer."
92 :group 'jde-checkstyle
95 (defvar jde-checkstyle-interactive-args ""
96 "String of checker arguments entered in the minibuffer.")
98 (defvar jde-checkstyle-interactive-arg-history nil
99 "History of checker arguments entered in the minibuffer.")
101 ;; (makunbound 'jde-checkstyle-style)
102 (defcustom jde-checkstyle-style nil
103 "*Style used to check this project's Java code. \"Sun\"
104 checks for conformity to the Java code style standard established by
105 Sun Microsystems. \"Custom\" specifies a a user-defined
106 style. Selecting this option causes Emacs to display an edit
107 field. Enter the path of a CheckStyle configuration file that defines
108 the custom coding style in this field (see the CheckStyle
109 documentation for information on configuration files). Use
110 `jde-checkstyle-properties' to specify the values of properties that
111 the configuration file reads from the CheckStyle command line."
112 :group 'jde-checkstyle
113 :type '(choice (const :tag "Sun" :value nil)
114 (file :menu-tag "Custom" :tag "Config. File")))
117 (defcustom jde-checkstyle-expanded-properties nil
118 "*Specify the values of the expanded properties specified by the
119 `jde-checkstyle-style' configuration file. (See the CheckStyle
120 documentation for information about expanded properties.) To enter a
121 property, select the INS button. Emacs displays a Property Name field
122 and a Property Value field for the property. Enter the name of the
123 property, for example, checkstyle.header.file, in the Property Name
124 field; enter its value, for example, docs/java.header, in the Property
125 Value field. Repeat this process to display additional
126 properties. You can specify as many properties as you like in
127 this way. To delete a property, select the DEL button next
129 :group 'jde-checkstyle
131 (string :tag "Property Name")
132 (string :tag "Property Value"))))
134 ;; (makunbound 'jde-checkstyle-expanded-properties-file)
135 (defcustom jde-checkstyle-expanded-properties-file nil
136 "*Path of a file that specifies the values of a configuration
137 file's expanded properties. If this option is set, the JDEE ignores
138 the settings of the `jde-checkstyle-expanded-properties' variable."
139 :group 'jde-checkstyle
140 :type '(choice (const :tag "None" :value nil)
141 (file :menu-tag "Properties File" :tag "Path")))
143 ;; (makunbound 'jde-checkstyle-module-package-names-file)
144 (defcustom jde-checkstyle-module-package-names-file nil
145 "*Path of a file that specifies the package names of
146 custom style checking modules used by this project."
147 :group 'jde-checkstyle
148 :type '(choice (const :tag "None" :value nil)
149 (file :menu-tag "Package Names File" :tag "Path")))
151 ;; (makunbound 'jde-checkstyle-output-file)
152 (defcustom jde-checkstyle-output-file nil
153 "*Path of a file to store CheckStyle's output."
154 :group 'jde-checkstyle
155 :type '(choice (const :tag "None" :value nil)
156 (file :menu-tag "Output File" :tag "Path")))
159 ;; (makunbound 'jde-checkstyle-output-format)
160 (defcustom jde-checkstyle-output-format nil
161 "*Format of CheckStyle's output. Options are plain or XML."
162 :group 'jde-checkstyle
163 :type '(choice (const :tag "Plain" :value nil)
164 (const :tag "XML" :value "xml")))
167 ;; (makunbound 'jde-checkstyle-source-dir)
168 (defcustom jde-checkstyle-source-dir nil
169 "*Path of a directory to check. If you specify a
170 path, CheckStyle checks all the files in the specified
171 directory. Otherwise, it checks the file in the current
173 :group 'jde-checkstyle
174 :type '(choice (const :tag "None" :value nil)
175 (file :menu-tag "Source Directory" :tag "Path")))
178 ;; (makunbound 'jde-checkstyle-finish-hook)
179 (defcustom jde-checkstyle-finish-hook
180 '(jde-compile-finish-kill-buffer)
181 "List of functions to be invoked when CheckStyle terminates. Each
182 function should accept two arguments: the compilation buffer and a
183 string describing how the compilation finished."
184 :group 'jde-checkstyle
188 ;; (makunbound 'jde-checkstyle-source-file-extension)
189 (defcustom jde-checkstyle-source-file-extension nil
190 "*Extension of Java source files (if not java)."
191 :group 'jde-checkstyle
192 :type '(choice (const :tag "java" :value nil)
193 (string :menu-tag "other" :tag "Extension")))
196 (defmethod jde-checkstyle-get-property-args ((this jde-run-vm))
197 "Get property arguments."
200 (format "-D%s=%s" (car prop) (cdr prop)))
201 jde-run-option-properties))
205 (defun jde-checkstyle-customize ()
206 "Set Java style checking options."
208 (customize-group "jde-checkstyle"))
211 (defclass jde-checkstyle-checker ()
212 ((buffer :initarg :buffer
215 "Compilation buffer")
216 (window :initarg :window
219 "Window that displays the compilation buffer.")
220 (interactive-args :initarg :interactive-args
223 "Arguments entered in the minibuffer."))
224 "Class of Java style checkers.")
226 (defmethod jde-checkstyle-create-checker-buffer ((this jde-checkstyle-checker))
228 (let ((buf (get-buffer-create "*check style*"))
229 (error-regexp-alist compilation-error-regexp-alist)
230 (enter-regexp-alist (if (boundp 'compilation-enter-directory-regexp-alist)
231 compilation-enter-directory-regexp-alist))
232 (leave-regexp-alist (if (boundp 'compilation-leave-directory-regexp-alist)
233 compilation-leave-directory-regexp-alist))
234 (file-regexp-alist (if (boundp 'compilation-file-regexp-alist)
235 compilation-file-regexp-alist))
236 (nomessage-regexp-alist (if (boundp 'compilation-nomessage-regexp-alist)
237 compilation-nomessage-regexp-alist))
238 (parser compilation-parse-errors-function)
239 (error-message "No further errors")
240 (thisdir default-directory))
242 (oset this :buffer buf)
246 ;; Make sure a style checker process is not
248 (let ((check-proc (get-buffer-process (current-buffer))))
250 (if (or (not (eq (process-status check-proc) 'run))
252 "A check style process is running; kill it?"))
255 (interrupt-process check-proc)
257 (delete-process check-proc))
259 (error "Cannot have two processes in `%s' at once"
262 ;; In case the checker buffer is current, make sure we get the global
263 ;; values of compilation-error-regexp-alist, etc.
264 (kill-all-local-variables)
266 ;; Clear out the compilation buffer and make it writable.
267 (buffer-disable-undo (current-buffer))
269 (buffer-enable-undo (current-buffer))
272 (setq buffer-read-only nil)
274 (set (make-local-variable 'compilation-finish-function)
276 (run-hook-with-args 'jde-checkstyle-finish-hook buf msg)
277 (setq compilation-finish-function nil)))
278 (set (make-local-variable 'compilation-parse-errors-function) parser)
279 (set (make-local-variable 'compilation-error-message) error-message)
280 (set (make-local-variable 'compilation-error-regexp-alist)
282 (if (not jde-xemacsp)
284 (set (make-local-variable 'compilation-enter-directory-regexp-alist)
286 (set (make-local-variable 'compilation-leave-directory-regexp-alist)
288 (set (make-local-variable 'compilation-file-regexp-alist)
290 (set (make-local-variable 'compilation-nomessage-regexp-alist)
291 nomessage-regexp-alist)))
292 (setq default-directory thisdir
293 compilation-directory-stack (list default-directory)))))
295 (defmethod jde-checkstyle-get-property-args ((this jde-checkstyle-checker))
296 "Get property arguments."
299 (format "-D%s=%s" (car prop) (cdr prop)))
300 jde-checkstyle-expanded-properties))
302 (defmethod jde-checkstyle-exec ((this jde-checkstyle-checker))
304 (jde-checkstyle-create-checker-buffer this)
306 ;; Pop to checker buffer.
307 (let ((outwin (display-buffer (oref this :buffer))))
308 (compilation-set-window-height outwin)
309 (oset this :window outwin))
311 (if (not jde-xemacsp)
312 (if compilation-process-setup-function
313 (funcall compilation-process-setup-function)))
315 (let* ((outbuf (oref this :buffer))
316 (vm-path (oref (jde-run-get-vm) :path))
318 (concat (file-name-nondirectory buffer-file-name)))
321 (jde-find-jde-data-directory)
324 (unless jde-checkstyle-expanded-properties-file
325 (jde-checkstyle-get-property-args this))
326 (oref this :interactive-args)
328 (if jde-checkstyle-classpath
329 (jde-build-classpath jde-checkstyle-classpath)
331 (expand-file-name "lib/checkstyle-all.jar" jde-java-directory))))
332 (list jde-checkstyle-class)
334 (if jde-checkstyle-style
335 (jde-normalize-path jde-checkstyle-style)
336 (concat (jde-find-jde-data-directory) "java/lib/sun_checks.xml")))
337 (if jde-checkstyle-expanded-properties-file
338 (list "-p" (jde-normalize-path jde-checkstyle-expanded-properties-file)))
339 (if jde-checkstyle-module-package-names-file
340 (list "-n" (jde-normalize-path jde-checkstyle-module-package-names-file)))
341 (if jde-checkstyle-output-format
342 (list "-f" jde-checkstyle-output-format))
343 (if jde-checkstyle-output-file
344 (list "-o" (jde-normalize-path jde-checkstyle-output-file)))
345 (if jde-checkstyle-source-file-extension
346 (list "-e" jde-checkstyle-source-file-extension))
347 (if jde-checkstyle-source-dir
348 (list "-r" (jde-normalize-path jde-checkstyle-source-dir))
349 (list source-file)))))
354 (insert (format "cd %s\n" default-directory))
359 (mapconcat 'identity args " ")
362 (let* ((process-environment (cons "EMACS=t" process-environment))
363 (w32-quote-process-args ?\")
364 (win32-quote-process-args ?\") ;; XEmacs
365 (proc (apply 'start-process
370 (set-process-sentinel proc 'compilation-sentinel)
371 (set-process-filter proc 'compilation-filter)
372 (set-marker (process-mark proc) (point) outbuf)
373 (setq compilation-in-progress
374 (cons proc compilation-in-progress)))
376 (set-buffer-modified-p nil)
377 (setq compilation-last-buffer (oref this :buffer)))))
382 (defun jde-checkstyle ()
383 "Checks the Java program in the current buffer.
384 This command invokes the style checker specified by `jde-checkstyle-class'
385 with the options specif2ied by the JDEE customization variables
386 that begin with `jde-checkstyle'. If the variable
387 `jde-checkstyle-read-args' is non-nil, this command reads
388 additional compilation options from the minibuffer, with
392 (if jde-checkstyle-read-args
393 (setq jde-checkstyle-interactive-args
394 (read-from-minibuffer
396 jde-checkstyle-interactive-args
398 '(jde-checkstyle-interactive-arg-history . 1))))
400 (let ((checker (jde-checkstyle-checker
402 :interactive-args (if jde-checkstyle-read-args
403 jde-checkstyle-interactive-args))))
405 ;; Force save-some-buffers to use the minibuffer
406 ;; to query user about whether to save modified buffers.
407 ;; Otherwise, when user invokes jde-checkstyle from
408 ;; menu, save-some-buffers tries to popup a menu
409 ;; which seems not to be supported--at least on
411 (if (and (eq system-type 'windows-nt)
413 (let ((temp last-nonmenu-event))
414 ;; The next line makes emacs think that jde-checkstyle
415 ;; was invoked from the minibuffer, even when it
416 ;; is actually invoked from the menu-bar.
417 (setq last-nonmenu-event t)
418 (save-some-buffers (not compilation-ask-about-save) nil)
419 (setq last-nonmenu-event temp))
420 (save-some-buffers (not compilation-ask-about-save) nil))
422 (jde-checkstyle-exec checker)))
424 ;; Register and initialize the customization variables defined
426 (jde-update-autoloaded-symbols)
428 (provide 'jde-checkstyle)
430 ;; $Log: jde-checkstyle.el,v $
431 ;; Revision 1.20 2004/12/29 05:01:29 paulk
432 ;; Set buffer-read-only to nil after invoking compilation-mode, which sets it to t in latest version of Emacs.
434 ;; Revision 1.19 2004/08/01 12:25:29 paulk
435 ;; Removed optional mode name from call to compilation-mode in jde-checkstyle-create-checker-buffer. This is necessary for compatibility with the latest Emacs, which no longer accepts the optional argument.
437 ;; Revision 1.18 2004/07/01 14:04:39 jslopez
438 ;; Compatibility fix for emacs in CVS. Replaces jde-xemacsp check for boundp for
439 ;; the following variables: compilation-nomessage-regexp-alist,
440 ;; compilation-file-regexp-alist, compilation-leave-directory-regexp-alist,
441 ;; compilation-enter-directory-regexp-alist. Uses the compilation-mode without a
442 ;; parameter. The emacs in CVS does not contain the variables, or the parameter
443 ;; for compilation mode.
445 ;; Revision 1.17 2004/02/02 05:32:50 paulk
446 ;; Added jde-checkstyle-finish-hook. Thanks to Len Trigg.
448 ;; Revision 1.16 2003/11/05 08:33:59 paulk
451 ;; Revision 1.15 2003/11/03 06:00:53 paulk
452 ;; Updated to support CheckStyle 3.1.
454 ;; Revision 1.14 2003/09/27 05:15:24 paulk
455 ;; Normalize path of CheckStyle jar file to permit use on the cygwin versions
458 ;; Revision 1.13 2003/09/01 03:38:18 paulk
459 ;; Removed the code that somebody added to prepend the package path to
460 ;; the source file name and hence force the checkstyle command to be run
461 ;; from the root of a package, thereby making it impossible to run from
464 ;; Revision 1.12 2003/08/05 16:22:04 ahyatt
465 ;; Fixes problem with using checkstyle on files not in top-level directory
467 ;; Revision 1.11 2003/02/23 06:35:23 paulk
468 ;; Adds a variable jde-checkstyle-configuration-file to specify xml config file required by Checkstyle 3.0.
469 ;; Thanks to Joshua Spiewak <JSpiewak@axeda.com>.
471 ;; Revision 1.10 2003/01/19 05:46:08 paulk
472 ;; Removed aliasing of jde-build-classpath to jde-run-build-classpath-arg. I don't understand
473 ;; why that was done but it seems very bad for this file to change the definition of
474 ;; such an important function.
476 ;; Revision 1.9 2002/12/21 09:06:22 paulk
477 ;; Fix bug in generation of jde-checkstyle-option-lcurly-method option. Thanks to ABE Yasushi.
479 ;; Revision 1.8 2002/12/13 08:17:17 paulk
480 ;; Fix typo in defcustom for jde-checkstyle-option-illegal-instantiations.
482 ;; Revision 1.7 2002/11/21 04:18:41 paulk
483 ;; These packages, when autoloaded, now register and initialize the customization variables
484 ;; that they define to the values specified in the current project file.
486 ;; Revision 1.6 2002/11/15 06:46:00 paulk
487 ;; Fixed bug in checkstyle command line: properties file arg now comes after Checkstyle class.
489 ;; Revision 1.5 2002/11/14 06:59:07 paulk
490 ;; - Fixes bug in handling of to-do option.
491 ;; - Fixes bug in handling of the header file check option.
492 ;; - Adds customization variable jde-checkstyle-properties-file.
493 ;; - Now uses jde-checkstyle-classpath if nonnil.
494 ;; Thanks to Joshua Spiewak for the last three changes.
496 ;; Revision 1.4 2002/10/11 05:53:23 paulk
497 ;; Added more packages to the list of packages that are demand loaded. This is intended to reduce the startup time for the JDEE.
499 ;; Revision 1.3 2002/09/16 04:07:25 paulk
500 ;; XEmacs compatibility fix. Thanks to Andy Piper.
502 ;; Revision 1.2 2002/09/10 04:48:56 paulk
503 ;; Updated CheckStyle URL.
505 ;; Revision 1.1 2002/09/06 12:53:48 paulk
506 ;; Initial revision to style checker interface.
510 ;; - Updated to support latest version of checkstyle (2.3), adding
511 ;; support for all the command-line properties as customizable variables. A
512 ;; total of 43 properties are now supported, from 19 in the previous jde-checkstyle
516 ;; - adopted to checkstyle version 1.3
517 ;; - compatible with recent versions of jde
518 ;; patch by Nascif Abousalh-Neto
521 ;; - minor bug fix to be compatible with recent versions of jde
525 ;;; JDE-CHECKSTYLE.EL ends here