4

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)

to

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

I am on the stable 24.4 version of emacs.

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

3 Answers 3

4

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)
2

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)
2
  • 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. Commented Jan 6, 2015 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
    Commented Jan 6, 2015 at 14:54
0

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)
2
  • 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. Commented Nov 4, 2016 at 19:19
  • @KaushalModi yeah I started to run into some problems as well. But that hack you provided is first rate! Commented Nov 18, 2016 at 18:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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