3

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)
(save-buffer)

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?

Drew
  • 75,699
  • 9
  • 109
  • 225

2 Answers2

6

@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))
(mhtml-mode)
(indent-region (point-min) (point-max) nil)
(save-buffer)

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)
(mhtml-mode)
(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).

NickD
  • 27,023
  • 3
  • 23
  • 42
  • 1
    I'm using [pre-commit](https://pre-commit.com/) 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! – Jaap Joris Vens Feb 11 '21 at 09: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
3

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))
 (web-mode)
 ;; etc
glucas
  • 20,175
  • 1
  • 51
  • 83
  • 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` – Jaap Joris Vens Feb 10 '21 at 19:44