2
10
Fork
You've already forked sutter
3
A static HTML blog / Gemini capsule generator
C 98.9%
Makefile 0.5%
Python 0.5%
Find a file
2025年12月09日 04:46:18 +01:00
tools Use xs_str_wrap_i() in many places. 2023年01月16日 14:27:48 +01:00
.gitignore More files. 2023年01月13日 15:09:38 +01:00
data.c Render tag indexes. 2025年04月23日 07:11:20 +02:00
LICENSE Bumped copyright year. 2025年01月13日 09:25:51 +01:00
main.c Bumped copyright year. 2025年01月13日 09:25:51 +01:00
Makefile Render tag indexes. 2025年04月23日 07:11:20 +02:00
parallel.c Render tag indexes. 2025年04月23日 07:11:20 +02:00
README.md Updated README. 2024年10月08日 10:53:14 +02:00
RELEASE_NOTES.md Updated RELEASE_NOTES. 2025年12月09日 04:46:18 +01:00
render.c Added a 2nd level UL in gemini. 2025年12月09日 04:44:38 +01:00
sutter.c Bumped copyright year. 2025年01月13日 09:25:51 +01:00
sutter.css More rendering work. 2023年01月15日 12:18:11 +01:00
sutter.h Render tag indexes. 2025年04月23日 07:11:20 +02:00
TODO.md Updated TODO. 2024年09月05日 13:49:59 +02:00
utils.c New server-wide or post setting named 'author_fediverse'. 2025年01月17日 10:31:31 +01:00
xs.h Added a 2nd level UL in markdown. 2025年12月09日 04:42:07 +01:00
xs_btree.h Backport from xs. 2025年07月26日 07:08:24 +02:00
xs_hex.h Bumped copyright year. 2025年01月13日 09:25:51 +01:00
xs_html.h Backport from xs. 2025年06月12日 11:46:37 +02:00
xs_io.h Backport from xs. 2025年02月06日 11:04:11 +01:00
xs_json.h Added a 2nd level UL in markdown. 2025年12月09日 04:42:07 +01:00
xs_match.h Also add the 'discuss' link to Gemini pages. 2025年01月25日 08:28:19 +01:00
xs_md5.h Backport from xs. 2023年12月27日 09:50:19 +01:00
xs_mime.h Backport from xs. 2025年07月01日 19:14:00 +02:00
xs_regex.h Backport from xs. 2025年06月12日 11:46:37 +02:00
xs_time.h Added a 2nd level UL in markdown. 2025年12月09日 04:42:07 +01:00
xs_unicode.h Added a 2nd level UL in markdown. 2025年12月09日 04:42:07 +01:00
xs_unicode_tbl.h Bumped copyright year. 2025年01月13日 09:25:51 +01:00
xs_version.h Added a 2nd level UL in markdown. 2025年12月09日 04:42:07 +01:00

sutter

A static HTML blog / Gemini capsule generator

Features

  • Lightweight (written in C, no dependencies on libraries nor programs)
  • Multithreaded
  • Simple as hell

Description

sutter (as in "Do you read Sutter Cane...?") is a standalone program which duty is to explore a directory of files (with as many subdirectory levels as desired) and generate an HTML-based blog and a Gemini capsule with the same directory hierarchy as possible.

Files with the extensions .html, .gmi, .md, .raw_html and .raw_gmi are considered by sutter to be special "source" files. These files can have a set of metadata appended to the end, like the post entry title, the publishing date and the author information. These metadata is looked up after a line containing the string __META__ on its own. If sutter finds a "source" file that does not contain this metadata, it adds it with some default values. Source file links and references are added to the indexes (more below).

The processor does the following to each type of file found:

  • HTML (.html) files: adds a common header and footer and writes the result to the www output directory.
  • Gemini (.gmi) files: does two things: adds a common header and footer and writes the result to the gmi output directory; also, it converts the entry to HTML with a common header and footer and writes the result to the www directory.
  • Markdown (.md) file: converts the entry to HTML with a common header and footer and writes the result to the www directory. This is a special subset of Markdown (see below) and no external tools are called nor needed.
  • Raw HTML (.raw_html) files: copies the file as is (renamed with an .html extension) to the www directory.
  • Raw Gemini (.raw_gmi) files: copies the file as is (renamed with a .gmi extension) to the gmi output directory.
  • The rest of the files are hard-linked from the src directory to both output directories.

The following indexes are updated for each processed file:

  • For HTML and converted Gemini files: www/rss.xml, www/archive.html and www/sitemap.xml.
  • For Gemini files: gmi/archive.gmi.

Files that have not changed are not rewritten to be gentle to rsync and similar tools that may transfer the blog/capsule to another host.

Building and installation

Run make and then make install as root.

Usage

sutter has the following commands:

sutter init [{storage directory}]

