GNU bug report logs -
#78159
shell-script indent regression in Emacs 30
Previous Next
To reply to this bug, email your comments to 78159 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78159
; Package
emacs
.
(Wed, 30 Apr 2025 06:57:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
john.ciolfi.32 <at> gmail.com
:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org
.
(Wed, 30 Apr 2025 06:57:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
Hi
In the following shell-script, the use of subshell, in this case, wrapping the "id" command in
parens, causes Emacs 30 to incorrectly indent the lines that follow use of subshells. Notice if you
remove the parens from id indentation is correct. The behavior is correct in Emacs 29, but not
Emacs 30. This issue can shift all lines in a shell script following the use of a subshell.
---- example.sh ----
#!/bin/bash
haveid1 () {
(id) 2> /dev/null 1>&2
if [ $? -eq 0 ]; then
echo "haveid1: yes"
else
echo "haveid1: no"
fi
}
haveid2 () {
id 2> /dev/null 1>&2
if [ $? -eq 0 ]; then
echo "haveid2: yes"
else
echo "haveid2: no"
fi
}
In GNU Emacs 30.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.38,
cairo version 1.16.0) of 2025-04-04, modified by Debian built on sbuild
Windowing system distributor 'The X.Org Foundation', version 11.0.12101006
System Description: Debian GNU/Linux 12 (bookworm)
Configured using:
'configure --build x86_64-linux-gnu --prefix=/usr
--sharedstatedir=/var/lib --libexecdir=/usr/libexec
--localstatedir=/var/lib --infodir=/usr/share/info
--mandir=/usr/share/man --with-libsystemd --with-pop=yes
--enable-locallisppath=/etc/emacs:/usr/local/share/emacs/30.1/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/30.1/site-lisp:/usr/share/emacs/site-lisp
--with-sound=alsa --without-gconf --with-mailutils --build
x86_64-linux-gnu --prefix=/usr --sharedstatedir=/var/lib
--libexecdir=/usr/libexec --localstatedir=/var/lib
--infodir=/usr/share/info --mandir=/usr/share/man --with-libsystemd
--with-pop=yes
--enable-locallisppath=/etc/emacs:/usr/local/share/emacs/30.1/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/30.1/site-lisp:/usr/share/emacs/site-lisp
--with-sound=alsa --without-gconf --with-mailutils --with-cairo
--with-x=yes --with-x-toolkit=gtk3 --with-toolkit-scroll-bars
'CFLAGS=-g -O2
-ffile-prefix-map=/build/reproducible-path/emacs-30.1+1=. -fstack-protector-strong
-Wformat -Werror=format-security -Wall' 'CPPFLAGS=-Wdate-time
-D_FORTIFY_SOURCE=2' LDFLAGS=-Wl,-z,relro'
Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NATIVE_COMP
NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF
TOOLKIT_SCROLL_BARS TREE_SITTER WEBP X11 XDBE XIM XINPUT2 XPM GTK3 ZLIB
Important settings:
value of $LANG: en_US.UTF-8
locale-coding-system: utf-8-unix
Major mode: Shell-script
Minor modes in effect:
sh-electric-here-document-mode: t
tooltip-mode: t
global-eldoc-mode: t
show-paren-mode: t
electric-indent-mode: t
mouse-wheel-mode: t
tool-bar-mode: t
menu-bar-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
blink-cursor-mode: t
minibuffer-regexp-mode: t
line-number-mode: t
indent-tabs-mode: t
transient-mark-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
Load-path shadows:
None found.
Features:
(shadow sort mail-extr emacsbug pulse color xref project oc-basic
org-element org-persist org-id org-refile org-element-ast inline
avl-tree generator ol-eww eww xdg url-queue mm-url ol-rmail ol-mhe
ol-irc ol-info ol-gnus nnselect gnus-art mm-uu mml2015 mm-view mml-smime
smime gnutls dig gnus-sum shr pixel-fill kinsoku url-file svg dom
gnus-group gnus-undo gnus-start gnus-dbus dbus compile comp-run xml
gnus-cloud nnimap nnmail browse-url url url-proxy url-privacy url-expand
url-methods url-history url-cookie generate-lisp-file url-domsuf
url-util url-parse auth-source cl-seq eieio eieio-core cl-macs json map
url-vars mail-source utf7 nnoo parse-time gnus-spec gnus-int gnus-range
message sendmail mailcap yank-media puny rfc822 mml mml-sec
password-cache epa derived epg rfc6068 epg-config mm-decode mm-bodies
mm-encode mail-parse rfc2231 rfc2047 rfc2045 ietf-drums mailabbrev
gmm-utils mailheader gnus-win gnus nnheader gnus-util mail-utils range
mm-util mail-prsvr wid-edit ol-docview doc-view filenotify image-mode
exif dired dired-loaddefs ol-bibtex bibtex iso8601 ol-bbdb ol-w3m ol-doi
org-link-doi org ob ob-tangle ob-ref ob-lob ob-table ob-exp org-macro
org-src ob-comint org-pcomplete pcomplete comint ansi-osc ansi-color
ring org-list org-footnote org-faces org-entities noutline outline icons
org-version ob-emacs-lisp ob-core ob-eval org-cycle org-table ol
org-fold org-fold-core org-keys oc org-loaddefs cal-menu calendar
cal-loaddefs org-compat org-macs format-spec misearch multi-isearch
cl-print byte-opt gv bytecomp byte-compile time-date subr-x pcase edebug
debug backtrace jka-compr cl-extra shortdoc text-property-search
comp-common help-fns radix-tree help-mode thingatpt find-func sh-script
rx smie treesit cl-loaddefs cl-lib executable rmc iso-transl tooltip
cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type
elisp-mode mwheel term/x-win x-win term/common-win x-dnd touch-screen
tool-bar dnd fontset image regexp-opt fringe tabulated-list replace
newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar
rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock
font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq
simple cl-generic indonesian philippine cham georgian utf-8-lang
misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms
cp51932 hebrew greek romanian slovak czech european ethiopic indian
cyrillic chinese composite emoji-zwj charscript charprop case-table
epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button
loaddefs theme-loaddefs faces cus-face macroexp files window
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget keymap hashtable-print-readable backquote threads dbusbind
inotify lcms2 dynamic-setting system-font-setting font-render-setting
cairo gtk x-toolkit xinput2 x multi-tty move-toolbar
make-network-process native-compile emacs)
Memory information:
((conses 16 434138 109987) (symbols 48 22590 4)
(strings 32 107934 6084) (string-bytes 1 3306214) (vectors 16 63088)
(vector-slots 8 1428105 82431) (floats 8 870 285)
(intervals 56 6273 2078) (buffers 992 21))
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78159
; Package
emacs
.
(Wed, 30 Apr 2025 14:08:03 GMT)
Full text and
rfc822 format available.
Message #8 received at 78159 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Hi
I debugged this a little and see the regression occurred when sh-script.el
sh-font-lock-paren was changed in Emacs 30 to have:
;; Also recognize OpenBSD's case X { ... } (bug#55764).
(and (looking-at ";\\(?:;&?\\|[&|]\\)\\|\\_<in\\|.{")
where the Emacs 29 had:
(and (looking-at ";[;&]\\|\\_<in")
when I modify Emacs 30 sh-script.el to revert this one line back to the
Emacs 29 content, we get the correct answer. I suspect reverting this line
is not the right thing to do. Rather, I hope it helps someone find the
solution.
Thanks
John
[Message part 2 (text/html, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78159
; Package
emacs
.
(Wed, 30 Apr 2025 14:08:03 GMT)
Full text and
rfc822 format available.
Message #11 received at 78159 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Hi
One more observation is that it's the subshell, code in parens, that's not
handled correctly. In the following example, the indentation in haveid3 is
incorrect so the issue is not due to the std handle redirects.
#!/bin/bash
haveid1 () {
(id) 2> /dev/null 1>&2
if [ $? -eq 0 ]; then
echo "haveid1: yes"
else
echo "haveid1: no"
fi
x = 1
}
haveid2 () {
id 2> /dev/null 1>&2
if [ $? -eq 0 ]; then
echo "haveid2: yes"
else
echo "haveid2: no"
fi
}
haveid3 () {
(id)
if [ $? -eq 0 ]; then
echo "haveid2: yes"
else
echo "haveid2: no"
fi
}
On Wed, Apr 30, 2025 at 8:49 AM John C <john.ciolfi.32 <at> gmail.com> wrote:
> Hi
>
> I debugged this a little and see the regression occurred when
> sh-script.el sh-font-lock-paren was changed in Emacs 30 to have:
>
> ;; Also recognize OpenBSD's case X { ... } (bug#55764).
> (and (looking-at ";\\(?:;&?\\|[&|]\\)\\|\\_<in\\|.{")
>
> where the Emacs 29 had:
>
>
> (and (looking-at ";[;&]\\|\\_<in")
>
> when I modify Emacs 30 sh-script.el to revert this one line back to the
> Emacs 29 content, we get the correct answer. I suspect reverting this line
> is not the right thing to do. Rather, I hope it helps someone find the
> solution.
>
> Thanks
> John
>
[Message part 2 (text/html, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78159
; Package
emacs
.
(Wed, 30 Apr 2025 14:24:01 GMT)
Full text and
rfc822 format available.
Message #14 received at 78159 <at> debbugs.gnu.org (full text, mbox):
> From: John C <john.ciolfi.32 <at> gmail.com>
> Date: Wed, 30 Apr 2025 08:49:28 -0400
>
> I debugged this a little and see the regression occurred when sh-script.el sh-font-lock-paren was changed
> in Emacs 30 to have:
>
> ;; Also recognize OpenBSD's case X { ... } (bug#55764).
> (and (looking-at ";\\(?:;&?\\|[&|]\\)\\|\\_<in\\|.{")
>
> where the Emacs 29 had:
>
> (and (looking-at ";[;&]\\|\\_<in")
>
> when I modify Emacs 30 sh-script.el to revert this one line back to the Emacs 29 content, we get the correct
> answer. I suspect reverting this line is not the right thing to do. Rather, I hope it helps someone find the
> solution.
Stefan, any suggestions?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78159
; Package
emacs
.
(Thu, 01 May 2025 21:26:02 GMT)
Full text and
rfc822 format available.
Message #17 received at 78159 <at> debbugs.gnu.org (full text, mbox):
>
> haveid1 () {
> (id) 2> /dev/null 1>&2
> if [ $? -eq 0 ]; then
> echo "haveid1: yes"
> else
> echo "haveid1: no"
> fi
> }
>
> haveid2 () {
> id 2> /dev/null 1>&2
> if [ $? -eq 0 ]; then
> echo "haveid2: yes"
> else
> echo "haveid2: no"
> fi
> }
Oh, yes, it's due to the change to accept:
case FOO {
(id) ...;;
(other) ...;;
}
The previous code accepted only
case FOO in
(id) ...;;
(other) ...;;
esac
and it checked only the presence of `in` without checking that it's part
of a case statement, which was sufficient because `in` doesn't seem to
ever occur elsewhere than in case statements.
The new code similarly fails to check that the `{` is part of a case
statement but `{` doesn't enjoy this same property as `in`, hence the
bug you're seeing.
A crude hack could be something like the patch below, but we should try
to do a more thorough job of deciding if this `{` is part of case
statement or not.
Stefan
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index 287f0501350..b5ccc5507e5 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -1065,14 +1065,19 @@ sh-font-lock-paren
;; a normal command rather than the real `in' keyword.
;; I.e. we should look back to try and find the
;; corresponding `case'.
- ;; Also recognize OpenBSD's case X { ... } (bug#55764).
- (and (looking-at ";\\(?:;&?\\|[&|]\\)\\|\\_<in\\|.{")
- ;; ";; esac )" is a case that looks
- ;; like a case-pattern but it's really just a close
- ;; paren after a case statement. I.e. if we skipped
- ;; over `esac' just now, we're not looking
- ;; at a case-pattern.
- (not (looking-at "..[ \t\n]+esac[^[:word:]_]"))))
+ (cond
+ ((looking-at ";\\(?:;&?\\|[&|]\\)\\|\\_<in")
+ ;; ";; esac )" is a case that looks
+ ;; like a case-pattern but it's really just a close
+ ;; paren after a case statement. I.e. if we skipped
+ ;; over `esac' just now, we're not looking
+ ;; at a case-pattern.
+ (not (looking-at "..[ \t\n]+esac[^[:word:]_]")))
+ ;; Also recognize OpenBSD's case X { ... } (bug#55764).
+ ((looking-at ".{")
+ (save-excursion
+ ;; Try and make sure this is a case statement!
+ (re-search-backward "esac" (pos-bol) t)))))
(progn
(when open
(put-text-property open (1+ open) 'syntax-table sh-st-punc))
This bug report was last modified 2 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.