Artifact cf9edca8d8d0a7fa82d6bdc91381d2541c949236dc978a84721fd230b3ecc57b:


#! /usr/bin/env tclsh
# Generate a tag page for a Fossil wiki.
# Copyright (c) 2020 D. Bohdan.
# License: MIT.
# Typical usage in an open Fossil repository:
# $ ./tag-page.tcl . 'Special: Pages by tag'

package require Tcl 8.6

proc page-tags text {
    if {[regexp -nocase {\n\[Tags\]\([^)]+\): ([^\.\n]+)} $text _ tags]} {
        return [lmap x [split $tags ,] {string trim $x}]
    } else {
        return {}
    }
}


proc group-by-tag pages {
    set grouped {}

    foreach {name contents} $pages {
        if {$contents in {{} \n}} continue

        foreach tag [page-tags $contents] {
            dict lappend grouped $tag $name
        }
    }

    return $grouped
}


proc entities text {
    return [string map {
        & &amp
        < &lt;
        > &gt;
        \" &quot;
        ' &#039;
    } $text]
}


proc markdown-list {grouped prefix} {
    set markdown {}

    foreach {tag pages} $grouped {
        set section [list "$prefix [entities $tag]"]

        foreach page $pages {
            set link [expr {
                [regexp {[\(\)\[\]<>"'&]} $page]
                ? "<a href=\"/wiki?name=[entities $page]\">[entities $page]</a>"
                : "\[$page\](wiki:$page)"
            }]
            lappend section "* $link"
        }

        lappend markdown [join $section \n]
    }

    join $markdown \n\n
}


proc fossil args {
    exec -ignorestderr fossil {*}$args
}


proc update-page {name contents} {
    set old [fossil wiki export $name]
    if {$contents eq $old} return
    fossil wiki commit $name << $contents
}


proc tag-page repo {
    set lines {}

    lappend lines {# Pages by tag} {## Contents} {## Tags}

    set pages {}
    foreach name [split [fossil wiki ls $repo] \n] {
        lappend pages $name [fossil wiki export $name]
    }

    set grouped [group-by-tag $pages]
    set sorted [lsort -stride 2 -index 0 -nocase $grouped]
    lappend lines [markdown-list $sorted ###]

    return [join $lines \n]
}


proc main {repo {page-name {}}} {
    set contents [tag-page $repo]
    if {${page-name} in {{} -}} {
        puts $contents
    } else {
        update-page ${page-name} $contents
    }
}


# If this is the main script...
if {[info exists argv0] && ([file tail [info script]] eq [file tail $argv0])} {
    puts [main {*}$argv]
}