]> 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 ac2c260ad0b97afc9a3ad050b788ed943ee43431..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.
 
 
 ;;; 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,33 +153,123 @@ The expansion is entirely correct because it uses the C preprocessor."
   (modify-syntax-entry ?| "." perl-mode-syntax-table)
 )
 
-(defvar perl-indent-level 4
-  "*Indentation of Perl statements with respect to containing block.")
-(defvar perl-continued-statement-offset 4
-  "*Extra indent for lines not starting new statements.")
-(defvar 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'.")
-(defvar perl-brace-offset 0
-  "*Extra indentation for braces, compared with other text in same context.")
-(defvar perl-brace-imaginary-offset 0
-  "*Imagined indentation of an open brace that actually follows a statement.")
-(defvar perl-label-offset -2
-  "*Offset of Perl label lines relative to usual indentation.")
-
-(defvar perl-tab-always-indent t
+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.")
+nonwhite character on the line."
+  :type 'boolean
+  :group 'perl)
 
-(defvar perl-tab-to-comment t
+;; 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.")
-
-(defvar perl-nochange ";?#\\|\f\\|\\s(\\|\\(\\w\\|\\s_\\)+:"
-  "*Lines starting with this regular expression are not auto-indented.")
+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 ()
@@ -228,7 +325,7 @@ Turning on Perl mode runs the normal hook `perl-mode-hook'."
   (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)
@@ -249,6 +346,16 @@ Turning on Perl mode runs the normal hook `perl-mode-hook'."
   (setq comment-indent-function 'perl-comment-indent)
   (make-local-variable 'parse-sexp-ignore-comments)
   (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
@@ -259,8 +366,10 @@ Turning on Perl mode runs the normal hook `perl-mode-hook'."
       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 and adjust indentation.
@@ -272,7 +381,8 @@ If at end-of-line, and not in a comment or a quote, correct the'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_\\)+$"))
@@ -319,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) 
@@ -347,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))
@@ -429,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?
@@ -441,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) '(?\; ?\} ?\{)))
@@ -515,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")
@@ -568,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))
@@ -638,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