bugmans' blog
Generating Web Pages
Note: When writing this article I found another great article about the same topic. Be sure to check it out.

Making a web-page is extremely easy. Anyone can go use a WYSIWYG editor and mock up a page in minutes, or use a tool like wordpress to make websites with any functionality you wish by adding widgets from a catalog. But be honest, someone making a blog doesn't need any of that. I'm not dogmatic -- use whatever makes you happy, but be honest; paying 96 dollars a year for wordpress so you can "customize fonts and colors" is absurd. For the website you're seeing now, it cost about 60 dollars for three years of hosting. Don't overspend. There's beauty in the old style websites. With my blog, I've tried to emulate it and in doing so have developed a workflow to make it a lot easier. It's a kludge but a very personal one.

The Gameplan

One of the first steps to ascending to command-line wizardhood is understanding that everything is text. Yes, even photos. If it's not text yet, there are tools for it. If there are no tools for it, there will be. That's why there's such an emphasis on command line tools; they're the most effective way to manipulate text in bulk. I like to stick to pure text when practical and I'm not breaking that tradition with my website. I edit everything in normal Emacs buffers and use an external browser (GNU Icecat) to preview it. My window manager is EXWM so it integrates seamlessly into the workflow. One of these days I want to make the jump to a full Lisp browser like Nyxt but I haven't really found the time. Back on topic: HTML is no exception to the "everything is text" policy. It's in-fact one of the simplest textual representations of data I know of. A CSV file has the capacity to be more complex than HTML. So, we can use and abuse HTML with a suite of text based tools. Here's the spread:

GNU M4

What?

Writing HTML by hand can be a pain in the ass, and reading it can be an even bigger pain in the ass. But, there are solutions that don't cost 96 dollars a year. GNU M4 is a macro processor. At its simplest, the user describes some symbol-value pairs: The user could declare that the symbol foo is equal to the value of bar. If M4 comes across foo in its input, it will be transformed into bar in its output. Expanding upon this functionality, M4 also allows you to specify the location of the replaced argument. Using the `$1' variable lets you specify where you want the first argument to appear. You can keep increasing this number if you have multiple variables, but it may be more practical to use `$@' to display all arguments. Some examples:

define(LOVE, `I love $1 so much! :)')
LOVE(steak)
>`I love steak so much! :)'

define(HATE, `I hate $1 and $2 so much!')
HATE(red, green)
>I hate red and green so much!

