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 | ]