Initial Commit
[packages] / xemacs-packages / jde / lisp / jde-checkstyle.el
1 ;;; JDE-CHECKSTYLE.EL --- Checkstyle interface for JDE
2 ;; $Revision: 1.20 $ $Date: 2004/12/29 05:01:29 $
3
4 ;; Copyright (C) 2001, 2002, 2003, 2004 Markus Mohnen and Paul Kinnucan
5
6 ;; Authors: Markus Mohnen and Paul Kinnucan
7 ;; Maintainers: Markus Mohnen and Paul Kinnucan
8 ;; Created: 06 Jun 2001
9 ;; 
10 ;;
11 ;; Keywords: Java coding standard checker Emacs
12  
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)
16 ;; any later version.
17
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.
22
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.
27
28 ;; LCD Archive Entry:
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
32
33 ;;; Commentary:
34
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
39 ;;; standard.
40
41 ;;; Installation:
42 ;;
43 ;;  Put this file on your Emacs-Lisp load path and add following into your
44 ;;  ~/.emacs startup file
45 ;;
46 ;;      (require 'jde-checkstyle)
47
48 ;;; Usage:
49 ;;
50 ;;  M-x `jde-checkstyle' to check the java file in the current buffer.
51 ;;
52
53 ;;; Customization:
54 ;;
55 ;;  M-x `jde-checkstyle-customize' to customize all the jde-checkstyle options.
56
57 ;;; Code:
58
59 (require 'jde-compile)
60
61 (defconst jde-checkstyle-version "3.1")
62
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
67 style."
68   :group 'jde)
69
70 (defcustom jde-checkstyle-class "com.puppycrawl.tools.checkstyle.Main"
71   "*Java checker class.
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
75   :type 'string)
76
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")))
84
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
93   :type 'boolean)
94
95 (defvar jde-checkstyle-interactive-args ""
96   "String of checker arguments entered in the minibuffer.")
97
98 (defvar jde-checkstyle-interactive-arg-history nil
99   "History of checker arguments entered in the minibuffer.")
100
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")))
115
116
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
128 to the property."
129   :group 'jde-checkstyle
130   :type '(repeat (cons 
131                   (string :tag "Property Name") 
132                   (string :tag "Property Value"))))
133
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")))
142
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")))
150
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")))
157
158
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")))
165
166
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
172 buffer."
173    :group 'jde-checkstyle
174    :type '(choice (const :tag "None" :value nil)
175                   (file :menu-tag "Source Directory" :tag "Path")))
176
177
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
185   :type 'hook)
186
187
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")))
194
195
196 (defmethod jde-checkstyle-get-property-args ((this jde-run-vm))
197     "Get property arguments."
198     (mapcar
199      (lambda (prop)
200        (format "-D%s=%s" (car prop) (cdr prop)))
201      jde-run-option-properties))
202   
203
204 ;;;###autoload
205 (defun jde-checkstyle-customize ()
206   "Set Java style checking options."
207   (interactive)
208   (customize-group "jde-checkstyle"))
209
210
211 (defclass jde-checkstyle-checker ()
212   ((buffer           :initarg :buffer
213                      :type buffer
214                      :documentation
215                      "Compilation buffer")
216    (window           :initarg :window
217                      :type window
218                      :documentation
219                      "Window that displays the compilation buffer.")
220    (interactive-args :initarg :interactive-args
221                      :type list
222                      :documentation
223                      "Arguments entered in the minibuffer."))
224   "Class of Java style checkers.")
225
226 (defmethod jde-checkstyle-create-checker-buffer ((this jde-checkstyle-checker))
227   (save-excursion
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))
241
242       (oset this :buffer buf)
243
244       (set-buffer buf)
245
246       ;; Make sure a style checker process is not
247       ;; already running.
248       (let ((check-proc (get-buffer-process (current-buffer))))
249         (if check-proc
250             (if (or (not (eq (process-status check-proc) 'run))
251                     (yes-or-no-p
252                          "A check style process is running; kill it?"))
253                 (condition-case ()
254                     (progn
255                       (interrupt-process check-proc)
256                       (sit-for 1)
257                       (delete-process check-proc))
258                   (error nil))
259               (error "Cannot have two processes in `%s' at once"
260                          (buffer-name)))))
261
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)
265
266       ;; Clear out the compilation buffer and make it writable.
267       (buffer-disable-undo (current-buffer))
268       (erase-buffer)
269       (buffer-enable-undo (current-buffer))
270
271       (compilation-mode)
272       (setq buffer-read-only nil)
273
274       (set (make-local-variable 'compilation-finish-function)
275            (lambda (buf msg) 
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)
281              error-regexp-alist)
282       (if (not jde-xemacsp)
283           (progn
284             (set (make-local-variable 'compilation-enter-directory-regexp-alist)
285                  enter-regexp-alist)
286             (set (make-local-variable 'compilation-leave-directory-regexp-alist)
287                  leave-regexp-alist)
288             (set (make-local-variable 'compilation-file-regexp-alist)
289                  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)))))
294
295 (defmethod jde-checkstyle-get-property-args ((this jde-checkstyle-checker))
296     "Get property arguments."
297     (mapcar
298      (lambda (prop)
299        (format "-D%s=%s" (car prop) (cdr prop)))
300      jde-checkstyle-expanded-properties))
301   
302 (defmethod jde-checkstyle-exec ((this jde-checkstyle-checker))
303
304   (jde-checkstyle-create-checker-buffer this)
305
306   ;; Pop to checker buffer.
307   (let ((outwin (display-buffer (oref this :buffer))))
308     (compilation-set-window-height outwin)
309     (oset this :window outwin))
310
311   (if (not jde-xemacsp)
312       (if compilation-process-setup-function
313           (funcall compilation-process-setup-function)))     
314
315   (let* ((outbuf (oref this :buffer))
316          (vm-path (oref (jde-run-get-vm) :path))
317          (source-file 
318           (concat (file-name-nondirectory buffer-file-name)))
319          (jde-java-directory
320           (concat
321            (jde-find-jde-data-directory)
322            "java/"))
323          (args (append
324                 (unless jde-checkstyle-expanded-properties-file
325                   (jde-checkstyle-get-property-args this))
326                 (oref this :interactive-args)
327                 (list "-classpath" 
328                       (if jde-checkstyle-classpath
329                           (jde-build-classpath jde-checkstyle-classpath)
330                         (jde-normalize-path
331                          (expand-file-name "lib/checkstyle-all.jar" jde-java-directory))))
332                 (list jde-checkstyle-class)             
333                 (list "-c" 
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)))))
350
351     (save-excursion
352       (set-buffer outbuf)
353
354       (insert (format "cd %s\n" default-directory))
355
356       (insert (concat
357                vm-path
358                " "
359                (mapconcat 'identity args " ")
360                "\n\n"))
361
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 
366                           (downcase mode-name)
367                           outbuf
368                           vm-path
369                           args)))
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)))
375
376       (set-buffer-modified-p nil)
377       (setq compilation-last-buffer (oref this :buffer)))))
378
379
380
381 ;;;###autoload
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
389 history enabled."
390   (interactive)
391
392   (if jde-checkstyle-read-args
393       (setq jde-checkstyle-interactive-args
394             (read-from-minibuffer 
395              "Check args: "
396              jde-checkstyle-interactive-args
397              nil nil
398              '(jde-checkstyle-interactive-arg-history . 1))))
399
400   (let ((checker (jde-checkstyle-checker 
401                   "checker" 
402                   :interactive-args (if jde-checkstyle-read-args
403                                         jde-checkstyle-interactive-args))))
404             
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
410     ;; the PC.
411     (if (and (eq system-type 'windows-nt)
412              (not jde-xemacsp)) 
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))
421
422     (jde-checkstyle-exec checker)))
423
424 ;; Register and initialize the customization variables defined
425 ;; by this package.
426 (jde-update-autoloaded-symbols)
427
428 (provide 'jde-checkstyle)
429
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.
433 ;;
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.
436 ;;
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.
444 ;;
445 ;; Revision 1.17  2004/02/02 05:32:50  paulk
446 ;; Added jde-checkstyle-finish-hook. Thanks to Len Trigg.
447 ;;
448 ;; Revision 1.16  2003/11/05 08:33:59  paulk
449 ;; Cosmetic changes.
450 ;;
451 ;; Revision 1.15  2003/11/03 06:00:53  paulk
452 ;; Updated to support CheckStyle 3.1.
453 ;;
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
456 ;; of Emacs.
457 ;;
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
462 ;; the menu.
463 ;;
464 ;; Revision 1.12  2003/08/05 16:22:04  ahyatt
465 ;; Fixes problem with using checkstyle on files not in top-level directory
466 ;;
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>.
470 ;;
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.
475 ;;
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.
478 ;;
479 ;; Revision 1.8  2002/12/13 08:17:17  paulk
480 ;; Fix typo in defcustom for jde-checkstyle-option-illegal-instantiations.
481 ;;
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.
485 ;;
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.
488 ;;
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.
495 ;;
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.
498 ;;
499 ;; Revision 1.3  2002/09/16 04:07:25  paulk
500 ;; XEmacs compatibility fix. Thanks to Andy Piper.
501 ;;
502 ;; Revision 1.2  2002/09/10 04:48:56  paulk
503 ;; Updated CheckStyle URL.
504 ;;
505 ;; Revision 1.1  2002/09/06 12:53:48  paulk
506 ;; Initial revision to style checker interface.
507 ;;
508
509 ;; Version: 1.3 
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
513 ;; version.
514 ;;
515 ;; Version: 1.2
516 ;; - adopted to checkstyle version 1.3
517 ;; - compatible with recent versions of jde
518 ;;   patch by Nascif Abousalh-Neto 
519 ;;
520 ;; Version: 1.1
521 ;; - minor bug fix to be compatible with recent versions of jde
522 ;; 
523 ;; Version: 1.0
524
525 ;;; JDE-CHECKSTYLE.EL ends here