About me: My name is Solène Rapenne, pronouns she/her. I like learning and sharing knowledge. Hobbies: '(BSD OpenBSD Qubes OS Lisp cmdline gaming security QubesOS internet-stuff). I love percent and lambda characters. OpenBSD developer solene@. No AI is involved in this blog.

Contact me: solene at dataswamp dot org or @solene@bsd.network (mastodon).

I'm a freelance OpenBSD, FreeBSD, Linux and Qubes OS consultant, this includes DevOps, DevSecOps, technical writing or documentation work. If you enjoy this blog, you can sponsor my open source work financially so I can write this blog and contribute to Free Software as my daily job.

New cl-yag version

Written by Solène, on 16 December 2017.
Tags: #unix #cl-yag

Comments on Fediverse/Mastodon

Introduction

cl-yag is a static website generator. It's a software used to publish a website and/or a gopher hole from a list of articles. As the developer of cl-yag I'm happy to announce that a new version has been released.

New features

The new version, with its number 0.6, bring lot of new features :

  • supporting different markup language per article
  • date format configurable
  • gopher output format configurable
  • ship with the default theme "clyma", minimalist but responsive (the one used on this website)
  • easier to use
  • full user documentation

The code is available at git://bitreich.org/cl-yag, the program requires sbcl or ecl to work.

Per article markup language

The best feature I'm proud of is allowing to use a different language per article. While on my blog I choosed to use markdown, it's sometimes not adapted for more elaborated articles like the one about LISP containing code which was written in org-mode then converted to markdown manually to fit to cl-yag. Now, the user can declare a named "converter" which is a command line with pattern replacement, to produce the html file. We can imagine a lot of things with this, even producing a gallery with find + awk command. Now, I can use markdown by default and specify if I want to use org-mode or something else.

This is the way to declare a converter, taking org-mode as example, which is not very simple, because of emacs not being script friendly :

(converter :name :org-mode  :extension ".org"
           :command (concatenate 'string
                                 "emacs data/%IN --batch --eval '(with-temp-buffer (org-mode) "
                                 "(insert-file \"%IN\") (org-html-export-as-html nil nil nil t)"
                                 "(princ (buffer-string)))' --kill | tee %OUT"))

And an easy way to produce a gallery with awk from a .txt file containing a list of images path.

(converter :name :gallery :extension ".txt"
           :command (concatenate 'string
                                 "awk 'BEGIN { print \"<div class=\\\"gallery\\\">\"} "
                                 "{ print \"<img src=\\\"static/images/\"$1\"\\\" />\" } "
                                 " END { print  \"</div>\"} data/%IN | tee %OUT"))

The concatenate function is only used to improve the presentation, to split the command in multiples lines and make it easier to read. It's possible to write all the command in one line.

The patterns %IN and %OUT are replaced by the input file name and the output file name when the command is executed.

For an easier example, the default markdown converter looks like this, calling multimarkdown command :

(converter :name :markdown :extension ".md"
           :command "multimarkdown -t html -o %OUT data/%IN")

It's really easy (I hope !) to add new converters you need with this feature.

Date format configurable

One problem I had with cl-yag is that it's plain vanilla Common LISP without libraries, so it's easier to fetch and use but it lacks some elaborated libraries like one to parse date and format a date. Before this release, I was writing in plain text "14 December 2017" in the date field of a blog post. It was easy to use, but not really usable in the RSS feed in the pubDate attribute, and if I wanted to change the display of the date for some reason, I would have to rewrite everything.

Now, the date is simply in the format "YYYYMMDD" like "20171231" for the 31rd December 2017. And in the configuration variable, there is a :date-format keyword to define the date display. This variable is a string allowing pattern replacement of the following variables :

%DayNumber
day of the month in number, from 1 to 31
%DayName
day of the week, from Monday to Sunday, names are written in english in the source code and can be translated
%MonthNumber
month in number, from 1 to 12
%MonthName
month name, from January to December, names are written in english in the source code and can be translated
%Year
year

Currently, as the time of writing, I use the value "%DayNumber %MonthName %Year"

A :gopher-format keyword exist in the configuration file to configure the date format in the gopher export. It can be different from the html one.

More Gopher configuration

There are cases where the gopher server use an unusual syntax compared to most of the servers. I wanted to make it configurable, so the user could easily use cl-yag without having to mess with the code. I provide the default for geomyidae and in comments another syntax is available. There is also a configurable value to indicates where to store the gopher page menu, it's not always gophermap, it could be index.gph or whatever you need.

Easier to use

A comparison of code will make it easier to understand. There was a little change the way blog posts are declared :

From

(defparameter *articles*
  (list
   (list :id "third-article"  :title "My third article" :tag "me" :date "20171205")
   (list :id "second-article" :title "Another article"  :tag "me" :date "20171204")
   (list :id "first-article"  :title "My first article" :tag "me" :date "20171201")
   ))

to

(post :id "third-article"  :title "My third article" :tag "me" :date "20171205")
(post :id "second-article" :title "Another article"  :tag "me" :date "20171204")
(post :id "first-article"  :title "My first article" :tag "me" :date "20171201")

Each post are independtly declared and I plan to add a "page" function to create static pages, but this is going to be for the next version !

Future work

I am very happy to hack on cl-yag, I want to continue improving it but I should really think about each feature I want to add. I want to keep it really simple even if it limits the features.

I want to allow the creation of static pages like "About me", "Legal" or "websites I liked" that integrates well in the template. The user may not want all the static pages links to go at the same place in the template, or use the same template. I'm thinking about this.

Also, I think the gopher generation could be improved, but I still have no idea how.

Others themes may come in the default configuration, allowing the user to have a choice between themes. But as for now, I don't plan to bring a theme using javascript.