The default indentation levels of GNU Emacs for the
case statements of sh(1) scripts (and derivative or compatible shells) are a bit smal for my taste (4 columns). This makes
case statements in shell scripts look almost “ok”, but I don’t like the small indentation for the rest of my scripts. Here is how the default indentation would look for a part of my ~/.bashrc file:
I like 8 column indentation in nested statements, so one of the things I do in my ~/elisp/keramida-hooks.el startup file is:
(defun gker-setup-sh-mode () "My own personal preferences for `sh-mode'. This is a custom function that sets up the parameters I usually prefer for `sh-mode'. It is automatically added to `sh-mode-hook', but is can also be called interactively." (interactive) (setq sh-basic-offset 8 sh-indentation 8)) (add-hook 'sh-mode-hook 'gker-setup-sh-mode)
Setting the basic indentation to 8 columns has an undesired side-effect though. It indents the labels and the code of
case statements too much for my taste. The default indentation levels set up by sh-mode for these statements indent the case label by sh-basic-offset columns and the commands after a case label by twice the same amount.
The same part of my ~/.bashrc file becomes then:
The extra indentation of
case labels seems a bit excessive now. It consumes 8 extra columns of precious horizontal space. For someone who likes reading source code in relatively narrow windows like me, this is a waste of space that would look more useful if it contained code instead of empty space / indentation.
GNU Emacs is, however, as I’ve written several times in the past, an infinitely customizable, extensible editor. There are, in fact, at least two different ways of customizing the indentation level of
case labels and
case commands (after those labels) in shell scripts. The first option is to modify the syntax table of sh-mode for these two syntax elements right there, inside the same hook that tweaks the default indentation offset from 4 columns to 8 columns:
(defun gker-setup-sh-mode () "My own personal preferences for `sh-mode'. This is a custom function that sets up the parameters I usually prefer for `sh-mode'. It is automatically added to `sh-mode-hook', but is can also be called interactively." (interactive) (setq sh-basic-offset 8 sh-indentation 8 ;; Tweak the indentation level of case-related syntax elements, to avoid ;; excessive indentation because of the larger than default value of ;; `sh-basic-offset' and other indentation options. sh-indent-for-case-label 0 sh-indent-for-case-alt '+) (add-hook 'sh-mode-hook 'gker-setup-sh-mode)
This way of setting up the indentation for the two
case-related syntax elements has the advantage that it is as close as possible to the sh-basic-offset and the other related changes. A small comment above the
case-related syntax elements is sufficient to document why these syntax changes are needed.
Another option is to set the default values of these two syntax elements of sh-mode, by something like:
(setq-default sh-indent-for-case-label 0) (setq-default sh-indent-for-case-alt '+)
This way of reducing the indentation for
case-related shell script code should work too. It’s not as nice as the first option, but it can be used to achieve similar results, even if it runs outside of the mode hooks for sh-mode.
After one of these changes has been evaluated, the indentation of
case-statements in sh-mode changes to
This is much better. At least it’s much better according to my taste, and it precisely matches the default style of indentation I use when I am writing scripts in that other popular editor.
As an extra, bonus side-effect, by configuring the syntax elements of sh-mode correctly, I can now mark any part of a shell script as the active region, and the
M-x indent-region command (bound to
C-M-\ by default in Emacs) will and indent the marked region with the correct style, i.e. the one I like using :-)