I am trying to create an Emacs script that indents HTML files from the command line. This is what I have so far:

#!/usr/bin/env -S emacs --script

(require 'web-mode)
(indent-region (point-min) (point-max) nil)

I saved this file as indent and made it executable with chmod 755 indent. Then, I tried running it on an HTML file:

$ ./indent base.html 
Loading /etc/emacs/site-start.d/00debian.el (source)...
Loading /etc/emacs/site-start.d/50autoconf.el (source)...
Loading /etc/emacs/site-start.d/50cmake-data.el (source)...
Loading /etc/emacs/site-start.d/50dictionaries-common.el (source)...
Loading debian-ispell...
Loading /var/cache/dictionaries-common/emacsen-ispell-default.el (source)...
Loading /var/cache/dictionaries-common/emacsen-ispell-dicts.el (source)...
Loading /etc/emacs/site-start.d/50figlet.el (source)...
Loading /etc/emacs/site-start.d/50gettext.el (source)...
Package gettext-el removed but not purged. Skipping setup.
Loading /etc/emacs/site-start.d/50latexmk.el (source)...
Loading /etc/emacs/site-start.d/50pylint.el (source)...
Indenting region... 
Indenting region...done

It seemed to work, but there is no output. The content of file base.html remains unchanged. I'd really like to get this working, because I want to use this command as a git hook to format HTML files using web-mode.el.

Could anyone help?


@glucas's answer is correct in its diagnosis, but has a minor problem (you want the 0th element of argv) and is incomplete. Here is a more complete example:

#!/usr/bin/env -S emacs --script

(find-file (nth 0 argv))
(indent-region (point-min) (point-max) nil)

This does not use web-mode which is not available to me (does it exist?); instead I use mhtml-mode which is what my emacs uses when editing HTML files.

One safety point: instead of modifying a file in place, I would rather save it to a different file name, so if something goes wrong, I still have the original file and I can retry after fixing any problems (although you can use a backup, either one you made, or one made for you by emacs). So you might want to go with something like this:

#!/usr/bin/env -S emacs --script

(setq fname (nth 0 argv))
(find-file fname)
(indent-region (point-min) (point-max) nil)
(write-file (concat fname ".indent") t)

When invoked like this:

./indent foo.html

the script will save the result in a new file foo.html.indent (if foo.html.indent exists already, the t argument of write-file will cause the script to ask you whether to overwrite it: if you say y it will overwrite it; if you say n it will not, but you'll get a backtrace, since the script does not handle error conditions gracefully).

  • 1
    I'm using pre-commit to run this script. It will stage the changes to the index. That way, it's easy to revert to the original file with git checkout. Thank you very much, it works flawlessly! Feb 11 '21 at 9:04
  • 1
    Nice, thanks. I was pretty sure what the issue was but have never used Emacs this way... Might have a few places it could be handy...
    – glucas
    Feb 11 '21 at 14:01

I believe your example is not loading the file specified on the command line. It looks like with --script you need to get the file name from the command-line arguments passed to emacs and open that file before you try to process it. Something like:

 (find-file (nth 1 argv))
 ;; etc
  • I am new to Lisp, and I would very much appreciate it if you could elaborate on the etc part :-) I have tried prepending this code to my original code but I got the following error: Wrong type argument: stringp, nil Feb 10 '21 at 19:44

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.