Soupault 1.4 release

Estimated reading time: 2 minutes.

I've released soupault 1.4. It's not a big release, but it offers some convenience features that hopefully make it easier to work with.

You can download the executables from or build them from source. I've moved them to my own server to decrease reliance on third-party services and expose people to less third-party tracking, but still be able to see how often each version is downloaded. Here's what has changed.

Separate verbose and debug options

The original --verbose option was not very well thought out. Its output was an overkill for people who just want a build progress log, but it was not detailed enough for debugging some likely problems like “why my widget doesn't run on a page”.

Now there are separate --verbose and --debug options, that you can also make permanent by adding them to the [settings] section of your soupault.conf.

  verbose = true
  debug = true

The debug option implies verbose. I went for two distinct options instead of a single log level option so that they are easier to just comment out in the config if they are not needed and re-enable any time. Internally, it's just a log level of course, by default it's set to warning, the verbose option raises it to info, and the debug option sets it to debug.

What's more important is that verbose option now shows what is done, while debug also shows why it's done. It also shows what could be done but isn't and why it isn't. For example, if a widget doesn't run, it shows why (target element not in the page, page excluded by options etc.).

On the subject of debugging, the after option for setting widget processing order should be less annoying to use now. First, debug output now includes the processing order. Second, dependencies on non-existent widgets and circular dependencies are now distinct errors with clear error messages.

Ignoring certain files

Many static site generators include a “draft mode”. If you add something like published: false to the page metadata, they ignore the page. Ability to exclude some files is a useful feature, but since soupault extracts metadata from the HTML itself, using presence of an element matching some selector as a draft flag is probably a wrong thing to do. In that case it would need to parse a page just to decide if it's to be ignored.

Instead, I've added a more general option ignore_file_extensions. You can use it for hiding drafts, e.g. by setting it to ignore_file_extensions = ["draft"] and renaming draft pages to mypage.html.draft. You can also exclude any file extensions for any reason.

Sorting order for the index data

Originally the index data would be sorted by date in the ascending order, i.e. oldest entries first. It's trivial to correct in a script, but it's an extra operation and everyone who wants a blog will want them in the opposite order. Now you can add newest_entries_first = true to the [index] section and get the entries in the natural order for a blog.

  newest_entries_first = true

Better default config

The default config generated by soupault --init got more illustrative. It now includes an examples of setting the page title (to the first h1), and also a silly example of using the insert_html widget—it adds a generator meta tag in the best traditions of FrontPage. All options now come with comments too.

I hope it will give newcomers a better feel of what kind of things they can do with it. For the record, this is the new default config:

  # Stop on page processing errors?
  strict = true

  # Display progress?
  verbose = false

  # Display detailed debug output?
  debug = false

  # Where to output pages
  build_dir = "build"

  # Where page content files are stored
  site_dir = "site"

  # Where page template is stored
  default_template = "templates/main.html"

  # Where to insert the page content inside the template
  content_selector = "body"

  doctype = "<!DOCTYPE html>"

  clean_urls = true

  # Files with these extensions are considered pages and processed
  # All other files are copied to build/ unchanged
  page_file_extensions = ["htm", "html", "md", "rst", "adoc"]

  # Files with these extensions are ignored
  ignore_extensions = ["draft"]

# Takes the content of the first <h1> and inserts it into the <title>
  widget = "title"
  selector = "h1"
  default = "My Homepage"
  append = " — My Homepage"

# Inserts a generator meta tag in the page <head>
# Just for demonstration, feel free to remove
  widget = "insert_html"
  html = '<meta name="generator" content="soupault 1.4">'
  selector = "head"

There's also a friendlier post-init message.