* bug#35925: perl-mode wrecks formats
2019-05-27 13:11 bug#35925: perl-mode wrecks formats 積丹尼 Dan Jacobson
2019-07-09 2:11 ` Lars Ingebrigtsen
@ 2023-09-16 23:03 ` Mauro Aranda
2023-10-01 2:17 ` Stefan Kangas
1 sibling, 1 reply; 8+ messages in thread
From: Mauro Aranda @ 2023-09-16 23:03 UTC (permalink / raw)
To: 35925; +Cc: 積丹尼 Dan Jacobson
[-- Attachment #1: Type: text/plain, Size: 625 bytes --]
tags 35925 patch
quit
積丹尼 Dan Jacobson <jidanni@jidanni.org> writes:
> In perl-mode,
>
> format FH =
> @<< @# @<< @### @<<<<< @# @<<<< @#
> (split)[0..5, 7..8]
> .
> write FH;
>
> becomes
>
> format FH =
> @<< @# @<< @### @<<<<< @# @<<<< @#
> (split)[0..5, 7..8]
> .
> write FH;
>
> wrecking output indentation and even introducing a syntax error on
the "." line.
>
> (See man perlform.)
>
> Seen with C-x h TAB, emacs-version "26.1".
AFAICS, perl-mode doesn't recognize a format declaration when indenting.
I attach a patch that adds a check, plus some tests.
[-- Attachment #2: 0001-Fix-indentation-in-perl-mode-Bug-35925.patch --]
[-- Type: text/x-patch, Size: 6362 bytes --]
From 2a6416a26c3b7e11340a2b296dbbd9c1d8a51ca7 Mon Sep 17 00:00:00 2001
From: Mauro Aranda <maurooaranda@gmail.com>
Date: Sat, 16 Sep 2023 18:15:40 -0300
Subject: [PATCH] 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.
---
lisp/progmodes/perl-mode.el | 30 ++++++++++++----
.../cperl-mode-resources/cperl-bug-35925.pl | 36 +++++++++++++++++++
test/lisp/progmodes/cperl-mode-tests.el | 14 ++++++++
3 files changed, 74 insertions(+), 6 deletions(-)
create mode 100644 test/lisp/progmodes/cperl-mode-resources/cperl-bug-35925.pl
diff --git a/lisp/progmodes/perl-mode.el b/lisp/progmodes/perl-mode.el
index 040ef187e97..b8d811baf0d 100644
--- a/lisp/progmodes/perl-mode.el
+++ b/lisp/progmodes/perl-mode.el
@@ -223,7 +223,10 @@ perl-quote-like-pairs
"\\|=>"
"\\|[?:.,;|&*=!~({[]"
"\\|[^-+][-+]" ;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))
@@ -252,7 +255,7 @@ perl-syntax-propertize-function
;; 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 +949,17 @@ perl-indent-line
(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,7 +973,8 @@ perl-continuation-line-p
(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 ()
@@ -999,7 +1014,9 @@ perl-calculate-indent
(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 +1026,7 @@ perl-calculate-indent
(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 +1035,8 @@ perl-calculate-indent
;; 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:
diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-bug-35925.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-35925.pl
new file mode 100644
index 00000000000..e3f96241ab7
--- /dev/null
+++ b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-35925.pl
@@ -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 -------
diff --git a/test/lisp/progmodes/cperl-mode-tests.el b/test/lisp/progmodes/cperl-mode-tests.el
index 87d8ffa2d8d..172adfc79dd 100644
--- a/test/lisp/progmodes/cperl-mode-tests.el
+++ b/test/lisp/progmodes/cperl-mode-tests.el
@@ -1139,6 +1139,20 @@ cperl-test-bug-30393
(cperl-indent-command)
(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 ()
"Verify that closing a paren in a regex goes without a message.
Also check that the message is issued if the regex terminator is
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread