aboutsummaryrefslogtreecommitdiff
path: root/doc/skribilo.scm
diff options
context:
space:
mode:
Diffstat (limited to 'doc/skribilo.scm')
-rw-r--r--doc/skribilo.scm148
1 files changed, 148 insertions, 0 deletions
diff --git a/doc/skribilo.scm b/doc/skribilo.scm
new file mode 100644
index 0000000..d97f485
--- /dev/null
+++ b/doc/skribilo.scm
@@ -0,0 +1,148 @@
+;;; guix-forge --- Guix software forge meta-service
+;;; Copyright © 2022 Arun Isaac <arunisaac@systemreboot.net>
+;;;
+;;; This file is part of guix-forge.
+;;;
+;;; guix-forge 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.
+;;;
+;;; guix-forge 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 guix-forge. If not, see
+;;; <https://www.gnu.org/licenses/>.
+
+(define-module (doc skribilo)
+ #:use-module (rnrs conditions)
+ #:use-module (rnrs io ports)
+ #:use-module (srfi srfi-28)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 regex)
+ #:use-module (skribilo ast)
+ #:use-module (skribilo engine)
+ #:use-module (skribilo lib)
+ #:use-module (skribilo writer)
+ #:use-module (skribilo package base)
+ #:use-module (skribilo parameters)
+ #:use-module (skribilo source lisp)
+ #:use-module (skribilo utils keywords)
+ #:export (file
+ command
+ scheme-source
+ scheme-source-form
+ source-ref))
+
+;; Constants
+(define %source-uri-base
+ "https://git.systemreboot.net/guix-forge/tree/")
+
+;; Aliases
+(define file samp)
+(define command code)
+
+;; 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 (source-uri file start-line end-line)
+ "Return a URI referring to source FILE from START-LINE to END-LINE."
+ (string-append %source-uri-base
+ file
+ "#n"
+ (number->string start-line)))
+
+(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)))
+ (raise-exception (condition (make-message-condition
+ (format "source-ref: regexp ~s found on multiple lines"
+ regexp))
+ (make-irritants-condition 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
+ (raise-exception (condition (make-message-condition
+ (format "source-ref: regexp ~s not found" regexp))
+ (make-irritants-condition 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)
+ "Link to S-expression in FILE whose beginning matches REGEXP. TEXT
+is the text of the link."
+ (ref #:url (match (sexp-file-lines (search-path (*source-path*) file)
+ regexp)
+ ((start-line . end-line)
+ (source-uri file start-line end-line)))
+ #:text text))
+
+;; Extract forms from scheme source
+(define (scheme-source-form file regexp)
+ "Extract form from scheme source FILE whose beginning matches
+REGEXP. Return it enclosed in a prog form."
+ (prog (match (sexp-file-lines (search-path (*source-path*) file)
+ regexp)
+ ((start . stop)
+ (source #:language scheme
+ #:file file
+ #:start (1- start)
+ #:stop (1- stop))))
+ #:line #f))
+
+;; 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")
+ (markup-writer 'abbr html-engine
+ #:options '(#:short #:long)
+ #:action (lambda (markup engine)
+ (display (format "<abbr title=\"~a\">~a</abbr> (~a)"
+ (markup-option markup #:long)
+ (markup-option markup #:short)
+ (markup-option markup #:long))
+ (current-output-port)))))