import std/[os, unicode, critbits, options, strformat]
from std/strutils import startsWith, Whitespace, splitLines
from std/strbasics import strip
const
WhitespaceUC = toRunes("_\t\n\x0b\x0c\r\x1c\x1d\x1e\x1f \x85\xa0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000")
Warning = "<!--- DO NOT EDIT: This file is automatically generated by `directory.nim` -->\n"
Header = "# The Algorithms — Nim: Directory Hierarchy\n"
IgnoreSubDirs = ["scripts"]
type
Directory = CritBitTree[CritBitTree[string]]
func canonicalize(s: string): string =
var isFirst = true
for word in unicode.split(s, WhitespaceUC):
if word.len > 0:
if isFirst: isFirst = false
else: result.add(' ')
result.add(word.title())
proc extractTitle(s, fpath: string): Option[string] =
var s = s.strip()
if s.startsWith("##"):
s.strip(trailing = false, chars = Whitespace + {'
if s.len > 0: some(s)
else: none(string)
else:
stderr.writeLine(&"\u26A0: \"{fpath}\". First line is not a doc comment! Deriving title from a file name.")
none(string)
proc readLn(fpath: string): Option[string] =
var f: File = nil
var s: string
if open(f, fpath):
try:
if not readLine(f, s): none(string)
else: s.extractTitle(fpath)
except CatchableError: none(string)
finally: close(f)
else: none(string)
proc collectDirectory(dir = ""): Directory =
for (pc, path) in walkDir(dir, relative = true):
if pc == pcDir and path[0] != '.' and path notin IgnoreSubDirs:
var categoryDir: CritBitTree[string]
for (pc, fname) in walkDir(path, relative = true):
if pc == pcFile and fname[0] != '.':
let (_, name, ext) = splitFile(fname)
let fpath = path / fname
if ext == ".nim":
let title = readLn(fpath).get(name.changeFileExt("").canonicalize())
categoryDir[title] = fname
if categoryDir.len > 0:
result[path] = categoryDir
when isMainModule:
let directory = collectDirectory(getCurrentDir())
if directory.len > 0:
echo Warning, "\n", Header
for (categoryDir, contents) in directory.pairs():
if contents.len > 0:
echo "## ", categoryDir.canonicalize()
for (title, fname) in contents.pairs():
echo &" * [{title}]({categoryDir}/{fname})"
echo ""