Skip to content

luciusmagn/shsx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Readme

SHSX (Scheme HTML S-expressions)

A simple and powerful HTML generator for Gerbil Scheme.

Installation

Add this to your .gerbil/lib directory or install directly from source:

git clone https://github.com/luciusmagn/shsx
cd shsx
gxpkg install .

Basic Usage

SHSX uses a simple syntax where HTML elements are represented as S-expressions with colons:

(import :shsx/lib)

(define example
 (shsx
  (div: class: "container"
       (h1: "Welcome to SHSX")
       (p: "This is an example paragraph."))))

(displayln (render-html example))

This generates:

<div class="container">
 <h1>Welcome to SHSX</h1>
 <p>This is an example paragraph.</p>
</div>

You need to use unquoting to insert values into the template.

(shsx
 (p: class: ,my-classes "Hello!"))

If you are inserting from a variable with user data, make sure to sanitize the string:

(shsx
 (blockquote: ,(sanitize user-input)))

Control Flow

SHSX provides several control flow macros. Only the macro itself has to be unquoted, not the condition or the branches

@if

Conditional rendering:

(define admin? #t)

(shsx
  (div:
   ,(@if admin?
      (p: "Admin panel")
      (p: "Please log in"))))

@when and @unless

One-sided conditions:

(shsx
  (div:
   ,(@when logged-in?
      (p: "Welcome back!")
      (button: "Logout"))
   ,(@unless admin?
      (p: "Regular user area"))))

@begin

Group multiple elements without creating a wrapper:

(shsx
  (div:
   ,(@begin
     (h1: "Title")
     (p: "First paragraph")
     (p: "Second paragraph"))))

Self-closing Tags

SHSX automatically handles self-closing tags like img:, br:, input::

(shsx
  (div:
   (img: src: "cat.jpg" alt: "A cute cat")
   (br:)
   (input: type: "text" placeholder: "Enter name")))

Dynamic Content

You can unquote Scheme expressions inside SHSX:

(define name "Alice")
(define items '("One" "Two" "Three"))

(shsx
  (div:
   (h1: "Hello, " ,name "!")
   (ul: class: ,(if (> (length items) 2) "big-list" "small-list")
     (li: ,(car items))
     (li: ,(cadr items)))))

Quasiquoting in SHSX

SHSX uses standard Scheme quasiquoting syntax to interpolate dynamic content:

Single Unquote (,)

Used to evaluate expressions, including control flow macros:

(define name "Alice")
(define admin? #t)

(shsx
 (div:
   (h1: "Hello, " ,name "!")
   ,(@when admin?  ; Control macros use simple unquote
      (button: "Delete")
      (button: "Edit"))))

Unquote-Splicing (,@)

Used to splice lists of elements directly into parent:

(define items '("One" "Two"))
(shsx
 (ul:
   ,@(map (lambda (x)
           (li: x))
         items)))
;; Generates:
;; <ul>
;;   <li>One</li>
;;   <li>Two</li>
;; </ul>

;; Without ,@ would generate invalid:
;; <ul>((li: "One") (li: "Two"))</ul>

Predicate and sanitization

You can test whether something is a SHSX template using the shsx-template? predicate:

(shsx-template? (shsx (div:))) => #t
(shsx-template? '(div:)) => #f

And you can sanitize strings with sanitize

(test-case "String sanitization"
  (check (equal? (sanitize "<script>") "&lt;script&gt;") => #t)
  (check (equal? (sanitize "a & b") "a &amp; b") => #t)
  (check (equal? (sanitize "\"quote\" and 'apostrophe'")
                 "&quot;quote&quot; and &#39;apostrophe&#39;") => #t)
  (check (string? (render-html sanitize-test)) => #t))

License

Fair License

Copyright © 2025 Lukáš Hozda

Usage of the works is permitted provided that this instrument is retained with the works, so that any entity that uses the works is notified of this instrument.

DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published