home *** CD-ROM | disk | FTP | other *** search
/ Java 1996 August / Java - Summer 1996.iso / sundist / java / contrib / emacs / java-mode.el < prev    next >
Encoding:
Text File  |  1995-09-10  |  15.7 KB  |  437 lines

  1. ;; Emacs lisp mode for editing java files.
  2. ;; $Id: java-mode.el,v 1.2 1995/04/06 03:03:21 mchapman Exp $  Mitch Chapman
  3. ;;
  4. ;; java-mode.el
  5. ;; ------------
  6. ;; Major mode for editing Java programs.
  7. ;; java-mode is an extension of c++-mode, and it uses alot of variables
  8. ;; from that mode.
  9. ;;
  10. ;; Author:  Mitch Chapman
  11. ;;
  12.  
  13. ;; Maintainer: none
  14. ;; Keywords: languages, major modes
  15.  
  16. ;; This file is *NOT* part of GNU Emacs.
  17.  
  18. ;; java-mode.el is free software; you can redistribute it and/or modify
  19. ;; it under the terms of the GNU General Public License as published by
  20. ;; the Free Software Foundation; either version 2, or (at your option)
  21. ;; any later version.
  22.  
  23. ;; java-mode.el is distributed in the hope that it will be useful,
  24. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26. ;; GNU General Public License for more details.
  27.  
  28. ;; You should have received a copy of the GNU General Public License
  29. ;; along with java-mode.el; see the file COPYING.  If not, write to
  30. ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  31.  
  32. ;;; Commentary:
  33.  
  34. ;; This module derives an editing mode from c++-mode.  The derived mode
  35. ;; is for editing Java code.  (In the first release of this mode there's
  36. ;; very little specialized code; mostly you get a new mode-hook variable
  37. ;; ('java-mode-hook) and a new name ("Java") for your emacs mode line.
  38.  
  39. ;; To use java-mode, put this in your .emacs file:
  40. ;; (autoload 'java-mode "yourLispCodeDirectory/java-mode" "java mode" t nil)
  41. ;; (setq auto-mode-alist
  42. ;;       (append '(("\\.java$" . java-mode)) auto-mode-alist))
  43. ;;
  44.  
  45. ;;; Change Log:
  46. ;;    $Log: java-mode.el,v $
  47. ; Revision 1.2  1995/04/06  03:03:21  mchapman
  48. ; o (fix provided by Eric Mumpower, nocturne@mit.edu)
  49. ;   Original java-mode failed if c++-mode-hook not set.
  50. ; o Added java-indent-command for better indenting of Java methods.
  51. ;   Still needs lots of work.
  52. ;
  53. ; Revision 1.1  1995/04/06  02:50:28  mchapman
  54. ; Initial RCS revision
  55.  
  56. ;;; Code:
  57.  
  58. (provide 'java-mode)
  59.  
  60. (defvar java-mode-map ()
  61.   "Keymap used in Java mode.")
  62.  
  63. (defun java-mode ()
  64.   "Major mode for editing java code.
  65. See the documentation for c++-mode:  java-mode is an extension of
  66. c++-mode.
  67. Use the hook java-mode-hook to execute custom code when entering Java
  68. mode.
  69. \\{java-mode-map}"
  70.   (interactive)
  71.   (let ((current-c++-mode-hook (and (boundp 'c++-mode-hook) c++-mode-hook)))
  72.     ;; Temporarily disable the c++-mode hook; don't wanna run
  73.     ;; it when loading up c++-mode.
  74.     (setq c++-mode-hook nil)
  75.  
  76.     (c++-mode)
  77.  
  78.     ;; Now customize c++-mode to give us any behaviors specific to
  79.     ;; java mode.  (Hm; not much there right now...)
  80.    
  81.     ;; The Java mode map is the C++ mode map, but with a different name.
  82.     (setq java-mode-map c++-mode-map)
  83.     (use-local-map java-mode-map)
  84.     (define-key java-mode-map "\t" 'java-indent-command)
  85.  
  86.     (setq major-mode 'java-mode
  87.       mode-name "Java")
  88.  
  89.     ;; Customize defun-matching expression to allow Java
  90.     ;; functions to be identified.  This is tricky, and all I'm trying to
  91.     ;; do is make it possible to put opening braces at the end of the
  92.     ;; function signature definition, as in the distributed Java code.
  93.     ;; I'm assuming that any line which starts with exactly one level of
  94.     ;; indentation (four spaces in my case; adjust it for your style)
  95.     ;; immediately followed by a letter, matches the beginning of a function
  96.     ;; definition.
  97.     ;; This won't match member data definitions because the function
  98.     ;; "beginning-of-defun-raw" (see lisp.el) insists that a paragraph
  99.     ;; start expression ends with some sort of open character (e.g. "{").
  100.     (set (make-local-variable 'defun-prompt-regexp) "^    \\sw.*")
  101.  
  102.     ;; Restore the original c++-mode-hook.
  103.     (setq c++-mode-hook current-c++-mode-hook)
  104.     (run-hooks 'java-mode-hook)))
  105.  
  106.  
  107. ;;
  108. ;; These functions are lifted almost verbatim from cplus-md.el of
  109. ;; GNU emacs 19.28.
  110. ;; 
  111. (defun java-indent-command (&optional whole-exp)
  112.   "Indent current line as Java code, or in some cases insert a tab character.
  113. If `c-tab-always-indent' is non-nil (the default), always indent current
  114. line.  Otherwise, indent the current line only if point is at the left
  115. margin or in the line's indentation; otherwise insert a tab.
  116.  
  117. A numeric argument, regardless of its value, means indent rigidly all means
  118. indent rigidly all the lines of the expression starting after point so that
  119. this line becomes properly indented.  The relative indentation among the
  120. lines of the expression are preserved."
  121.   (interactive "P")
  122.   (if whole-exp
  123.       ;; If arg, always indent this line as C
  124.       ;; and shift remaining lines of expression the same amount.
  125.       (let ((shift-amt (java-indent-line))
  126.         beg end)
  127.     (save-excursion
  128.       (if c-tab-always-indent
  129.           (beginning-of-line))
  130.       (setq beg (point))
  131.       (forward-sexp 1)
  132.       (setq end (point))
  133.       (goto-char beg)
  134.       (forward-line 1)
  135.       (setq beg (point)))
  136.     (if (> end beg)
  137.         (indent-code-rigidly beg end shift-amt "#")))
  138.     (if (and (not c-tab-always-indent)
  139.          (save-excursion
  140.            (skip-chars-backward " \t")
  141.            (not (bolp))))
  142.     (insert-tab)
  143.       (java-indent-line))))
  144.  
  145. (defun java-indent-line ()
  146.   "Indent current line as Java code.
  147. Return the amount the indentation changed by."
  148.   (let ((indent (calculate-java-indent nil))
  149.     beg shift-amt
  150.     (case-fold-search nil)
  151.     (pos (- (point-max) (point))))
  152.     (beginning-of-line)
  153.     (setq beg (point))
  154.     (cond ((eq indent nil)
  155.        (setq indent (current-indentation)))
  156.       ((eq indent t)
  157.        (setq indent (calculate-c-indent-within-comment)))
  158.       (t
  159.        (skip-chars-forward " \t")
  160.        (if (listp indent) (setq indent (car indent)))
  161.        (cond ((looking-at "default:")
  162.           (setq indent (+ indent c-label-offset)))
  163.          ((or (looking-at "case\\b")
  164.               (and (looking-at "[A-Za-z]")
  165.                (save-excursion
  166.                  (forward-sexp 1)
  167.                  (looking-at ":[^:]"))))
  168.           (setq indent (max 1 (+ indent c-label-offset))))
  169.          ((and (looking-at "else\\b")
  170.                (not (looking-at "else\\s_")))
  171.           (setq indent (save-excursion
  172.                  (c-backward-to-start-of-if)
  173.                  (current-indentation))))
  174.          ((= (following-char) ?})
  175.           (setq indent (- indent c-indent-level)))
  176.          ((= (following-char) ?{)
  177.           (setq indent (+ indent c-brace-offset))))))
  178.     (skip-chars-forward " \t")
  179.     (setq shift-amt (- indent (current-column)))
  180.     (if (zerop shift-amt)
  181.     (if (> (- (point-max) pos) (point))
  182.         (goto-char (- (point-max) pos)))
  183.       (delete-region beg (point))
  184.       (indent-to indent)
  185.       ;; If initial point was within line's indentation,
  186.       ;; position after the indentation.  Else stay at same point in text.
  187.       (if (> (- (point-max) pos) (point))
  188.       (goto-char (- (point-max) pos))))
  189.     shift-amt))
  190.  
  191. (defun calculate-java-indent (&optional parse-start)
  192.   "Return appropriate indentation for current line as Java code.
  193. In usual case returns an integer: the column to indent to.
  194. Returns nil if line starts inside a string, t if in a comment."
  195.   (save-excursion
  196.     (beginning-of-line)
  197.     (let ((indent-point (point))
  198.       (case-fold-search nil)
  199.       state
  200.       containing-sexp)
  201.       (if parse-start
  202.       (goto-char parse-start)
  203.     (beginning-of-java-class))
  204.       (while (< (point) indent-point)
  205.     (setq parse-start (point))
  206.     (setq state (parse-partial-sexp (point) indent-point 0))
  207.     (setq containing-sexp (car (cdr state))))
  208.       (cond ((or (nth 3 state) (nth 4 state))
  209.          ;; return nil or t if should not change this line
  210.          (nth 4 state))
  211.         ((null containing-sexp)
  212.          ;; Line is at top level.  May be class, data or method
  213.          ;; definition, or may be function argument declaration or
  214.          ;; member initialization.
  215.          ;; Indent like the previous top level line unless
  216.          ;; (1) the previous line ends in a closeparen without semicolon,
  217.          ;; in which case this line is the first argument declaration or
  218.          ;; member initialization, or
  219.          ;; (2) the previous line begins with a colon,
  220.          ;; in which case this is the second line of member inits.
  221.          ;; It is assumed that arg decls and member inits are not mixed.
  222.          (goto-char indent-point)
  223.          (skip-chars-forward " \t")
  224.          (if (= (following-char) ?{)
  225.          0   ; Unless it starts a method body
  226.            (c++-backward-to-noncomment (or parse-start (point-min)))
  227.            (if (= (preceding-char) ?\))
  228.            (progn        ; first arg decl or member init
  229.              (goto-char indent-point)
  230.              (skip-chars-forward " \t")
  231.              (if (= (following-char) ?:)
  232.              c++-member-init-indent
  233.                c-argdecl-indent))
  234.          (if (= (preceding-char) ?\;)
  235.              (backward-char 1))
  236.          (if (= (preceding-char) ?})
  237.              0
  238.            (beginning-of-line)    ; continued arg decls or member inits
  239.            (skip-chars-forward " \t")
  240.            (if (= (following-char) ?:)
  241.                (if c++-continued-member-init-offset
  242.                (+ (current-indentation)
  243.                   c++-continued-member-init-offset)
  244.              (progn
  245.                (forward-char 1)
  246.                (skip-chars-forward " \t")
  247.                (current-column)))
  248.              (current-indentation)))
  249.          )))
  250.         ((/= (char-after containing-sexp) ?{)
  251.          ;; line is expression, not statement:
  252.          ;; indent to just after the surrounding open -- unless
  253.          ;; empty arg list, in which case we do what
  254.          ;; c++-empty-arglist-indent says to do.
  255.          (if (and c++-empty-arglist-indent
  256.               (or (null (nth 2 state))    ;; indicates empty arg
  257.                         ;; list.
  258.               ;; Use a heuristic: if the first
  259.               ;; non-whitespace following left paren on
  260.               ;; same line is not a comment,
  261.               ;; is not an empty arglist.
  262.               (save-excursion
  263.                 (goto-char (1+ containing-sexp))
  264.                 (not
  265.                  (looking-at "\\( \\|\t\\)*[^/\n]")))))
  266.          (progn
  267.            (goto-char containing-sexp)
  268.            (beginning-of-line)
  269.            (skip-chars-forward " \t")
  270.            (goto-char (min (+ (point) c++-empty-arglist-indent)
  271.                    (1+ containing-sexp)))
  272.            (current-column))
  273.            ;; In C-mode, we would always indent to one after the
  274.            ;; left paren.  Here, though, we may have an
  275.            ;; empty-arglist, so we'll indent to the min of that
  276.            ;; and the beginning of the first argument.
  277.            (goto-char (1+ containing-sexp))
  278.            (current-column)))
  279.         (t
  280.          ;; Statement.  Find previous non-comment character.
  281.          (goto-char indent-point)
  282.          (c++-backward-to-noncomment containing-sexp)
  283.          (if (not (memq (preceding-char) '(nil ?\, ?\; ?} ?: ?\{)))
  284.          ;; This line is continuation of preceding line's statement;
  285.          ;; indent  c-continued-statement-offset  more than the
  286.          ;; previous line of the statement.
  287.          (progn
  288.            (c-backward-to-start-of-continued-exp containing-sexp)
  289.            (+ c-continued-statement-offset (current-column)
  290.                       (if (save-excursion (goto-char indent-point)
  291.                       (skip-chars-forward " \t")
  292.                       (eq (following-char) ?{))
  293.               c-continued-brace-offset 0)))
  294.            ;; This line starts a new statement.
  295.            ;; Position following last unclosed open.
  296.            (goto-char containing-sexp)
  297.            ;; Is line first statement after an open-brace?
  298.            (or
  299.          ;; If no, find that first statement and indent like it.
  300.          (save-excursion
  301.            (forward-char 1)
  302.            (while (progn (skip-chars-forward " \t\n")
  303.                  (looking-at
  304.                   (concat
  305.                    "/\\*\\|//"
  306.                    "\\|case[ \t]"
  307.                    "\\|[a-zA-Z0-9_$]*:[^:]")))
  308.              ;; Skip over comments and labels following openbrace.
  309.              (cond ((= (following-char) ?\#)
  310.                 (forward-line 1))
  311.                ((looking-at "/\\*")
  312.                 (search-forward "*/" nil 'move))
  313.                ((looking-at "//")
  314.                 (forward-line 1))
  315.                (t
  316.                 (re-search-forward ":[^:]" nil 'move))))
  317.               ;; The first following code counts
  318.               ;; if it is before the line we want to indent.
  319.               (and (< (point) indent-point)
  320.                (current-column)))
  321.          ;; If no previous statement,
  322.          ;; indent it relative to line brace is on.
  323.          ;; For open brace in column zero, don't let statement
  324.          ;; start there too.  If c-indent-offset is zero,
  325.          ;; use c-brace-offset + c-continued-statement-offset instead.
  326.          ;; For open-braces not the first thing in a line,
  327.          ;; add in c-brace-imaginary-offset.
  328.          (+ (if (and (bolp) (zerop c-indent-level))
  329.             (+ c-brace-offset c-continued-statement-offset)
  330.               c-indent-level)
  331.             ;; Move back over whitespace before the openbrace.
  332.             ;; If openbrace is not first nonwhite thing on the line,
  333.             ;; add the c-brace-imaginary-offset.
  334.             (progn (skip-chars-backward " \t")
  335.                (if (bolp) 0 c-brace-imaginary-offset))
  336.             ;; If the openbrace is preceded by a parenthesized exp,
  337.             ;; move to the beginning of that;
  338.             ;; possibly a different line
  339.             (progn
  340.               (if (eq (preceding-char) ?\))
  341.               (forward-sexp -1))
  342.               ;; Get initial indentation of the line we are on.
  343.               (current-indentation))))))))))
  344.  
  345. ;; This is lifted from emacs 19.28's lisp.el\beginning-of-defun.
  346. (defconst java-identifier-regexp "[A-Za-z][A-Za-z0-9_$]*"
  347.   "Regular expression to match a Java identifier.  (Does anyone know
  348. whether or not such identifiers can begin with '_' or '$'?)")
  349.  
  350. (defconst java-class-def-regexp
  351.   (concat "^\\(" java-identifier-regexp "[ \t]+\\)*"
  352.       "class[ \t]*")
  353.   "Regular expression to match a Java class definition.")
  354.  
  355. (defun beginning-of-java-class (&optional arg)
  356.   "Move point to the beginning of a Java class definition line.
  357. With argument, do it that many times.  Negative arg -N
  358. means move forward to Nth following beginning of class.
  359. Returns t unless search stops due to beginning or end of buffer."
  360.   (interactive "p")
  361.   (and (beginning-of-java-class-raw arg)
  362.        (progn (beginning-of-line) t)))
  363.  
  364. (defun beginning-of-java-class-raw (&optional arg)
  365.   "Move point to the character that starts a class definition.
  366. This is identical to beginning-of-java-class, except that point does not move
  367. to the beginning of the line."
  368.   (interactive "p")
  369.   (beginning-of-java-regexp java-class-def-regexp arg))
  370.  
  371. (defun beginning-of-java-regexp (rexpr &optional arg)
  372.   "Move point to the beginning of a regular expression.
  373. With argument, do it that many times.  Negative arg -N means move
  374. forward to Nth following beginning of rexpr.
  375. Returns t unless search stops due to beginning or end of buffer."
  376.   (interactive "p")
  377.   (and arg (< arg 0) (not (eobp)) (forward-char 1))
  378.   (and (re-search-backward rexpr nil 'move (or arg 1))
  379.        (progn (goto-char (1- (match-end 0)))) t))
  380.  
  381.  
  382. (defun end-of-java-class (&optional arg)
  383.   "Move point to the end of a Java class definition.
  384. With argument, do it that many times."
  385.   (interactive "p")
  386.   (beginning-of-java-class (- (1+ arg)))
  387.   (re-search-backward "^}" nil 'move))
  388.  
  389.  
  390. (defun beginning-of-java-method ()
  391.   "Goto the beginning of the enclosing Java method."
  392.   (interactive)
  393.   (let ((currpoint (point))
  394.     (at-beginning nil))
  395.     (while (and (not at-beginning)
  396.         (re-search-backward 
  397.          (concat "^[ \t]*"
  398.              "\\(" java-identifier-regexp "[ \t\n]+\\)*"
  399.              "\\(" java-identifier-regexp "[ \t\n]*\\)(")
  400.          (point-min) t))
  401.       (goto-char (match-beginning 2))
  402.       (setq at-beginning 
  403.         (and (not (or (looking-at "if")
  404.               (looking-at "else")
  405.               (looking-at "switch")))
  406.          (save-excursion
  407.            (re-search-forward ")[ \t]*{" currpoint t)))))
  408.     (if at-beginning
  409.     (beginning-of-line))))
  410.  
  411.  
  412.  
  413. ;;;
  414. ;;; Variables and functions for use with imenu -- lets you pop up a
  415. ;;; menu of functions defined in a Java module.
  416. ;;; 
  417. ;;; 
  418. ;; Regular expression to find Java functions
  419. ;; Okay, so this works only with ASCII...
  420. (defun java-imenu--function-name-regexp ()
  421.   (concat 
  422.    "^"
  423.    ;; Include the number of spaces which would lead a properly-
  424.    ;; indented Java member function.  This is a bad way to do
  425.    ;; business because it fails to find functions if things aren't
  426.    ;; already properly indented.
  427.    (make-string c-continued-statement-offset ? )
  428.    "[a-zA-Z0-9:]+[ \t]?"        ; type specs; there can be no
  429.    "\\([a-zA-Z0-9_$]+[ \t]+\\)?"    ; more than 3 tokens, right?
  430.    "\\([a-zA-Z0-9_$]+[ \t]+\\)?"
  431.    "\\([ \t]*\\)?"            ; pointer
  432.    "\\([a-zA-Z0-9_$]+\\)[ \t]*("    ; name
  433.    ))
  434.  
  435. (defun java-imenu--create-index ()
  436.   (imenu-example--create-c-index (java-imenu--function-name-regexp)))
  437.