smartparens icon indicating copy to clipboard operation
smartparens copied to clipboard

unmatched-expression error when editing shell scripts with case statements

Open jgarvin opened this issue 10 years ago • 4 comments

case $1 in
    -d)
        echo "$projectile_dir"
        exit 0
        ;;
esac

I was writing this snippet of zsh (though I think the syntax is the same in bash) and had my cursor right after the closing paren. Smartparens prints the :unmatched-expression message because it thinks it's a paren that should be matched. I'm not enough of a shell script guru to know if there is an easy fix, might be hard.

jgarvin avatar Apr 11 '15 20:04 jgarvin

You can add a predicate to tell SP some pairs are not to be matched. See SKIP-MATCH in the docstring of sp-local-pair.

An example is in smartparens-config for sp--lisp-modes (search for :skip-match).

If you figure this out, I would be happy to pull in some config for bash/shell modes.

Fuco1 avatar Apr 11 '15 21:04 Fuco1

Just to clarify, by "some pairs are not to be matched" I ment that you can exclude some particular situations in the buffer from the balance counter. Parens will still be matched in other constructs, like $(foo) where the skip predicate won't trigger.

Fuco1 avatar Apr 11 '15 21:04 Fuco1

I've found a way to tell if the point is inside a case block, but I am not familiar with the mechanism of smartparens. Here's what I do:

(sp-local-pair 'sh-mode "(" ")"
               :skip-match (lambda (ms _mb _me)
                             (let ((pt-old (point))
                                   (pt-new))
                               (save-excursion
                                 ;; This is not documented, but it goes to the
                                 ;; beginning of case block when the point is
                                 ;; inside one.
                                 (sh-goto-matching-case)
                                 (setq pt-new (point)))
                               (and
                                ;; I think by "currently matched delimiter" it
                                ;; means when I type ")", `ms' will be "("
                                (string= ms "(")
                                (not (eq pt-old pt-new))))))

I think it has some effect: when inside a case block, I can delete closing parens (I use strict mode so this can't be done normally). But I still can't type in a right paren directly.

@Fuco1 Would you like to look into this? What should I do to make it work?

AmaiKinono avatar Sep 29 '19 15:09 AmaiKinono

@AmaiKinono Thanks, the snippet you posted is useful digging up the sh mode function.

The :skip-match option controls the matching of the pairs, so if you set it here to ignore the ) after the option it will not count it as mis-matched.

To make it possible to insert the closing ) I'm not actually sure what needs to be done :D. I think maybe one of the :when or :unless needs to be configured, but I don't remember what action is checked for this.

I'll take a look, it should be fairly simple with the code you provided.

Fuco1 avatar Sep 30 '19 16:09 Fuco1