1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-24 10:38:38 +00:00

Fix indentation in perl-mode (Bug#35925)

* lisp/progmodes/perl-mode.el (perl--format-regexp): New defconst.
(perl--end-of-format-p): New function.
(perl-continuation-line-p): Use it.
(perl-calculate-indent): Use it.  Make the lines of the formlist stay
at column 0.

* test/lisp/progmodes/cperl-mode-resources/cperl-bug-35925.pl: New
test file.

* test/lisp/progmodes/cperl-mode-tests.el (cperl-test-bug-35925): New
test.
This commit is contained in:
Mauro Aranda 2023-09-16 18:15:40 -03:00 committed by Stefan Kangas
parent 6dd1565fcf
commit 7caa3f5499
3 changed files with 74 additions and 6 deletions

View File

@ -223,7 +223,10 @@
"\\|=>" "\\|=>"
"\\|[?:.,;|&*=!~({[]" "\\|[?:.,;|&*=!~({[]"
"\\|[^-+][-+]" ;Bug#42168: `+' is intro but `++' isn't! "\\|[^-+][-+]" ;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) (defun perl-syntax-propertize-function (start end)
(let ((case-fold-search nil)) (let ((case-fold-search nil))
@ -252,7 +255,7 @@
;; Handle funny names like $DB'stop. ;; Handle funny names like $DB'stop.
("\\$ ?{?\\^?[_[:alpha:]][_[:alnum:]]*\\('\\)[_[:alpha:]]" (1 "_")) ("\\$ ?{?\\^?[_[:alpha:]][_[:alnum:]]*\\('\\)[_[:alpha:]]" (1 "_"))
;; format statements ;; format statements
("^[ \t]*format.*=[ \t]*\\(\n\\)" (perl--format-regexp
(1 (prog1 "\"" (perl-syntax-propertize-special-constructs end)))) (1 (prog1 "\"" (perl-syntax-propertize-special-constructs end))))
;; Propertize perl prototype chars `$%&*;+@\[]' as punctuation ;; Propertize perl prototype chars `$%&*;+@\[]' as punctuation
;; in `sub' arg-specs like `sub myfun ($)' and `sub ($)'. But ;; in `sub' arg-specs like `sub myfun ($)' and `sub ($)'. But
@ -946,6 +949,17 @@ changed by, or (parse-state) if line starts in a quoted string."
(goto-char (- (point-max) pos))) (goto-char (- (point-max) pos)))
shift-amt)) 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 () (defun perl-continuation-line-p ()
"Move to end of previous line and return non-nil if continued." "Move to end of previous line and return non-nil if continued."
;; Statement level. Is it a continuation or a new statement? ;; Statement level. Is it a continuation or a new statement?
@ -959,7 +973,8 @@ changed by, or (parse-state) if line starts in a quoted string."
(beginning-of-line) (beginning-of-line)
(perl-backward-to-noncomment)) (perl-backward-to-noncomment))
;; Now we get the answer. ;; Now we get the answer.
(unless (memq (preceding-char) '(?\; ?\} ?\{)) (unless (or (memq (preceding-char) '(?\; ?\} ?\{))
(perl--end-of-format-p))
(preceding-char))) (preceding-char)))
(defun perl-hanging-paren-p () (defun perl-hanging-paren-p ()
@ -999,7 +1014,9 @@ Returns (parse-state) if line starts inside a string."
(state (syntax-ppss)) (state (syntax-ppss))
(containing-sexp (nth 1 state)) (containing-sexp (nth 1 state))
;; Don't auto-indent in a quoted string or a here-document. ;; 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)) (when (and (eq t (nth 3 state))
(save-excursion (save-excursion
(goto-char (nth 8 state)) (goto-char (nth 8 state))
@ -1009,7 +1026,7 @@ Returns (parse-state) if line starts inside a string."
(setq unindentable nil) (setq unindentable nil)
(setq containing-sexp (nth 8 state))) (setq containing-sexp (nth 8 state)))
(cond (cond
(unindentable 'noindent) (unindentable (if format 0 'noindent))
((null containing-sexp) ; Line is at top level. ((null containing-sexp) ; Line is at top level.
(skip-chars-forward " \t\f") (skip-chars-forward " \t\f")
(if (memq (following-char) (if (memq (following-char)
@ -1018,7 +1035,8 @@ Returns (parse-state) if line starts inside a string."
;; indent a little if this is a continuation line ;; indent a little if this is a continuation line
(perl-backward-to-noncomment) (perl-backward-to-noncomment)
(if (or (bobp) (if (or (bobp)
(memq (preceding-char) '(?\; ?\}))) (memq (preceding-char) '(?\; ?\}))
(perl--end-of-format-p))
0 perl-continued-statement-offset))) 0 perl-continued-statement-offset)))
((/= (char-after containing-sexp) ?{) ((/= (char-after containing-sexp) ?{)
;; line is expression, not statement: ;; line is expression, not statement:

View File

@ -0,0 +1,36 @@
# This resource file can be run with cperl--run-testcases from
# cperl-tests.el and works with both perl-mode and cperl-mode.
# -------- Bug#35925: input -------
format FH =
@### @.### @###
42, 3.1415, 0
.
write FH;
# -------- Bug#35925: expected output -------
format FH =
@### @.### @###
42, 3.1415, 0
.
write FH;
# -------- Bug#35925: end -------
# -------- format not as top-level: input -------
foo: {
format STDOUT =
^<<<<
$foo
.
write;
}
# -------- format not as top-level: expected output -------
foo: {
format STDOUT =
^<<<<
$foo
.
write;
}
# -------- format not as top-level: end -------

View File

@ -1143,6 +1143,20 @@ Perl is not Lisp: An open paren in column 0 does not start a function."
(cperl-indent-command) (cperl-indent-command)
(forward-line 1)))) (forward-line 1))))
(ert-deftest cperl-test-bug-35925 ()
"Check that indentation is correct after a terminating format declaration."
(cperl-set-style "PBP") ; Make cperl-mode use the same settings as perl-mode.
(cperl--run-test-cases
(ert-resource-file "cperl-bug-35925.pl")
(let ((tab-function
(if (equal cperl-test-mode 'perl-mode)
#'indent-for-tab-command
#'cperl-indent-command)))
(goto-char (point-max))
(forward-line -2)
(funcall tab-function)))
(cperl-set-style-back))
(ert-deftest cperl-test-bug-37127 () (ert-deftest cperl-test-bug-37127 ()
"Verify that closing a paren in a regex goes without a message. "Verify that closing a paren in a regex goes without a message.
Also check that the message is issued if the regex terminator is Also check that the message is issued if the regex terminator is