about summary refs log tree commit diff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/ccwl.skb2
-rw-r--r--doc/skribilo.scm140
2 files changed, 141 insertions, 1 deletions
diff --git a/doc/ccwl.skb b/doc/ccwl.skb
index a56e4fa..fcf6e25 100644
--- a/doc/ccwl.skb
+++ b/doc/ccwl.skb
@@ -17,7 +17,7 @@
 ;;; along with ccwl.  If not, see <https://www.gnu.org/licenses/>.
 
 (use-modules (skribilo lib)
-             (ccwl skribilo))
+             (doc skribilo))
 
 (document :title [Concise Common Workflow Language]
   (chapter :title [Introduction]
diff --git a/doc/skribilo.scm b/doc/skribilo.scm
new file mode 100644
index 0000000..4a1eda0
--- /dev/null
+++ b/doc/skribilo.scm
@@ -0,0 +1,140 @@
+;;; ccwl --- Concise Common Workflow Language
+;;; Copyright © 2021 Arun Isaac <arunisaac@systemreboot.net>
+;;;
+;;; This file is part of ccwl.
+;;;
+;;; ccwl is free software: you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation, either version 3 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; ccwl is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with ccwl.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This module customizes Skribilo to our needs.
+
+;;; Code:
+
+(define-module (doc skribilo)
+  #:use-module (rnrs io ports)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 regex)
+  #:use-module (srfi srfi-171)
+  #:use-module (skribilo ast)
+  #:use-module (skribilo engine)
+  #:use-module (skribilo lib)
+  #:use-module (skribilo package base)
+  #:use-module (skribilo source lisp)
+  #:use-module (skribilo utils keywords)
+  #:use-module (skribilo writer)
+  #:export (command
+            file
+            scheme-source
+            source-ref))
+
+;; Constants
+(define %source-uri-base
+  "https://github.com/arunisaac/ccwl/blob/main/")
+
+;; Aliases
+(define file samp)
+(define command code)
+
+;; Shorthand for scheme source
+(define (scheme-source file)
+  (prog (source #:language scheme #:file file)
+        #:line #f))
+
+;; Abbreviations
+(define-markup (abbr #:rest opts
+		     #:key (ident #f) (class "abbr") (short #f) (long #f))
+  (new container
+       (markup 'abbr)
+       (ident (or ident (symbol->string (gensym "abbr"))))
+       (class class)
+       (loc &invocation-location)
+       (required-options '(#:short #:long))
+       (options `((#:short ,short)
+		  (#:long ,long)
+		  ,@(the-options opts #:ident #:class #:short #:long)))
+       (body (the-body opts))))
+
+;; S-exp source links
+(define (sexp-position str regexp)
+  "Return (START . END) where START is the start of the match to
+REGEXP in STR and END is the end of the sexp beginning at START. START
+and END are character positions indexed from 0. If multiple matches
+are found, error out."
+  (cond
+   ((string-match regexp str)
+    => (lambda (match-struct)
+         (let ((start (match:start match-struct)))
+           (if (string-match regexp (substring str (1+ start)))
+               (error "source-ref: regexp found on multiple lines" regexp)
+               (cons start
+                     (1- (- (string-length str)
+                            (string-length
+                             (call-with-input-string (substring str start)
+                               (lambda (port)
+                                 (read port)
+                                 (get-string-all port)))))))))))
+   (else
+    (error "source-sexp-ref: regexp not found" regexp))))
+
+(define (position->line-number str position)
+  "Return the line number in STR corresponding to POSITION."
+  (string-fold (lambda (c result)
+                 (if (char=? c #\newline)
+                     (1+ result)
+                     result))
+               1
+               (substring str 0 position)))
+
+(define (sexp-file-lines file regexp)
+  "Return (START . END) where START is the start of the match to
+REGEXP in STR and END is the end of the sexp beginning at START. START
+and END are line numbers indexed from 1."
+  (let ((str (call-with-input-file file get-string-all)))
+    (match (sexp-position str regexp)
+      ((start . end)
+       (cons (position->line-number str start)
+             (position->line-number str end))))))
+
+(define (source-ref file regexp text)
+  (call-with-input-file file
+    (lambda (port)
+      (ref #:url (match (sexp-file-lines file regexp)
+                   ((start-line . end-line)
+                    (if (= start-line end-line)
+                        (string-append %source-uri-base
+                                       file
+                                       "#L"
+                                       (number->string start-line))
+                        (string-append %source-uri-base
+                                       file
+                                       "#L"
+                                       (number->string start-line)
+                                       "-L"
+                                       (number->string end-line)))))
+           #:text text))))
+
+;; HTML engine customizations
+(let ((html-engine (find-engine 'html)))
+  (engine-custom-set! html-engine 'css "/style.css")
+  (engine-custom-set! html-engine 'charset "UTF-8")
+  (engine-custom-set! html-engine 'image-format
+                      (list "svg" "png" "gif" "jpg" "jpeg"))
+  (markup-writer 'abbr html-engine
+                 #:options '(#:short #:long)
+                 #:action (lambda (markup engine)
+                            (format #t "<abbr title=\"~a\">~a</abbr> (~a)"
+                                    (markup-option markup #:long)
+                                    (markup-option markup #:short)
+                                    (markup-option markup #:long)))))