builtin-programs/web/index.folk

Wish the web server handles route "/" with handler {
    fn readOutputFile {path} {
        if {[catch {set fp [open $path r]}]} { return "" }
        set content [read $fp]
        close $fp
        return $content
    }

    fn emitHtmlForProgramList {programList label} {
        set programList [lsort -command {apply {{a b} {string compare $a(programName) $b(programName)}}} $programList]
        set prettyLabel [string map {- " "} $label]
        set prettyLabel [string totitle $prettyLabel]:
        set returnList [list "<details open data-label='$label' data-count='[llength $programList]'><summary>$prettyLabel ([llength $programList])</summary>"]
        lappend returnList "<ul>"
        foreach item $programList {
            set escapedThis [regsub -all -- / $item(programName) __]
            set out [readOutputFile "/var/tmp/folk-[pid]/$escapedThis.stdout"]
            set err [readOutputFile "/var/tmp/folk-[pid]/$escapedThis.stderr"]
            set outputHtml ""
            if {$out ne ""} {
                append outputHtml "<pre style='margin: 0.25em 0 0 1em; padding: 0.25em 0.5em; font-size: 0.85em; white-space: pre-wrap; border-left: 3px solid #888'>[htmlEscape $out]</pre>"
            }
            if {$err ne ""} {
                append outputHtml "<pre style='margin: 0.25em 0 0 1em; padding: 0.25em 0.5em; font-size: 0.85em; white-space: pre-wrap; border-left: 3px solid #c00; color: #c00'>[htmlEscape $err]</pre>"
            }
            set outLen [string length $out]
            set errLen [string length $err]

            set outputSuffix ""
            if {$item(programName) ne "sysmon.c"} {
                set outputSuffix "(<a href='/program/$item(programName)'>source</a>)"
            }
            if {$outLen > 0} { append outputSuffix " <span style='font-size: 0.75em; color: #888'>${outLen}b stdout</span>" }
            if {$errLen > 0} { append outputSuffix " <span style='font-size: 0.75em; color: #888'>${errLen}b stderr</span>" }
            set errors [Query! $item(programName) has error /err/ with info /info/]
            foreach e $errors {
                append outputHtml "<pre style='margin: 0.25em 0 0 1em; padding: 0.25em 0.5em; font-size: 0.85em; white-space: pre-wrap; border-left: 3px solid #c00; color: #c00'>[htmlEscape $e(err)]</pre>"
            }
            set errCount [llength $errors]
            set displayName [regsub {^builtin-programs/} $item(programName) ""]
            set nameStyle [expr {$errCount > 0 ? "style='color: #c00'" : ""}]
            if {$errCount > 0} { append outputSuffix " (<span style='font-size: 0.75em; color: #c00'>${errCount} errors</span>)" }
            set summaryStyle [expr {$outputHtml eq "" ? "style='list-style: none'" : ""}]
            lappend returnList [subst {
                <li id="program-[string map {{ } -} $item(programName)]"><details>
                  <summary $summaryStyle><span $nameStyle>$displayName</span> $outputSuffix</summary>
                  $outputHtml
                </details></li>
            }]
        }
        lappend returnList "</ul>"
        lappend returnList "</details>"
        join $returnList
    }

    fn emitHtmlForPrograms {programs} {
        set vp [list]; # builtin programs
        set cp [list]; # local programs
        set wp [list]; # web programs
        set rp [list]; # real programs

        foreach match $programs {
            set programName [dict get $match programName]
            switch -glob $programName {
                "builtin-programs/*" { lappend vp $match }
                "/home/*" { lappend cp $match }
                "/Users/*" { lappend cp $match }
                "web-program-*" { lappend wp $match }
                default { lappend rp $match }
            }
        }
        lappend vp {programName "sysmon.c"}

        return [join [list \
            [emitHtmlForProgramList $vp "builtin-programs"] \
            [emitHtmlForProgramList $cp "local-programs"] \
            [emitHtmlForProgramList $rp "real-programs"] \
            [emitHtmlForProgramList $wp "web-programs"] ]]
    }

    html [subst {
        <html>
        <head>
            <title>Folk: Running programs</title>
            <link rel="stylesheet" href="/style.css">
            <style>
                body {
                    font-family: math;
                }
                summary {
                    font-family: monospace;
                }
                details ul {
                    margin-block: 0;
                    list-style-type: none;
                }
            </style>
            <script src="/lib/folk.js"></script>
            <script src="/vendor/idiomorph.js"></script>
            <script>
              const folk = new FolkWS();
            </script>
        </head>
        <body>
        [QueryOne! the web navigation HTML is /./]
        [HtmlWhen the collected results for [list /programName/ has program code /programCode/] are /programs/ {
            emitHtmlForPrograms $programs

        } -beforeAttributeUpdated {(attributeName, node, mutationType) => {
            if (attributeName === "open") { return false; }
        }}]
        </body>
        </html>
    }]
}