documentation

overview

halp works by translating directories of files into pages - either Gemini or Web pages.

I intended the experience of halp to be as close to using simple, familiar, Unix tools as possible. Pages are defined by directories. Content is described in plain HTML or Gemtext. Titles, descriptions, etc. live in dotfiles. Content history (for Atom feeds) is extracted from Git logs.

getting started

halp requires very few files to get started. Here's the minimum directory structure necessary to generate both Web and Gemini content:


$ tree -a
.
├── gemini
│   └── .gitkeep
├── halp-config.pl
├── tmp
│   ├── gemini
│   │   └── .gitkeep
│   └── web
│       └── .gitkeep
└── web
    └── .gitkeep

It is necessary that the above files and directories be committed to Git (hence the .gitkeep files). halp relies upon Git history to generate Atom feeds for content, as I'll explain later.

The configuration file, halp-config.pl, is a Perl file containing the Website and Gemini Capsule configuration:


{
  author => {
    email => 'alice@example.com',
    name => 'Alice'
  },

  domain => 'example.com',

  gemini => {
    host => 'http://example.com:8080',
    input_path => '.gemini',
    output_path => './tmp/gemini'
  },

  web => {
    host => 'http://example.com:8080',
    input_path => '.web',
    output_path => './tmp/web'
  }
}

To generate both the static Gemini capsule and Website from the above configuration and directory structure, you'd run:


$ perl ./halp.pl --config-filename ./halp-config.pl --gemini
$ perl ./halp.pl --config-filename ./halp-config.pl --web

This produces a simple Website and Gemini capsule that you can deploy by whatever means you choose (self-hosting with Caddy or Molly Brown, through a CDN, etc.):


tmp
├── gemini
│   ├── .gitkeep
│   ├── .static
│   │   └── images
│   │       ├── atom.png
│   │       ├── bvbrows.gif
│   │       ├── favicon.png
│   │       ├── halp-icon.jpg
│   │       ├── mothracompat.gif
│   │       ├── valid-atom.png
│   │       ├── valid-html5.png
│   │       └── vcss-blue
│   ├── feed.xml
│   ├── index.gmi
│   └── robots.txt
└── web
    ├── .gitkeep
    ├── .static
    │   ├── images
    │   │   ├── atom.png
    │   │   ├── avatar.jpg
    │   │   ├── bvbrows.gif
    │   │   ├── favicon-128x128.png
    │   │   ├── favicon-16x16.png
    │   │   ├── favicon-256x256.png
    │   │   ├── favicon-32x32.png
    │   │   ├── favicon-512x512.png
    │   │   ├── favicon-64x64.png
    │   │   ├── favicon-96x96.png
    │   │   ├── favicon-apple-touch-icon-152x152.png
    │   │   ├── favicon-apple-touch-icon-167x167.png
    │   │   ├── favicon-apple-touch-icon-180x180.png
    │   │   ├── favicon.ico
    │   │   ├── halp-icon.jpg
    │   │   ├── mothracompat.gif
    │   │   ├── valid-atom.png
    │   │   ├── valid-html5.png
    │   │   └── vcss-blue
    │   └── styles
    │       └── halp.css
    ├── feed.xml
    ├── index.html
    └── robots.txt

here's one I prepared earlier

The halp website, halp.fyi is, of course, built with halp! Probably the easiest way of learning halp is just to take a look at the configuration and input directory used to build it:

how halp works

For both Gemini and Web content, halp takes the same approach:

  1. It generates a menu from the root directory, listing the pages and subdirectories of the root directory.
  2. For each non-hidden directory, it generates an index page listing the directory contents.
  3. For each non-hidden directory, it generates an Atom feed (feed.xml).
  4. For each content file (.gmi for Gemini, .html for Web), it renders that content into a template that includes the menu.
  5. For each non-content file (e.g. images and binaries), it simply copies the file into the output directory.

Note that hidden files (i.e. those beginning with .) are not copied into the output directory, but hidden directories are.

titles and descriptions

If a directory contains a .description.html or .description.gmi file, that description is included in the index page before the directory contents. If a directory contains a .title file, the contents of that file will be used as the title instead of the directory name. E.g.:


$ tree -a
.
├── .description.html
└── .title

If a file has a matching dotfile containing a title, that will be used for the title instead of the filename. E.g.:


$ ls .*public* *public*
.2023-01-06-public-inbox-experiment.gmi.title
2023-01-06-public-inbox-experiment.gmi

static files

halp copies the following default static files into all generated Websites:


.
├── .static
│   └── images
│       ├── atom.png
│       ├── bvbrows.gif
│       ├── favicon.png
│       ├── halp-icon.jpg
│       ├── mothracompat.gif
│       ├── valid-atom.png
│       ├── valid-html5.png
│       └── vcss-blue
└── robots.txt

... and it copies the following default static files into all generated Gemini capsules:


.
├── .static
│   ├── images
│   │   ├── atom.png
│   │   ├── avatar.jpg
│   │   ├── bvbrows.gif
│   │   ├── favicon-128x128.png
│   │   ├── favicon-16x16.png
│   │   ├── favicon-256x256.png
│   │   ├── favicon-32x32.png
│   │   ├── favicon-512x512.png
│   │   ├── favicon-64x64.png
│   │   ├── favicon-96x96.png
│   │   ├── favicon-apple-touch-icon-152x152.png
│   │   ├── favicon-apple-touch-icon-167x167.png
│   │   ├── favicon-apple-touch-icon-180x180.png
│   │   ├── favicon.ico
│   │   ├── halp-icon.jpg
│   │   ├── mothracompat.gif
│   │   ├── valid-atom.png
│   │   ├── valid-html5.png
│   │   └── vcss-blue
│   └── styles
│       └── halp.css
└── robots.txt

In either case, if your input directory contains any of those files, the file from your input directory will be copied instead of the default static file. So e.g. you could include ./robots.txt in your input directory, and that would be what gets included instead of the default halp ./robots.txt.

atom feeds

Atom feeds are generated using timestamps from Git. The updated value for each entry is the last modified time for the input file, according to git. This has two consequences:
  1. All files in your input directory must be checked in to Git.
  2. If you build your Website or Gemini capsule before you check all your files into Git, the entry for files not checked in will have an updated value of the Unix epoch (Thursday, 1 January 1970 12:00:00 AM).

templates

halp has a set of simple text templates (courtesy the Text::Template library) that it uses for Gemini and Web content:


web/templates/
├── directory_listing.html.tpl
├── menu.html.tpl
└── page.html.tpl

gemini/templates/
├── directory_listing.gmi.tpl
├── menu.gmi.tpl
└── page.gmi.tpl

They are the same for all pages; customisation of title, description (in the case of directories), is done via dotfiles as described in titles and descriptions above.

Every halp page contains a menu (inspired by Brad Taunt's hamburgers post) at the bottom. The menu consists of links to: