-;;; perl-mode.el --- Perl code editing commands for GNU Emacs -*- coding: utf-8 -*-
+;;; perl-mode.el --- Perl code editing commands for GNU Emacs -*- lexical-binding:t -*-
;; Copyright (C) 1990, 1994, 2001-2013 Free Software Foundation, Inc.
(modify-syntax-entry ?\n ">" st)
(modify-syntax-entry ?# "<" st)
;; `$' is also a prefix char so I was tempted to say "/ p",
- ;; but the `p' thingy basically overrides the `/' :-( --stef
+ ;; but the `p' thingy basically overrides the `/' :-( -- Stef
(modify-syntax-entry ?$ "/" st)
(modify-syntax-entry ?% ". p" st)
(modify-syntax-entry ?@ ". p" st)
(defvar perl-imenu-generic-expression
'(;; Functions
- (nil "^[ \t]*sub\\s-+\\([-A-Za-z0-9+_:]+\\)" 1)
+ (nil "^[ \t]*sub\\s-+\\([-[:alnum:]+_:]+\\)" 1)
;;Variables
- ("Variables" "^\\(?:my\\|our\\)\\s-+\\([$@%][-A-Za-z0-9+_:]+\\)\\s-*=" 1)
- ("Packages" "^[ \t]*package\\s-+\\([-A-Za-z0-9+_:]+\\);" 1)
+ ("Variables" "^\\(?:my\\|our\\)\\s-+\\([$@%][-[:alnum:]+_:]+\\)\\s-*=" 1)
+ ("Packages" "^[ \t]*package\\s-+\\([-[:alnum:]+_:]+\\);" 1)
("Doc sections" "^=head[0-9][ \t]+\\(.*\\)" 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>.
-(defcustom perl-prettify-symbols t
- "If non-nil, some symbols will be displayed using Unicode chars."
- :type 'boolean)
-
(defconst perl--prettify-symbols-alist
- '(;;("andalso" . ?∧) ("orelse" . ?∨) ("as" . ?≡)("not" . ?¬)
- ;;("div" . ?÷) ("*" . ?×) ("o" . ?○)
- ("->" . ?→)
+ '(("->" . ?→)
("=>" . ?⇒)
- ;;("<-" . ?←) ("<>" . ?≠) (">=" . ?≥) ("<=" . ?≤) ("..." . ?⋯)
- ("::" . ?∷)
- ))
-
-(defun perl--font-lock-compose-symbol ()
- "Compose a sequence of ascii chars into a symbol.
-Regexp match data 0 points to the chars."
- ;; Check that the chars should really be composed into a symbol.
- (let* ((start (match-beginning 0))
- (end (match-end 0))
- (syntaxes (if (eq (char-syntax (char-after start)) ?w)
- '(?w) '(?. ?\\))))
- (if (or (memq (char-syntax (or (char-before start) ?\ )) syntaxes)
- (memq (char-syntax (or (char-after end) ?\ )) syntaxes)
- (nth 8 (syntax-ppss)))
- ;; No composition for you. Let's actually remove any composition
- ;; we may have added earlier and which is now incorrect.
- (remove-text-properties start end '(composition))
- ;; That's a symbol alright, so add the composition.
- (compose-region start end (cdr (assoc (match-string 0)
- perl--prettify-symbols-alist)))))
- ;; Return nil because we're not adding any face property.
- nil)
-
-(defun perl--font-lock-symbols-keywords ()
- (when perl-prettify-symbols
- `((,(regexp-opt (mapcar 'car perl--prettify-symbols-alist) t)
- (0 (perl--font-lock-compose-symbol))))))
+ ("::" . ?∷)))
(defconst perl-font-lock-keywords-1
'(;; What is this for?
;; 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)
- ,@(perl--font-lock-symbols-keywords)))
+ ("^[ \t]*\\(\\sw+\\)[ \t]*:[^:]" 1 font-lock-constant-face)))
"Gaudy level highlighting for Perl mode.")
(defvar perl-font-lock-keywords perl-font-lock-keywords-1
(let ((case-fold-search nil))
(goto-char start)
(perl-syntax-propertize-special-constructs end)
- ;; TODO: here-documents ("<<\\(\\sw\\|['\"]\\)")
(funcall
(syntax-propertize-rules
;; Turn POD into b-style comments. Place the cut rule first since it's
;; check that it occurs inside a '..' string.
("\\(\\$\\)[{']" (1 ". p"))
;; Handle funny names like $DB'stop.
- ("\\$ ?{?^?[_a-zA-Z][_a-zA-Z0-9]*\\('\\)[_a-zA-Z]" (1 "_"))
+ ("\\$ ?{?^?[_[:alpha:]][_[:alnum:]]*\\('\\)[_[:alpha:]]" (1 "_"))
;; format statements
("^[ \t]*format.*=[ \t]*\\(\n\\)"
(1 (prog1 "\"" (perl-syntax-propertize-special-constructs end))))
perl-quote-like-pairs)
(string-to-syntax "|")
(string-to-syntax "\"")))
- (perl-syntax-propertize-special-constructs end))))))
+ (perl-syntax-propertize-special-constructs end)))))
+ ;; Here documents.
+ ;; TODO: Handle <<WORD. These are trickier because you need to
+ ;; disambiguate with the shift operator.
+ ("<<[ \t]*\\('[^'\n]*'\\|\"[^\"\n]*\"\\|\\\\[[:alpha:]][[:alnum:]]*\\).*\\(\n\\)"
+ (2 (let* ((st (get-text-property (match-beginning 2) 'syntax-table))
+ (name (match-string 1)))
+ (goto-char (match-end 1))
+ (if (save-excursion (nth 8 (syntax-ppss (match-beginning 0))))
+ ;; Leave the property of the newline unchanged.
+ st
+ (cons (car (string-to-syntax "< c"))
+ ;; Remember the names of heredocs found on this line.
+ (cons (pcase (aref name 0)
+ (`?\\ (substring name 1))
+ (_ (substring name 1 -1)))
+ (cdr st)))))))
+ ;; We don't call perl-syntax-propertize-special-constructs directly
+ ;; from the << rule, because there might be other elements (between
+ ;; the << and the \n) that need to be propertized.
+ ("\\(?:$\\)\\s<"
+ (0 (ignore (perl-syntax-propertize-special-constructs end))))
+ )
(point) end)))
(defvar perl-empty-syntax-table
(let ((state (syntax-ppss))
char)
(cond
+ ((eq 2 (nth 7 state))
+ ;; A Here document.
+ (let ((names (cdr (get-text-property (nth 8 state) 'syntax-table))))
+ (when (cdr names)
+ (setq names (reverse names))
+ ;; Multiple heredocs on a single line, we have to search from the
+ ;; beginning, since we don't know which names might be
+ ;; before point.
+ (goto-char (nth 8 state)))
+ (while (and names
+ (re-search-forward
+ (concat "^" (regexp-quote (pop names)) "\n")
+ limit 'move))
+ (unless names
+ (put-text-property (1- (point)) (point) 'syntax-table
+ (string-to-syntax "> c"))))))
((or (null (setq char (nth 3 state)))
(and (characterp char) (eq (char-syntax (nth 3 state)) ?\")))
;; Normal text, or comment, or docstring, or normal string.
(defcustom perl-indent-level 4
"Indentation of Perl statements with respect to containing block."
- :type 'integer
- :group 'perl)
+ :type 'integer)
;; Is is not unusual to put both things like perl-indent-level and
;; cperl-indent-level in the local variable section of a file. If only
(defcustom perl-continued-statement-offset 4
"Extra indent for lines not starting new statements."
- :type 'integer
- :group 'perl)
+ :type 'integer)
(defcustom perl-continued-brace-offset -4
"Extra indent for substatements that start with open-braces.
This is in addition to `perl-continued-statement-offset'."
- :type 'integer
- :group 'perl)
+ :type 'integer)
(defcustom perl-brace-offset 0
"Extra indentation for braces, compared with other text in same context."
- :type 'integer
- :group 'perl)
+ :type 'integer)
(defcustom perl-brace-imaginary-offset 0
"Imagined indentation of an open brace that actually follows a statement."
- :type 'integer
- :group 'perl)
+ :type 'integer)
(defcustom perl-label-offset -2
"Offset of Perl label lines relative to usual indentation."
- :type 'integer
- :group 'perl)
+ :type 'integer)
(defcustom perl-indent-continued-arguments nil
"If non-nil offset of argument lines relative to usual indentation.
If nil, continued arguments are aligned with the first argument."
- :type '(choice integer (const nil))
- :group 'perl)
+ :type '(choice integer (const nil)))
(defcustom perl-indent-parens-as-block nil
"Non-nil means that non-block ()-, {}- and []-groups are indented as blocks.
The closing bracket is aligned with the line of the opening bracket,
not the contents of the brackets."
:version "24.3"
- :type 'boolean
- :group 'perl)
+ :type 'boolean)
(defcustom perl-tab-always-indent tab-always-indent
"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)
+ :type 'boolean)
;; I changed the default to nil for consistency with general Emacs
;; conventions -- rms.
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)
+ :type 'boolean)
-(defcustom perl-nochange ";?#\\|\f\\|\\s(\\|\\(\\w\\|\\s_\\)+:[^:]"
+(defcustom perl-nochange "\f"
"Lines starting with this regular expression are not auto-indented."
:type 'regexp
- :group 'perl)
+ :options '(";?#\\|\f\\|\\s(\\|\\(\\w\\|\\s_\\)+:[^:]"))
;; Outline support
(setq-local comment-start-skip "\\(^\\|\\s-\\);?#+ *")
(setq-local comment-indent-function #'perl-comment-indent)
(setq-local parse-sexp-ignore-comments t)
+
;; Tell font-lock.el how to handle Perl.
(setq font-lock-defaults '((perl-font-lock-keywords
- perl-font-lock-keywords-1
- perl-font-lock-keywords-2)
- nil nil ((?\_ . "w")) nil
+ perl-font-lock-keywords-1
+ perl-font-lock-keywords-2)
+ nil nil ((?\_ . "w")) nil
(font-lock-syntactic-face-function
. perl-font-lock-syntactic-face-function)))
+ (setq-local prettify-symbols-alist perl--prettify-symbols-alist)
(setq-local syntax-propertize-function #'perl-syntax-propertize-function)
(add-hook 'syntax-propertize-extend-region-functions
#'syntax-propertize-multiline 'append 'local)
(define-obsolete-function-alias 'electric-perl-terminator
'perl-electric-terminator "22.1")
-(defun perl-electric-noindent-p (char)
+(defun perl-electric-noindent-p (_char)
(unless (eolp) 'no-indent))
(defun perl-electric-terminator (arg)
changed by, or (parse-state) if line starts in a quoted string."
(let ((case-fold-search nil)
(pos (- (point-max) (point)))
- (bof (or parse-start (save-excursion (perl-beginning-of-function))))
+ (bof (or parse-start (save-excursion
+ ;; Don't consider text on this line as a
+ ;; valid BOF from which to indent.
+ (goto-char (line-end-position 0))
+ (perl-beginning-of-function))))
beg indent shift-amt)
(beginning-of-line)
(setq beg (point))