diff options
Diffstat (limited to 'lisp/progmodes/perl-mode.el')
-rw-r--r-- | lisp/progmodes/perl-mode.el | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/lisp/progmodes/perl-mode.el b/lisp/progmodes/perl-mode.el index 81a765d6f0c..f6c4dbed1e2 100644 --- a/lisp/progmodes/perl-mode.el +++ b/lisp/progmodes/perl-mode.el @@ -223,7 +223,10 @@ "\\|=>" "\\|[?:.,;|&*=!~({[]" "\\|[^-+][-+]" ;Bug#42168: `+' is intro but `++' isn't! - "\\|\\(^\\)\\)[ \t\n]*"))) + "\\|\\(^\\)\\)[ \t\n]*")) + + (defconst perl--format-regexp "^[ \t]*format.*=[ \t]*\\(\n\\)" + "Regexp to match the start of a format declaration.")) (defun perl-syntax-propertize-function (start end) (let ((case-fold-search nil)) @@ -248,11 +251,20 @@ ;; correctly the \() construct (Bug#11996) as well as references ;; to string values. ("\\(\\\\\\)['`\"($]" (1 (unless (nth 3 (syntax-ppss)) - (string-to-syntax ".")))) + (string-to-syntax ".")))) + ;; A "$" in Perl code must escape the next char to protect against + ;; misinterpreting Perl's punctuation variables as unbalanced + ;; quotes or parens. This is not needed in strings and broken in + ;; the special case of "$\"" (Bug#69604). Make "$" a punctuation + ;; char in strings. + ("\\$" (0 (if (save-excursion + (nth 3 (syntax-ppss (match-beginning 0)))) + (string-to-syntax ".") + (string-to-syntax "/")))) ;; Handle funny names like $DB'stop. ("\\$ ?{?\\^?[_[:alpha:]][_[:alnum:]]*\\('\\)[_[:alpha:]]" (1 "_")) ;; format statements - ("^[ \t]*format.*=[ \t]*\\(\n\\)" + (perl--format-regexp (1 (prog1 "\"" (perl-syntax-propertize-special-constructs end)))) ;; Propertize perl prototype chars `$%&*;+@\[]' as punctuation ;; in `sub' arg-specs like `sub myfun ($)' and `sub ($)'. But @@ -946,6 +958,17 @@ changed by, or (parse-state) if line starts in a quoted string." (goto-char (- (point-max) pos))) shift-amt)) +(defun perl--end-of-format-p () + "Non-nil if point is at the end of a format declaration, skipping whitespace." + (save-excursion + (skip-chars-backward " \t\n") + (beginning-of-line) + (when-let ((comm (and (looking-at "^\\.$") + (nth 8 (syntax-ppss))))) + (goto-char comm) + (beginning-of-line) + (looking-at perl--format-regexp)))) + (defun perl-continuation-line-p () "Move to end of previous line and return non-nil if continued." ;; Statement level. Is it a continuation or a new statement? @@ -959,12 +982,13 @@ changed by, or (parse-state) if line starts in a quoted string." (beginning-of-line) (perl-backward-to-noncomment)) ;; Now we get the answer. - (unless (memq (preceding-char) '(?\; ?\} ?\{)) + (unless (or (memq (preceding-char) '(?\; ?\} ?\{)) + (perl--end-of-format-p)) (preceding-char))) (defun perl-hanging-paren-p () "Non-nil if we are right after a hanging parenthesis-like char." - (and (looking-at "[ \t]*$") + (and (looking-at "[ \t]*\\(?:#.*\\)?$") (save-excursion (skip-syntax-backward " (") (not (bolp))))) @@ -999,7 +1023,9 @@ Returns (parse-state) if line starts inside a string." (state (syntax-ppss)) (containing-sexp (nth 1 state)) ;; Don't auto-indent in a quoted string or a here-document. - (unindentable (or (nth 3 state) (eq 2 (nth 7 state))))) + (unindentable (or (nth 3 state) (eq 2 (nth 7 state)))) + (format (and (nth 3 state) + (char-equal (nth 3 state) ?\n)))) (when (and (eq t (nth 3 state)) (save-excursion (goto-char (nth 8 state)) @@ -1009,7 +1035,7 @@ Returns (parse-state) if line starts inside a string." (setq unindentable nil) (setq containing-sexp (nth 8 state))) (cond - (unindentable 'noindent) + (unindentable (if format 0 'noindent)) ((null containing-sexp) ; Line is at top level. (skip-chars-forward " \t\f") (if (memq (following-char) @@ -1018,7 +1044,8 @@ Returns (parse-state) if line starts inside a string." ;; indent a little if this is a continuation line (perl-backward-to-noncomment) (if (or (bobp) - (memq (preceding-char) '(?\; ?\}))) + (memq (preceding-char) '(?\; ?\})) + (perl--end-of-format-p)) 0 perl-continued-statement-offset))) ((/= (char-after containing-sexp) ?{) ;; line is expression, not statement: |