How do you configure the indentation to work correctly for tcsh shell scripts?

I am unable to make the indentation work correctly when I use the shell-script-mode as it is.

Problem: An indentation of 4 spaces is inserted when I hit enter (when there shouldn't be any indentation!)

How to reproduce this problem?

  • Open \emacs -q&
  • Type #!/bin/tcsh -f in an empty buffer and save it as something like a.csh so that the shell-script-mode is auto-loaded.

When you hit enter at the end of this first and only line, the buffer converts from

#!/bin/tcsh -f (no indentation)


    #!/bin/tcsh -f (with indentation)

I am on the stable 24.4 version of emacs.

  • 1
    I can reproduce on 24.3. Weird.
    – Dan
    Jan 5 '15 at 15:19

Finally found a fix with a bit of a hack with the help of edebug-defun!

The keyword highlighting of shell-script-mode is good. But the problem was that it set the indent-line-function to sh-basic-indent-line when sh-shell was set to tcsh. That function caused the extra indentation by 4 spaces.

There is an outdated csh-mode.el (last updated in 1999) which does the indentation well but has outdated keyword highlighting info.

So I simply borrowed the useful stuff (csh-indent-line and csh-indent-region functions) from csh-mode.el when I am editing a .alias or any file whose extension ends in *csh:

(defun my/tcsh-set-indent-functions ()
  (when (or (string-match ".*\\.alias" (buffer-file-name))
            (string-match ".*csh$" (file-name-extension (buffer-file-name))))
    (require 'csh-mode) ; https://github.com/Tux/tcsh/blob/master/csh-mode.el
    (setq-local indent-line-function 'csh-indent-line)
    (setq-local indent-region-function 'csh-indent-region)))
(add-hook 'sh-set-shell-hook #'my/tcsh-set-indent-functions)

By default, emacs 24.4 turns on electric-indent-mode which makes it indent automatically. Disable it and you won't have that problem anymore:

(add-hook 'after-change-major-mode-hook (lambda() (electric-indent-mode -1)))

I set newline-and-indent to RET globally and have no problem:

(global-set-key (kbd "RET") 'newline-and-indent)
  • 1
    Thank you for this suggestion but the bigger issue is that the indentation is broken for tcsh in shell-script-mode. What you suggested will help avoid the issue but as soon as I do indent-region, I see the same problem of incorrect indentation. Jan 6 '15 at 14:48
  • 1
    Well yes but at least you are able to write csh script now, but manually. Probably you should report it to Emacs devs.
    – Tu Do
    Jan 6 '15 at 14:54

Going off the answer by Kaushal Modi this is a more general solution that will use the csh-indentation anytime your shell file is set to tcsh or csh. That way you don't have to enumerate every file that you want this fix to apply to and it won't affect other shell types.

(defun my/tcsh-set-indent-functions ()
  (when (string-match ".*csh.*" (symbol-value 'sh-shell-file))
    (require 'csh-mode) ; https://github.com/Tux/tcsh/blob/tux/csh-mode.el
    (setq-local indent-line-function 'csh-indent-line)
    (setq-local indent-region-function 'csh-indent-region)))
(add-hook 'sh-set-shell-hook #'my/tcsh-set-indent-functions)
  • I have to update my answer, but later I ended up doing something similar. But I still needed to hack sh-set-shell. The default evaluation of sh-shell did not work as I intended. Nov 4 '16 at 19:19
  • @KaushalModi yeah I started to run into some problems as well. But that hack you provided is first rate! Nov 18 '16 at 18:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.