define(WANT, `I want $@')
WANT(an xbox, a car, a bike)
>I want an xbox, a car, a bike.
M4 is usually used during the compilation of programs written in languages like C. Since macros are frowned upon, M4 is rarely used and is something of a "lost art" nowadays. It's true: Macros can cause problems that are hard to debug. Not to say that M4 can never be used successfully but many programmers avoid it and even demonize it. I think it's unfair to demonize macros or really any technique/technology/language etc. Everything has its place somewhere.

Why?

Despite this looking like a programming langauge, M4 does not interact with anything it does not recognize. You can write whatever you want it'll output it just as it is, unless it's recognized as a macro. For example, if you wished to use M4 to write HTML like I do, you would have the freedom to write HTML directly into an M4 file. This means you do not have to make macros for every little thing and you're free to write directly should the situation call for it. This grants the writer powerful abstraction features that do not get in the way. Everything annoying and complicated is placed on M4's shoulders and the writer is free to write without remembering how a link should be formatted or the hassle of writing <'s and >'s as &\lt and &\gt when you just want to embed some HTML.


In addition, this abstraction can make changing the presentation of your site much easier than contemporary website editors; you can abstract colors, font styles, size and more all away into macros. When I want to put emphasis on a word, I wrap it in an "ACCENT" macro. As the time of me typing this sentence out, the current accent is just making the word bold. If I want to change the color instead, which I probably will end up doing, I do not have to edit everything I put in bold, I just have to edit my one "ACCENT" macro and everything will be changed accordingly.

Macros of Interest

Here are a few macros I use. The other ones are mostly trivial. If you'd like more inspiration, check the manual or read the article listed at the top. For context, all these macros are placed into one file I call "standard_header.m4". I then use the include directive at the top of every page I'm writing. That way, I can change everything in one place and also include some standard formatting information. More on that later.
changequote(`[', `]')
Just... Goddamn, ` and ' as quotes is hell. Do yourself a favor and just change it to that. Or curly braces. Or anything that you find uncommon in your work, really.
define([LINK], <a href="$1" title="$1">$2</a>)
Lazy links, just has the title as the link. I find that to be enough for my purposes, it's trivial to add a third argument as the title if your needs vary.
define([HTML_BLOCK], patsubst(patsubst([[$*]], [<], [&\lt;]), [>], [&\gt;]) ]
This ones a bit esoteric but allows you to write example HTML without having to put in the whole &\lt; business. Remove the backslashes if you want to paste this in somewhere.
include(default_header.txt)
While this doesn't aid me in writing, this "default header" file contains HTML for the page header, the link box on the left, the footer at the bottom, and the path to the style sheet. It's included inside my standard header and thus included inside every file that uses the standard header. It makes keeping a consistent style very simple.

GNU Make

Make?

When one uses Make, it's almost always in the context of compiling non-trivial programs. But Make is effectively an advanced bash script, it's calling other commands to do the heavy lifting. In the manuals' own words, "You can use it to describe any task where some files must be updated automatically from others whenever the others change." Indeed, we are interested in updating .html files whenever we change our corresponding .m4 files. Make is simply a list of instructions on how to update or create files from a set of original files. It's designed so, on subsequent runs, it only operates on whats actually changed. This list of instructions is called a "Makefile". Using Make, it can do all the heavy lifting of manually creating .html files, sorting them, naming them, and updating them. We can just create our files and the right thing will happen when we run Make. Here's my solution:

OBJS=$(patsubst %.m4, %.html, $(wildcard *.m4))

all: $(OBJS)

%.html : %.m4
 -m4 $< | tidy -i --force-output yes -q --tidy-mark no 2>/dev/null > finished_pages/$@
I use the "tidy" command to clean up the resulting HTML. It's not strictly necessary, but makes the resulting HTML much cleaner. It's a wonderful workflow, really. Right now it dumps all the pages into one folder; if it ever becomes an issue I can rectify it later.
Make can be extended for really whatever you want. If you want javascript, I'm sure it could do that too. When writing this, I don't really feel that my page will ever need it.

GNU Emacs

I thoroughly enjoy Emacs because of its versatility and letting tools integrate with each other. With Emacs, I can edit the CSS and HTML for my page and have it update in real time. I find it very easy to edit CSS, HTML, Makefiles, and M4 all at the same time since they all have their own respective modes with syntax highlighting and other useful features. In any case, here's the package that makes the "real time" magic happen:

Impatient Mode

Impatient Mode is a fantastic tool that integrates simple-httpd mode with one of your Emacs buffers to have its contents displayed in real time. You simply enable "impatient-mode" on the buffers you want to serve up and it'll be available at localhost:8080/imp for you to see. Remember, if you want to edit CSS in real time you need to enable impatient mode on the style sheet. If you don't have Emacs, try this:

entr

Entr is a useful thing that's not really related to Emacs and lets us run a command whenever selected files change. For us, we want to run our Makefile whenever our .m4 file changes. This lets us get some of the "real time" benefit even when we're using M4.
find ./.m4 | entr make
You can run this in any shell you wish and it should work as long as you are in the correct directory. It's best to abstract what's being done into your Makefile instead of making a piped contraption for Entr itself to run.

auto-revert-mode

Built into Emacs and pairs very nicely with Entr, Make, and impatient mode. Simply put, a buffer with this mode enabled will automatically update to the files current contents whenever the file changes. If you make changes by hand it will not automatically overwrite your changes and you'll have to use M-x revert-buffer to do it manually.

Closing thoughts

Not much else to say here, I hope you found this useful. If not, I hope you at least got some ideas of your own on what to use M4 with. It's absolutely worth knowing.