ussg

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit e50d0409130b9c3b583396263df76a873297a290
parent 4fdd90df3d434834d15180bb4c24a600a4965c3d
Author: Ellenor Bjornsdottir <ellenor@umbrellix.net>
Date:   Wed, 14 Sep 2022 07:56:32 +0000

New options - quick mode, noheaders mode (legacy for sites that use plain Markdown)

Diffstat:
Mdoc/interface.md | 33+++++++++++++++++++++++++++------
Mplugins/navbar.tm | 6+++---
Mussg-page | 131++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
3 files changed, 134 insertions(+), 36 deletions(-)

diff --git a/doc/interface.md b/doc/interface.md @@ -15,23 +15,44 @@ The second side-stream input format of ussg is template, tbd. The third etc. side-stream input formats of ussg is HTML. These are printed verbatim to the output file in their template-appropriate locations, and the recommended template (which also includes some verbatim HTML5) has 4 such positions. These side-stream inputs are pointed to from headers. +A header name is separated from its value by one colon, and exactly one space. The space may be any character, but for readability it should be a space. + The names and purposes of the headers are thus: Name|Type|Purpose -|-|- -Title|Once|Set head::title +Title-Separator|Once|When guessing the title, this is used with X-Site-Title to esthetically improve the path. If not specified, defaults to '::'. +Title|Once|Set head::title, instead of guessing. If not specified, the title will be guessed. This should be specified per-page so that guessing can occur on pages where ussg-page must be invoked with -N. X-Site-Title|Once|Set site title (shown between header nav, and opt sidebar nav) X-Site-Description|Once|Set site subtitle X-Synoptic-Title|Once|Set meta og:title (synoptic title of the content) +X-Synoptic-Sitename|Once|Set meta og:site_name (synoptic site name) X-Synoptic-Text|Once|Set meta og:description (synoptic description of the content) -Favicon|Once|Favicon -Template|Once|Template +X-Synoptic-Image|Once|Set meta og:image (synoptic image of the content) +X-Synoptic-URL|Once|Set meta og:url (synoptic URL of the content) +Favicon|Once|Favicon in vnd.microsoft.icon format +Template|Once, Mandatory|Template. This defines the basic HTML layout of the Style|inf times|CSS style, relative to the webpage -Verbatim|n times|HTML printed verbatim where the Template requests %n +Verbatim|n times|HTML printed verbatim where the Template requests %n, where n is the number of Verbatim headers Plugin|inf times|Load a template command plugin +Url-Prefix|Once|(Only used by Navbar, but globally defined) Output filenames in the web server will have this prefix, which is not part of their filename on disk. This is mainly to be used for tilde space websites, where you don't have control to the root domain, where you are specifying links in navbar-type plugins relative to the root of the web server. +Raw-Head|inf times|Insert the following text at the position of the %heads template command, after synoptics, favicon and style +Navbar-Prefix|Once|Output filenames as they are being generated will have this prefix, which is not part of the URL. Co-opted from Navbar plugin. + +Plugins, which alter the template processing engine, can process headers, but cannot set that a header may only occur once. They must, instead, select the last occurrence of a given header in their processing routine. + +The names and purposes of the headers used by the Navbar plugin are thus: + +Name|Type|Purpose +-|-|- +Navbar-Prefix|Once|Output filenames as they are being generated will have this prefix, which is not part of the URL. +Navbar-Source|Once|The name of a file, tab separated values, which contains path and label data for the navbar. +Navbar-Title|Once|Add a title to the navbar. Blatant imitation of werc The invokation of the utility is thus (program name subject to change): -`ussg-page [-hv] [-H headers] input [output]` +`ussg-page [-hvN] [-HM headers markdown] input [output]` + +It is meant to be invoked from a makefile, and its output, if on standard output, is supposed to be redirected to a temporary file, then moved atomically over the intended name. This is done automatically if you use a filename output. -It is meant to be invoked from a makefile, and its output, if on standard output, is supposed to be redirected to a temporary file, then moved atomically over the intended name. This is done automaticall if you use a filename output. +**All input text should be properly HTML entity encoded, including the article segment after it has been processed by the markdown processor.** Failure to do so will result in corruption. diff --git a/plugins/navbar.tm b/plugins/navbar.tm @@ -30,7 +30,7 @@ proc navbar {} { puts stderr $provinputfd return } { - if {$navtitle != ""} {puts $::outputfd [format "<p class=\"sideBarTitle\">%s</p>" $navtitle]} + if {$navtitle != ""} {puts $::outputfd [format "<p class=\"sideBarTitle\">%s</p>" [lindex $navtitle end]]} puts $::outputfd "<ul>" while {![eof $provinputfd]} { set garbage [lassign [split [gets $provinputfd] "\t"] path label] @@ -44,9 +44,9 @@ proc navbar {} { if {[file normalize [format "%s/%s" $prefix $path]] == [file normalize $outputfile]} {set isthispath 1} } if {$isthispath} { - puts $::outputfd [format "<li><a href=\"%s\" class=\"thisPage\">&rsaquo; <i>%s</i></a></li>" $path $label] + puts $::outputfd [format "<li><a href=\"%s\" class=\"thisPage\">&raquo; <i>%s</i></a></li>" $path $label] } { - puts $::outputfd [format "<li><a href=\"%s\">&raquo; <i>%s</i></a></li>" $path $label] + puts $::outputfd [format "<li><a href=\"%s\">&rsaquo; %s</a></li>" $path $label] } } puts stderr [format "info: navbar plugin: prefix: %s outputfile: %s path: %s label: %s isthispath: %s" $prefix $outputfile $path $label $isthispath] diff --git a/ussg-page b/ussg-page @@ -156,6 +156,14 @@ Options: output file. Instead, balks with EX_CANTCREAT (73). This is not default, but it is recommended to use this if possible. + -N/--noheaders + The input file does not contain headers. It starts + immediately with content. + -Q/--quick + Not applicable if either file is the standard descriptor. + The mtimes of the input and output files are compared. + Should the output file not exist, or should it be older + than the input file, Specifying multiple short options together will result in them being interpreted separately, including dash options that @@ -202,7 +210,7 @@ set inputfile "" set outputfile "" set headersfiles [list] set headersfds [list] -set markdown [list env markdown] +set markdown "env markdown" set scribble 1 set moving 0 ;# 1 means that we'll have to move data after. @@ -226,15 +234,20 @@ set headermulti { verbatim 1 execverbatim 1 plugin 1 + url-prefix 0 + navbar-prefix 0 } -set parsedargs [opts [list h v H: M: help version headers: markdown:] $argv] +set parsedargs [opts [list h v H: M: N Q help version headers: markdown: noheaders quick] $argv] # opts [list h v H: M: help version headers: markdown:] [list input --markdown /usr/bin/markdown output -HMEQI .headers /usr/bin/markdown -- -EQI -- -- --] # warning: option -E not recognized by this program. Treating as a SEPARATE non-option argument - if this wasn't intended, put the argument containing this option after a '--'! # warning: option -Q not recognized by this program. Treating as a SEPARATE non-option argument - if this wasn't intended, put the argument containing this option after a '--'! # warning: option -I not recognized by this program. Treating as a SEPARATE non-option argument - if this wasn't intended, put the argument containing this option after a '--'! # {{markdown /usr/bin/markdown} {H .headers} {M /usr/bin/markdown}} {input output -E -Q -I -EQI -- -- --} +set firstblankline 0 +set quick 0 + lassign $parsedargs opts arg foreach {opt} $opts { @@ -261,6 +274,16 @@ foreach {opt} $opts { set ::markdown [lindex $opt 1] } + Q - + quick { + set ::quick 1 + } + + N - + noheaders { + set ::firstblankline 1 + } + R - restricted { set ::scribble 0 @@ -278,6 +301,7 @@ proc picktmpfilename {filename} { } if {[llength $arg] == 2} { + set inputfile [lindex $arg 0] set outputfile [lindex $arg 1] if {$outputfile == "-"} { } else { @@ -300,6 +324,22 @@ if {[llength $arg] == 2} { puts stderr $mkdirerr exit 73 } + if {$::quick && $::inputfile != "-"} { + # spend time to save time + if {[file exists $::outputfile] && + [file exists $::inputfile]} { + if {[set outputmtime [file mtime $::outputfile]] >= [set inputmtime [file mtime $::inputfile]]} { + puts stderr [format "Info: output file \'%s\' is newer (%s) than input file \'%s\' (%s)" $::outputfile $outputmtime $::inputfile $inputmtime] + exit 0 + } { + puts stderr [format "Info: output file \'%s\' was modified %s, input file \'%s\' was modified (%s)" $::outputfile $outputmtime $::inputfile $inputmtime] + } + } { + puts stderr [format "Info: only one of the two files exists"] + } + } { + puts stderr [format "Info: quick mode disabled, or input file == -"] + } if {[catch {open [set ::tmpoutputfile [picktmpfilename [set outputfile [file normalize $outputfile]]]] w} provoutputfd]} { puts stderr [format "Error: temporary output file \'%s\' could not be opened for writing. \[open\] reports:" $::tmpoutputfile] puts stderr $provoutputfd @@ -361,14 +401,8 @@ foreach headersfd $::headersfds { close $headersfd } -set firstblankline 0 -if {[catch {open [format "|%s" $markdown] r+} err]} { - puts stderr [format "Error: processor \'%s\' could not be executed for reading and writing. \[open\] reports:" $markdown] - puts stderr $err - exit 70 -} { - set mkdownfd $err -} +#firstblankline was set earlier +# if it's already 1 (user specified -N) we skip this. while {![eof $inputfd] && !$firstblankline} { gets $inputfd lin @@ -403,29 +437,71 @@ if {[catch {dict get $::headers template} templatehdr]} { } proc templcmdsrc {script} { + namespacesrc ::templcmds $script +} + +proc namespacesrc {namespace script} { if {[catch {open [file normalize $script] r} provinputfd]} { - puts stderr [format "Error: template command plugin file \'%s\' could not be opened for reading. Balking now; this is fatal. \[open\] reports:" $script] + puts stderr [format "Error: namespace \'%s\' file \'%s\' could not be opened for reading. Balking now; this is fatal. \[open\] reports:" $namespace $script] puts stderr $provinputfd exit 66 } { set fp $provinputfd } #set fp [open $script r] - set ev [list namespace eval ::templcmds [read $fp]] + set ev [list namespace eval $namespace [read $fp]] close $fp uplevel "#0" $ev } -if {![catch {dict get $::headers plugin} pluginhdr]} { - foreach {script} $pluginhdr { - templcmdsrc $script +# proc markdown: fd inputfd +# attributes: might block +# globals: markdown outputfd +# processfd markdown inputfd outputfd +# side effects: closes inputfd +proc markdown {inputfd} { + processfd $::markdown $inputfd $::outputfd + chan close $inputfd +} + +# proc processfd: string markdown, fd inputfd, fd outputfd +# attributes: might block +# process the remainder of inputfd, blocking if no data is available, +# with the program markdown (which must be a suitable Unix filter), +# outputting to outputfd +# leaves inputfd at EOF +proc processfd {markdown inputfd outputfd} { + # finally, our raison d'etre ! + # we expect to get eof on input. + if {[catch {open [format "|%s" $markdown] r+} err]} { + puts stderr [format "Error: processor \'%s\' could not be executed for reading and writing. \[open\] reports:" $markdown] + puts stderr $err + exit 70 + } { + set mkdownfd $err } + chan copy $inputfd $mkdownfd + chan flush $mkdownfd + chan close $mkdownfd write + # begone, input document + chan copy $mkdownfd $outputfd + chan flush $outputfd + chan close $mkdownfd read + # begone, markdown } namespace eval ::templcmds { proc title {} { # output page title - if {![catch {dict get $::headers title} title]} { puts $::outputfd [format "<title>%s</title>" $title] } + if {[catch {dict get $::headers title} title]} { + if {![catch {dict get $::headers navbar-prefix} navprefix]} {set prefix $navprefix} {set prefix ""} + if {![catch {dict get $::headers x-site-title} navprefix]} {set title $navprefix} {set title "Site Title Not Set"} + if {![catch {dict get $::headers title-separator} sep]} {set sep $sep} {set sep "::"} + set filename [string map [list [file normalize $prefix] ""] $::outputfile] + append title [format " %s " $sep] + append title [string map [list "<" "&lt;" ">" "&gt;" [file separator] $sep] [string trimleft $filename [file separator]]] + } + puts $::outputfd [format "<title>%s</title>" $title] } proc xsitetitle {} { @@ -461,20 +537,15 @@ namespace eval ::templcmds { if {![catch {dict get $::headers style} title]} { puts $::outputfd [format "<link rel=\"stylesheet\" href=\"/%s\" type=\"text/css\">" $title] } + if {![catch {dict get $::headers raw-head} rawheadhdr]} { + foreach {rawhead} $rawheadhdr { + puts $::outputfd $rawhead + } + } } proc article {} { - # finally, our raison d'etre ! - # we expect to get eof on input. - chan copy $::inputfd $::mkdownfd - chan flush $::mkdownfd - chan close $::mkdownfd write - chan close $::inputfd - # begone, input document - chan copy $::mkdownfd $::outputfd - chan flush $::outputfd - chan close $::mkdownfd read - # begone, markdown + markdown $::inputfd } proc verbatim {num} { @@ -498,6 +569,12 @@ namespace eval ::templcmds { namespace ensemble create } +if {![catch {dict get $::headers plugin} pluginhdr]} { + foreach {script} $pluginhdr { + templcmdsrc $script + } +} + proc templcmd {command} { if {[string is entier [string trimleft $command "%"]]} { templcmds verbatim [string trimleft $command "%"]