package require Tcl 8.6
package require sqlite3
proc main repo {
set db page-db
sqlite3 $db :memory:
$db eval {
CREATE TABLE pages(
name TEXT PRIMARY KEY,
h1 TEXT,
contents TEXT
);
CREATE TABLE tags(
page TEXT,
tag TEXT,
FOREIGN KEY (page) REFERENCES pages(name),
PRIMARY KEY (page, tag)
);
}
$db transaction {
foreach {name h1 contents} [pages-with-contents $repo] {
$db eval {
INSERT INTO pages(name, h1, contents)
VALUES (:name, :h1, :contents);
}
foreach tag [page-tags $contents] {
$db eval {
INSERT INTO tags(page, tag)
VALUES (:name, :tag);
}
}
}
}
set attrs {}
set attrNames {name h1}
set grouped {}
set prevTag {}
$db eval {
SELECT
tags.tag,
h1,
name
FROM tags
INNER JOIN pages
ON tags.page = pages.name
INNER JOIN (
SELECT
tag,
(-count(page) +
CASE WHEN tag = 'redirect' THEN 10000 ELSE 0 END)
AS tag_score
FROM tags
INNER JOIN pages
ON tags.page = pages.name
GROUP BY tag
) AS scores
ON tags.tag = scores.tag
ORDER BY
tag_score,
tags.tag,
h1,
name
COLLATE NOCASE ASC;
} row {
if {$row(tag) ne $prevTag} {
if {$prevTag ne {}} {
lappend grouped $prevTag {*}[lmap attr $attrNames {
dict get $attrs $attr
}]
set attrs {}
}
set prevTag $row(tag)
}
foreach attr $attrNames {
dict lappend attrs $attr $row($attr)
}
}
lappend grouped $prevTag {*}[lmap attr $attrNames {
dict get $attrs $attr
}]
puts [tag-page $grouped]
}
proc pages-with-contents repo {
set pages {}
foreach name [split [fossil wiki ls $repo] \n] {
set contents [fossil wiki export $name]
set h1 {}
regexp {^#\s*([^\n]+)\n} $contents _ h1
lappend pages $name $h1 $contents
}
return $pages
}
proc fossil args {
exec -ignorestderr fossil {*}$args
}
proc page-tags text {
if {[regexp -nocase {\n\[Tags\]\([^)]+\): ([^\.\n]+)} $text _ tags]} {
return [lmap x [split $tags ,] {string trim $x}]
} else {
return {}
}
}
proc tag-page sorted {
set lines [list]
lappend lines {# Pages by tag} {## Contents}
lappend lines {## Tags} [markdown-list $sorted ###]
return [join $lines \n]
}
proc markdown-list {grouped prefix} {
set markdown [list]
set esc {
[ \\[
] \\]
( \\(
) \\)
}
foreach {tag pages h1s} $grouped {
set section [list "$prefix $tag"]
foreach page $pages h1 $h1s {
set text $page
if {$h1 ne {}} {
set text $h1
}
set target [string map [list \
{ } + \
? %3f \
{*}$esc \
] $page]
set link \[[string map $esc $text]\](/wiki/$target)
lappend section "* $link"
}
lappend markdown [join $section \n]
}
join $markdown \n\n
}
if {[info exists argv0] && ([file tail [info script]] eq [file tail $argv0])} {
puts [main {*}$argv]
}