diff --git a/gamewiki/parser.py b/gamewiki/parser.py index b011d4c..815aa55 100644 --- a/gamewiki/parser.py +++ b/gamewiki/parser.py @@ -1,6 +1,12 @@ import glob +import re +from typing import TypeVar, Iterator + +T = TypeVar("T") + class WikiArticle: + '''Abstract class that defines an article in the wiki''' def __init__(self, filename): def tags(content): for line in content: @@ -24,12 +30,19 @@ class WikiArticle: self.title = title(content) self.tags = tags(content) self.filename = filename - + + def enrich(self, articles: Iterator): + raise NotImplementedError() + def __repr__(self): return f'{type(self).__name__}({self.title}, {self.filename}, {self.tags})' -class ContentArticle(WikiArticle): pass +class ContentArticle(WikiArticle): + '''The articles we wrote''' + pass + class MetaPage(WikiArticle): + '''Wiki article containing code that must be generated by this program''' def __init__(self, filename): self.header = '** Pages in this category' super().__init__(filename) @@ -41,14 +54,15 @@ class MetaPage(WikiArticle): if len(correct_section) != 1: raise Exception(f'Invalid meta section in {filename}') - def replace_content(self, wikiarticles): + def enrich(self, linked_articles: Iterator[WikiArticle]): + '''Generator that returns content that will end up in the document before html conversion''' content = map(identity, self.content) def rep(): for line in content: if line == self.header: break else: yield line yield self.header - for w in wikiarticles: + for w in linked_articles: yield f'- [[../{w.filename}][{w.title}]]' return rep() @@ -64,26 +78,47 @@ def files(): def metafiles(): return glob.glob('meta/*.org') - -def invert_map(map_: list[WikiArticle]): +def invert_map(map_: list[ContentArticle]): '''from {a: [1, 2], b: [2, 3]} to {1: [a], 2: [a, b], 3: [b]}''' keys = set(i for e in map_ for i in e.tags) - res = dict() + res: dict[str, list[WikiArticle]] = dict() for k in keys: res[k] = res.get(k, []) + [w for w in map_ if k in w.tags] return res -def write_meta_page(m: MetaPage, content: list[str]): +def links(article: ContentArticle): + def haslink(line): + return re.findall(r'\[\[(.+?)\]\]', line) + + def yield_links(line): + i = 0 + while i < len(line)-1: + sub = line[i:] + if sub.startswith('[[./') and ']]' in sub and '.org' in sub: # org link to one org file + ridx = sub.index('.org') + yield sub[:ridx+4] + i += sub.index(']]') + i += 1 + + for line in article.content: + if haslink(line): + yield from yield_links(line) + + +def writetodisk(m: WikiArticle, content: list[str]): with open(m.filename, 'w') as f: f.writelines(map(lambda l: l+'\n', content)) if __name__ == '__main__': - files = [ContentArticle(f) for f in files()] - meta = [MetaPage(f) for f in metafiles()] - meta = {m.meta: m for m in meta} - print(meta) - tags = invert_map(files) + files_ = [ContentArticle(f) for f in files()] + meta_ = [MetaPage(f) for f in metafiles()] + meta = {m.meta: m for m in meta_} + + tags = invert_map(files_) for t, articles in tags.items(): if t in meta: - newcontent = meta[t].replace_content(articles) - write_meta_page(meta[t], newcontent) + newcontent = meta[t].enrich(articles) + writetodisk(meta[t], newcontent) + + for a in files_: + print(a, links(a))