]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/perl-mode.el
(tar-mode): Position point on the name of the first file.
[gnu-emacs] / lisp / progmodes / perl-mode.el
index 5afd03adc7424cbec3bce81494c9b2bffa34b6b7..0772d565a88010a265fed1ea70efcef98cf7773f 100644 (file)
@@ -1,8 +1,9 @@
 ;;; perl-mode.el --- Perl code editing commands for GNU Emacs
 
-;; Copyright (C) 1990  Free Software Foundation, Inc.
+;; Copyright (C) 1990, 1994  Free Software Foundation, Inc.
 
 ;; Author: William F. Mann
+;; Maintainer: FSF
 ;; Adapted-By: ESR
 ;; Keywords: languages
 
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
 
 ;;; Commentary:
 
 ;; To enter perl-mode automatically, add (autoload 'perl-mode "perl-mode")
 ;; to your .emacs file and change the first line of your perl script to:
 ;; #!/usr/bin/perl --   # -*-Perl-*-
-;; With argments to perl:
+;; With arguments to perl:
 ;; #!/usr/bin/perl -P-  # -*-Perl-*-
 ;; To handle files included with do 'filename.pl';, add something like
-;; (setq auto-mode-alist (append (list (cons "\\.pl$" 'perl-mode))
+;; (setq auto-mode-alist (append (list (cons "\\.pl\\'" 'perl-mode))
 ;;                               auto-mode-alist))
 ;; to your .emacs file; otherwise the .pl suffix defaults to prolog-mode.
 
@@ -64,7 +66,7 @@
 ;; Known problems (these are all caused by limitations in the Emacs Lisp
 ;; parsing routine (parse-partial-sexp), which was not designed for such
 ;; a rich language; writing a more suitable parser would be a big job):
-;; 1)  Regular expression delimitors do not act as quotes, so special
+;; 1)  Regular expression delimiters do not act as quotes, so special
 ;;       characters such as `'"#:;[](){} may need to be backslashed
 ;;       in regular expressions and in both parts of s/// and tr///.
 ;; 2)  The globbing syntax <pattern> is not recognized, so special
 
 ;;; Code:
 
+(defgroup perl nil
+  "Major mode for editing Perl code."
+  :prefix "perl-"
+  :group 'languages)
+
 (defvar perl-mode-abbrev-table nil
   "Abbrev table in use in perl-mode buffers.")
 (define-abbrev-table 'perl-mode-abbrev-table ())
@@ -146,32 +153,125 @@ The expansion is entirely correct because it uses the C preprocessor."
   (modify-syntax-entry ?| "." perl-mode-syntax-table)
 )
 
-(defconst perl-indent-level 4
-  "*Indentation of Perl statements with respect to containing block.")
-(defconst perl-continued-statement-offset 4
-  "*Extra indent for lines not starting new statements.")
-(defconst perl-continued-brace-offset -4
+(defvar perl-imenu-generic-expression
+  '(
+    ;; Functions
+    (nil "^sub\\s-+\\([-A-Za-z0-9+_:]+\\)\\(\\s-\\|\n\\)*{" 1 )
+    ;;Variables
+    ("Variables" "^\\([$@%][-A-Za-z0-9+_:]+\\)\\s-*=" 1 )
+    ("Packages" "^package\\s-+\\([-A-Za-z0-9+_:]+\\);" 1 )
+    )
+  "Imenu generic expression for Perl mode.  See `imenu-generic-expression'.")
+
+;; Regexps updated with help from Tom Tromey <tromey@cambric.colorado.edu> and
+;; Jim Campbell <jec@murzim.ca.boeing.com>.
+
+(defconst perl-font-lock-keywords-1
+  '(;; What is this for?
+    ;;("\\(--- .* ---\\|=== .* ===\\)" . font-lock-string-face)
+    ;;
+    ;; Fontify preprocessor statements as we do in `c-font-lock-keywords'.
+    ;; Ilya Zakharevich <ilya@math.ohio-state.edu> thinks this is a bad idea.
+    ("^#[ \t]*include[ \t]+\\(<[^>\"\n]+>\\)" 1 font-lock-string-face)
+    ("^#[ \t]*define[ \t]+\\(\\sw+\\)(" 1 font-lock-function-name-face)
+    ("^#[ \t]*if\\>"
+     ("\\<\\(defined\\)\\>[ \t]*(?\\(\\sw+\\)?" nil nil
+      (1 font-lock-constant-face) (2 font-lock-variable-name-face nil t)))
+    ("^#[ \t]*\\(\\sw+\\)\\>[ \t]*\\(\\sw+\\)?"
+     (1 font-lock-constant-face) (2 font-lock-variable-name-face nil t))
+    ;;
+    ;; Fontify function and package names in declarations.
+    ("\\<\\(package\\|sub\\)\\>[ \t]*\\(\\sw+\\)?"
+     (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t))
+    ("\\<\\(import\\|no\\|require\\|use\\)\\>[ \t]*\\(\\sw+\\)?"
+     (1 font-lock-keyword-face) (2 font-lock-constant-face nil t)))
+  "Subdued level highlighting for Perl mode.")
+
+(defconst perl-font-lock-keywords-2
+  (append perl-font-lock-keywords-1
+   (list
+    ;;
+    ;; Fontify keywords, except those fontified otherwise.
+;   (make-regexp '("if" "until" "while" "elsif" "else" "unless" "do" "dump"
+;  "for" "foreach" "exit" "die"
+;  "BEGIN" "END" "return" "exec" "eval"))
+    (concat "\\<\\("
+           "BEGIN\\|END\\|d\\(ie\\|o\\|ump\\)\\|"
+           "e\\(ls\\(e\\|if\\)\\|val\\|x\\(ec\\|it\\)\\)\\|"
+           "for\\(\\|each\\)\\|if\\|return\\|un\\(less\\|til\\)\\|while"
+           "\\)\\>")
+    ;;
+    ;; Fontify local and my keywords as types.
+    '("\\<\\(local\\|my\\)\\>" . font-lock-type-face)
+    ;;
+    ;; Fontify function, variable and file name references.
+    '("&\\(\\sw+\\)" 1 font-lock-function-name-face)
+    ;; Additionally underline non-scalar variables.  Maybe this is a bad idea.
+    ;;'("[$@%*][#{]?\\(\\sw+\\)" 1 font-lock-variable-name-face)
+    '("[$*]{?\\(\\sw+\\)" 1 font-lock-variable-name-face)
+    '("\\([@%]\\|\\$#\\)\\(\\sw+\\)"
+      (2 (cons font-lock-variable-name-face '(underline))))
+    '("<\\(\\sw+\\)>" 1 font-lock-constant-face)
+    ;;
+    ;; Fontify keywords with/and labels as we do in `c++-font-lock-keywords'.
+    '("\\<\\(continue\\|goto\\|last\\|next\\|redo\\)\\>[ \t]*\\(\\sw+\\)?"
+      (1 font-lock-keyword-face) (2 font-lock-constant-face nil t))
+    '("^[ \t]*\\(\\sw+\\)[ \t]*:[^:]" 1 font-lock-constant-face)))
+  "Gaudy level highlighting for Perl mode.")
+
+(defvar perl-font-lock-keywords perl-font-lock-keywords-1
+  "Default expressions to highlight in Perl mode.")
+
+
+(defcustom perl-indent-level 4
+  "*Indentation of Perl statements with respect to containing block."
+  :type 'integer
+  :group 'perl)
+(defcustom perl-continued-statement-offset 4
+  "*Extra indent for lines not starting new statements."
+  :type 'integer
+  :group 'perl)
+(defcustom perl-continued-brace-offset -4
   "*Extra indent for substatements that start with open-braces.
-This is in addition to perl-continued-statement-offset.")
-(defconst perl-brace-offset 0
-  "*Extra indentation for braces, compared with other text in same context.")
-(defconst perl-brace-imaginary-offset 0
-  "*Imagined indentation of an open brace that actually follows a statement.")
-(defconst perl-label-offset -2
-  "*Offset of Perl label lines relative to usual indentation.")
-
-(defconst perl-tab-always-indent t
-  "*Non-nil means TAB in Perl mode should always indent the current line,
-regardless of where in the line point is when the TAB command is used.")
-
-(defconst perl-tab-to-comment t
-  "*Non-nil means that for lines which don't need indenting, TAB will
-either indent an existing comment, move to end-of-line, or if at end-of-line
-already, create a new comment.")
-
-(defconst perl-nochange ";?#\\|\f\\|\\s(\\|\\(\\w\\|\\s_\\)+:"
-  "*Lines starting with this regular expression will not be auto-indented.")
+This is in addition to `perl-continued-statement-offset'."
+  :type 'integer
+  :group 'perl)
+(defcustom perl-brace-offset 0
+  "*Extra indentation for braces, compared with other text in same context."
+  :type 'integer
+  :group 'perl)
+(defcustom perl-brace-imaginary-offset 0
+  "*Imagined indentation of an open brace that actually follows a statement."
+  :type 'integer
+  :group 'perl)
+(defcustom perl-label-offset -2
+  "*Offset of Perl label lines relative to usual indentation."
+  :type 'integer
+  :group 'perl)
+
+(defcustom perl-tab-always-indent t
+  "*Non-nil means TAB in Perl mode always indents the current line.
+Otherwise it inserts a tab character if you type it past the first
+nonwhite character on the line."
+  :type 'boolean
+  :group 'perl)
+
+;; I changed the default to nil for consistency with general Emacs
+;; conventions -- rms.
+(defcustom perl-tab-to-comment nil
+  "*Non-nil means TAB moves to eol or makes a comment in some cases.
+For lines which don't need indenting, TAB either indents an
+existing comment, moves to end-of-line, or if at end-of-line already,
+create a new comment."
+  :type 'boolean
+  :group 'perl)
+
+(defcustom perl-nochange ";?#\\|\f\\|\\s(\\|\\(\\w\\|\\s_\\)+:"
+  "*Lines starting with this regular expression are not auto-indented."
+  :type 'regexp
+  :group 'perl)
 \f
+;;;###autoload
 (defun perl-mode ()
   "Major mode for editing Perl code.
 Expression and list commands understand all Perl brackets.
@@ -189,7 +289,7 @@ Variables controlling indentation style:
     either delete an empty comment, indent an existing comment, move 
     to end-of-line, or if at end-of-line already, create a new comment.
  perl-nochange
-    Lines starting with this regular expression will not be auto-indented.
+    Lines starting with this regular expression are not auto-indented.
  perl-indent-level
     Indentation of Perl statements within surrounding block.
     The surrounding block's indentation is the indentation
@@ -199,7 +299,7 @@ Variables controlling indentation style:
     then-clause of an if or body of a while.
  perl-continued-brace-offset
     Extra indentation given to a brace that starts a substatement.
-    This is in addition to perl-continued-statement-offset.
+    This is in addition to `perl-continued-statement-offset'.
  perl-brace-offset
     Extra indentation for line if it starts with an open brace.
  perl-brace-imaginary-offset
@@ -216,8 +316,7 @@ Various indentation styles:       K&R  BSD  BLK  GNU  LW
   perl-brace-imaginary-offset      0    0    4    0    0
   perl-label-offset               -5   -8   -2   -2   -2
 
-Turning on Perl mode calls the value of the variable perl-mode-hook with no 
-args, if that value is non-nil."
+Turning on Perl mode runs the normal hook `perl-mode-hook'."
   (interactive)
   (kill-all-local-variables)
   (use-local-map perl-mode-map)
@@ -226,7 +325,7 @@ args, if that value is non-nil."
   (setq local-abbrev-table perl-mode-abbrev-table)
   (set-syntax-table perl-mode-syntax-table)
   (make-local-variable 'paragraph-start)
-  (setq paragraph-start (concat "^$\\|" page-delimiter))
+  (setq paragraph-start (concat "$\\|" page-delimiter))
   (make-local-variable 'paragraph-separate)
   (setq paragraph-separate paragraph-start)
   (make-local-variable 'paragraph-ignore-fill-prefix)
@@ -246,7 +345,17 @@ args, if that value is non-nil."
   (make-local-variable 'comment-indent-function)
   (setq comment-indent-function 'perl-comment-indent)
   (make-local-variable 'parse-sexp-ignore-comments)
-  (setq parse-sexp-ignore-comments nil)
+  (setq parse-sexp-ignore-comments t)
+  ;; Tell font-lock.el how to handle Perl.
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '((perl-font-lock-keywords
+                             perl-font-lock-keywords-1
+                             perl-font-lock-keywords-2)
+                            nil nil ((?\_ . "w"))))
+  ;; Tell imenu how to handle Perl.
+  (make-local-variable 'imenu-generic-expression)
+  (setq imenu-generic-expression perl-imenu-generic-expression)
+  (setq imenu-case-fold-search nil)
   (run-hooks 'perl-mode-hook))
 \f
 ;; This is used by indent-for-comment
@@ -257,12 +366,14 @@ args, if that value is non-nil."
       0                                        ;Existing comment at bol stays there.
     (save-excursion
       (skip-chars-backward " \t")
-      (max (1+ (current-column))       ;Else indent at comment column
-          comment-column))))           ; except leave at least one space.
+      (max (if (bolp)                  ;Else indent at comment column
+              0                        ; except leave at least one space if
+            (1+ (current-column)))     ; not at beginning of line.
+          comment-column))))
 
 (defun electric-perl-terminator (arg)
-  "Insert character.  If at end-of-line, and not in a comment or a quote,
-correct the line's indentation."
+  "Insert character and adjust indentation.
+If at end-of-line, and not in a comment or a quote, correct the's indentation."
   (interactive "P")
   (let ((insertpos (point)))
     (and (not arg)                     ; decide whether to indent
@@ -270,7 +381,8 @@ correct the line's indentation."
         (save-excursion
           (beginning-of-line)
           (and (not                    ; eliminate comments quickly
-                (re-search-forward comment-start-skip insertpos t)) 
+                (and comment-start-skip
+                     (re-search-forward comment-start-skip insertpos t)) )
                (or (/= last-command-char ?:)
                    ;; Colon is special only after a label ....
                    (looking-at "\\s-*\\(\\w\\|\\s_\\)+$"))
@@ -299,13 +411,13 @@ correct the line's indentation."
 
 With an argument, indent the current line, regardless of other options.
 
-If perl-tab-always-indent is nil and point is not in the indentation
+If `perl-tab-always-indent' is nil and point is not in the indentation
 area at the beginning of the line, simply insert a tab.
 
 Otherwise, indent the current line.  If point was within the indentation
 area it is moved to the end of the indentation area.  If the line was
 already indented properly and point was not within the indentation area,
-and if perl-tab-to-comment is non-nil (the default), then do the first
+and if `perl-tab-to-comment' is non-nil (the default), then do the first
 possible action from the following list:
 
   1) delete an empty comment
@@ -317,7 +429,7 @@ possible action from the following list:
   (if arg                              ; If arg, just indent this line
       (perl-indent-line "\f")
     (if (and (not perl-tab-always-indent)
-            (<= (current-column) (current-indentation)))
+            (> (current-column) (current-indentation)))
        (insert-tab)
       (let (bof lsexp delta (oldpnt (point)))
        (beginning-of-line) 
@@ -345,7 +457,8 @@ possible action from the following list:
                       (if (= oldpnt eol) ; no comment, create one?
                           (indent-for-comment))
                     (beginning-of-line)
-                    (if (re-search-forward comment-start-skip eol 'move)
+                    (if (and comment-start-skip
+                             (re-search-forward comment-start-skip eol 'move))
                         (if (eolp)
                             (progn     ; kill existing comment
                               (goto-char (match-beginning 0))
@@ -360,7 +473,8 @@ possible action from the following list:
                         (ding t))))))))))))
 
 (defun perl-indent-line (&optional nochange parse-start)
-  "Indent current line as Perl code.  Return the amount the indentation 
+  "Indent current line as Perl code.
+Return the amount the indentation 
 changed by, or (parse-state) if line starts in a quoted string."
   (let ((case-fold-search nil)
        (pos (- (point-max) (point)))
@@ -426,6 +540,7 @@ Returns (parse-state) if line starts inside a string."
             ;; line is expression, not statement:
             ;; indent to just after the surrounding open.
             (goto-char (1+ containing-sexp))
+            (skip-chars-forward " \t")
             (current-column))
            (t
             ;; Statement level.  Is it a continuation or a new statement?
@@ -438,8 +553,8 @@ Returns (parse-state) if line starts inside a string."
                             (memq (char-syntax (char-after (- (point) 2)))
                                   '(?w ?_))))
               (if (eq (preceding-char) ?\,)
-                  (perl-backward-to-start-of-continued-exp containing-sexp))
-              (beginning-of-line)
+                  (perl-backward-to-start-of-continued-exp containing-sexp)
+                (beginning-of-line))
               (perl-backward-to-noncomment))
             ;; Now we get the answer.
             (if (not (memq (preceding-char) '(?\; ?\} ?\{)))
@@ -512,7 +627,8 @@ Returns (parse-state) if line starts inside a string."
     (while (not stop)
       (setq opoint (point))
       (beginning-of-line)
-      (if (re-search-forward comment-start-skip opoint 'move 1)
+      (if (and comment-start-skip
+              (re-search-forward comment-start-skip opoint 'move 1))
          (progn (goto-char (match-end 1))
                 (skip-chars-forward ";")))
       (skip-chars-backward " \t\f")
@@ -565,7 +681,8 @@ Returns (parse-state) if line starts inside a string."
                      (listp delta)
                      (and (/= 0 delta)
                           (= (- (current-indentation) delta) comment-column)))
-                 (if (re-search-forward comment-start-skip eol t)
+                 (if (and comment-start-skip
+                          (re-search-forward comment-start-skip eol t))
                      (indent-for-comment))))) ; indent existing comment
        (forward-line 1))
       (goto-char (marker-position oldpnt))
@@ -635,4 +752,6 @@ With argument, repeat that many times; negative args move backward."
   (perl-beginning-of-function)
   (backward-paragraph))
 
-;;;;;;;; That's all, folks! ;;;;;;;;;
+(provide 'perl-mode)
+
+;;; perl-mode.el ends here