Subject: Re: bug#18380: 24.3.93; sh-script multiline quoted subshell wreaks havoc with indentation

From: Stefan Monnier <[email-masked]>
Date: Tue, 02 Sep 2014 20:39:36 -0400

> This will see the { as quoted:
> "$(echo  "{")"
>
> while this will not:
>
> "$(echo
>    "{")"

Actually, it depends: sometimes it will sometimes it won't :-(

> after this line indentation is broken as Emacs thinks there is an
> unclosed open brace.
>
> The problem with multiline quoted subshells is more general, as
> remarked by this comment in sh-script.el:
>
>   ;; FIXME: This can (and often does) match multiple lines, yet it makes no
>   ;; effort to handle multiline cases correctly, so it ends up being
>   ;; rather flaky.

Indeed, the problem you show is the direct result of the problem alluded
to in the above comment.  I installed the patch below which seems to help.

        Stefan

=== modified file 'lisp/progmodes/sh-script.el'
--- lisp/progmodes/sh-script.el	2014-07-21 01:41:59 +0000
+++ lisp/progmodes/sh-script.el	2014-09-03 00:37:50 +0000
@@ -1051,13 +1051,11 @@
   "Search for a subshell embedded in a string.
 Find all the unescaped \" characters within said subshell, remembering that
 subshells can nest."
-  ;; FIXME: This can (and often does) match multiple lines, yet it makes no
-  ;; effort to handle multiline cases correctly, so it ends up being
-  ;; rather flaky.
   (when (eq ?\" (nth 3 (syntax-ppss))) ; Check we matched an opening quote.
     ;; bingo we have a $( or a ` inside a ""
     (let (;; `state' can be: double-quote, backquote, code.
           (state (if (eq (char-before) ?`) 'backquote 'code))
+          (startpos (point))
           ;; Stacked states in the context.
           (states '(double-quote)))
       (while (and state (progn (skip-chars-forward "^'\\\\\"`$()" limit)
@@ -1088,7 +1086,12 @@
                  (`double-quote nil)
                  (_ (setq state (pop states)))))
           (_ (error "Internal error in sh-font-lock-quoted-subshell")))
-        (forward-char 1)))))
+        (forward-char 1))
+      (when (< startpos (line-beginning-position))
+        (put-text-property startpos (point) 'syntax-multiline t)
+        (add-hook 'syntax-propertize-extend-region-functions
+                  'syntax-propertize-multiline nil t))
+      )))

 (defun sh-is-quoted-p (pos)