Prompts for some basic information and creates an empty directory storage (see below).

sutter run {storage directory}

Does its thing and builds the content of the output directories.

sutter check {storage directory}

Checks that all entries in the storage directory have metadata and, for those that don't, adds it. The run command implies this.

sutter 2html {Markdown or Gemini file}

Converts a Markdown (.md) or Gemini (.gmi) file to HTML to STDOUT. Take note that you don't need a sutter storage for this operation to work.

Storage directory file hierarchy

The following files and directories are inside a sutter storage directory:

  • src/: The source directory. This is where you will create your source files.
  • www/: The directory where the Weblog is generated. This is what you will transfer to a directory in your HTTP server.
  • gmi/: The directory where the Gemini capsule is generated. This is what you will transfer to a directory in your Gemini server.
  • sutter.json: The configuration file (see below).
  • sutter.css: A tiny CSS file that will be inserted into all you HTML files.

Configuration directives

The sutter.json file is a JSON file with the following fields:

  • title: The blog/capsule title. Will be inserted in all titles and as the main 'back to top' link.
  • baseurl: The base URL for your blog. sutter tries to build all links as relative, but some things like the RSS file needs a complete base URL.
  • author_name: You (the default author).
  • author_email: Your email.
  • author_avatar: The URL to an image to be used as an avatar for your posts. If it's not defined, a Gravatar created using your author_email will be used instead.
  • srcdir, wwwdir and gmidir: The subdirectory names inside the sutter directory. You can change them, but don't need to.
  • dbglevel: The debug level. The higher the number, the louder sutter will chat about what it's doing. You can override this by setting the DEBUG environment variable to a matching value.
  • minimum_date: If an entry has a date metadata (in yyyy-mm-ddTHH:MM:SSZ format) older than this one, it will NOT be added to any index (but generated as well).
  • cssurls: An array of URLs to CSS files that will be added to all HTML headers.
  • num_rss_entries: The number of post entries in the RSS file (default: 10).

File metadata

File metadata fields appear after the META line in the source files as a keyword, a colon, a space and a content. They can be:

  • title: The entry title. If not defined, sutter will try to create one. Of course, you can always re-edit the file to change it.
  • date: The publishing date in yyyy-mm-ddTHH:MM:SSZ format. If this field is not defined, sutter will create one from the file date. If a file has a date that is in the future or older than the one defined in the minimum_date field of the configuration file, it's generated but NOT added to any index.
  • lang: A two-letter identifier of the language the entry is written in.
  • keywords: A comma-separated list of keywords that tag the entry.
  • author_name, author_email and author_avatar: If these fields exist, they are used instead of the values defined in the configuration file. Useful for guest contributions (you have those, don't you?).

Special URIs

Special markup that look like URIs (i.e. a keyword followed by a colon and two slashes) can be used as shortcuts for some HTML tagsets that are somewhat cumbersome to write. They can be used in .html and .md files. They can be:

img ://image.jpg An img tag for image files
img ://image.jpg/css_class An img tag wrapped in a css_class
story ://path/to_entry A link to an entry
story ://path/to_entry (link label) A link to an entry with a label
link ://example.host/path/path An http link to an URL
link ://example.host/path/path (label) An http link to an URL with a label
links ://example.host/path/path An https link to an URL
links ://example.host/path/path (label) An https link to an URL with a label

Markdown

The subset of Markdown implemented by sutter allows:

  • Italic, bold and monospaced text using one asterisk, two asterisks and backticks;
  • Strikethought text surrounded by two tildes;
  • Preformatted text surrounded by lines starting with three backticks;
  • Headers for lines prefixed with one, two or three hash symbols;
  • Bullet lists for lines prefixed by hyphens;
  • Blockquotes for paragraphs prefixed with the greater-than symbol.

Since version 1.02, Markdown links in the URL label format are supported.

Since version 1.04, Markdown images (like links, but prefixed by a !, and with the label used as the caption and alt text) are supported.

Also since version 1.04, simple Markdown tables are supported, like the following:

Header 1 Header 2 Header 3
Cell 1.1 Cell 1.2 Cell 1.3
Cell 2.1 2.3 (previous one is empty)
Cell 3.1 Cell 3.2 A somewhat longer cell content

Gemini

Gemini files are converted to HTML in a straightforward way. Also, square-bracketed references in paragraph texts are converted to links if there is a link below that starts with the same reference. For example:

Magpies [1] are very intelligent birds.
=> https://en.wikipedia.org/wiki/Magpie [1] Magpie page in Wikipedia

More information

Sutter Cane is the horror writer from John Carpenter's movie In The Mouth Of Madness.

I CAN SEE

License

See the LICENSE file for details.

Author

grunfink @grunfink@comam.es with the help of others.

Buy grunfink a coffee: https://ko-fi.com/grunfink