Emacs: Initializing code files with a template
Part of being a programmer is having an urge to automate repetitive tasks.
Every new HTML file I create should include some boilerplate HTML, like
<html><head></head></body></body></html>
.
Every new Python file I create should start with
#!/usr/bin/env python
, and most of them should end
with an if __name__ == "__main__":
clause.
I get tired of typing all that, especially the dunderscores and
slash-greater-thans.
Long ago, I wrote an emacs function called newhtml
to insert the boilerplate code:
(defun newhtml () "Insert a template for an empty HTML page" (interactive) (insert "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" "<html>\n" "<head>\n" "<title></title>\n" "</head>\n\n" "<body>\n\n" "<h1></h1>\n\n" "<p>\n\n" "</body>\n" "</html>\n") (forward-line -11) (forward-char 7) )
The motion commands at the end move the cursor back to point in
between the <title> and </title>, so I'm ready to type
the page title. (I should probably have it prompt me, so it can insert
the same string in title
and h1
, which
is almost always what I want.)
That has worked for quite a while. But when I decided it was time to write the same function for python:
(defun newpython () "Insert a template for an empty Python script" (interactive) (insert "#!/usr/bin/env python\n" "\n" "\n" "\n" "if __name__ == '__main__':\n" "\n" ) (forward-line -4) )... I realized that I wanted to be even more lazy than that. Emacs knows what sort of file it's editing -- it switches to html-mode or python-mode as appropriate. Why not have it insert the template automatically?
My first thought was to have emacs run the function upon loading a
file. There's a function with-eval-after-load
which
supposedly can act based on file suffix, so something like
(with-eval-after-load ".py" (newpython))
is documented to work. But I found that it was never called, and
couldn't find an example that actually worked.
But then I realized that I have mode hooks for all the programming modes anyway, to set up things like indentation preferences. Inserting some text at the end of the mode hook seems perfectly simple:
(add-hook 'python-mode-hook (lambda () (electric-indent-local-mode -1) (font-lock-add-keywords nil bad-whitespace) (if (= (buffer-size) 0) (newpython)) (message "python hook") ))
The (= (buffer-size) 0)
test ensures this only happens
if I open a new file. Obviously I don't want to be auto-inserting code
inside existing programs!
HTML mode was a little more complicated. I edit some files, like
blog posts, that use HTML formatting, and hence need html-mode,
but they aren't standalone HTML files that need the usual HTML
template inserted. For blog posts, I use a different file extension,
so I can use the elisp string-suffix-p
to test for that:
;; s-suffix? is like Python endswith (if (and (= (buffer-size) 0) (string-suffix-p ".html" (buffer-file-name))) (newhtml) )
I may eventually find other files that don't need the template; if I need to, it's easy to add other tests, like the directory where the new file will live.
A nice timesaver: open a new file and have a template automatically inserted.
[ 09:52 Feb 13, 2017 More linux/editors | permalink to this entry | ]