From 3ac0b2c73815b5b896342aa992e0ccfae021db5b Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Tue, 23 Apr 2019 16:20:23 -0700 Subject: [PATCH] Improve index sorting options --- lexipython/build.py | 120 ++++++++++++++++++++++++----- lexipython/resources/contents.html | 64 ++++++++++----- lexipython/resources/lexicon.cfg | 18 +++-- 3 files changed, 155 insertions(+), 47 deletions(-) diff --git a/lexipython/build.py b/lexipython/build.py index 75903d0..a8ea3f5 100644 --- a/lexipython/build.py +++ b/lexipython/build.py @@ -28,11 +28,21 @@ class LexiconPage: total_kwargs = {**self.kwargs, **kwargs} return self.skeleton.format(**total_kwargs) -def build_contents_page(page, articles, index_list): +def article_matches_index(index_type, pattern, article): + if index_type == "char": + return utils.titlesort(article.title)[0].upper() in pattern.upper() + if index_type == "prefix": + return article.title.startswith(pattern) + if index_type == "etc": + return True + raise ValueError("Unknown index type: '{}'".format(index_type)) + +def build_contents_page(config, page, articles): """ Builds the full HTML of the contents page. """ content = "
" + # Head the contents page with counts of written and phantom articles phantom_count = len([article for article in articles if article.player is None]) if phantom_count == 0: @@ -40,32 +50,68 @@ def build_contents_page(page, articles, index_list): else: content += "

There are {0} entries, {1} written and {2} phantom.

\n".format( len(articles), len(articles) - phantom_count, phantom_count) + # Prepare article links link_by_title = {article.title : "{0}".format( article.title, article.title_filesafe, " class=\"phantom\"" if article.player is None else "") for article in articles} - # Write the articles in alphabetical order - content += utils.load_resource("contents.html") - content += "
\n
    \n" - indices = index_list.split("\n") - alphabetical_order = sorted( + + # Determine index order + indices = config['INDEX_LIST'].split("\n") + index_by_pri = {} + index_list_order = [] + for index in indices: + match = re.match(r"([^[:]+)(\[([-\d]+)\])?:(.+)", index) + index_type = match.group(1) + pattern = match.group(4) + try: + pri_s = match.group(3) + pri = int(pri_s) if pri_s else 0 + except: + raise TypeError("Could not parse index pri '{}' in '{}'".format(pri_s, index)) + if pri not in index_by_pri: + index_by_pri[pri] = [] + index_by_pri[pri].append((index_type, pattern)) + index_list_order.append(pattern) + + # Assign articles to indices + articles_by_index = {pattern: [] for pattern in index_list_order} + titlesort_order = sorted( articles, key=lambda a: utils.titlesort(a.title)) - check_off = list(alphabetical_order) - for index_str in indices: - content += "

    {0}

    \n".format(index_str) - for article in alphabetical_order: - if (utils.titlesort(article.title)[0].upper() in index_str): - check_off.remove(article) - content += "
  • {}
  • \n".format(link_by_title[article.title]) - if len(check_off) > 0: - content += "

    &c.

    \n" - for article in check_off: + for article in titlesort_order: + # Find the first index that matches + matched = False + for pri, indices in sorted(index_by_pri.items(), reverse=True): + for index_type, pattern in indices: + # Try to match the index + if article_matches_index(index_type, pattern, article): + articles_by_index[pattern].append(article) + matched = True + # Break out once a match is found + if matched: + break + if matched: + break + if not matched: + raise KeyError("No index matched article '{}'".format(article.title)) + + # Write index order div + content += utils.load_resource("contents.html") + content += "
    \n
      \n".format( + "block" if config["DEFAULT_SORT"] == "index" else "none") + for pattern in index_list_order: + # Write the index header + content += "

      {0}

      \n".format(pattern) + # Write all matches articles + for article in articles_by_index[pattern]: content += "
    • {}
    • \n".format(link_by_title[article.title]) content += "
    \n
    \n" - # Write the articles in turn order - content += "
    \n
      \n" + + # Write turn order div + content += "
      \n
        \n".format( + "block" if config["DEFAULT_SORT"] == "turn" else "none") turn_numbers = [article.turn for article in articles if article.player is not None] first_turn, last_turn = min(turn_numbers), max(turn_numbers) turn_order = sorted( @@ -83,6 +129,31 @@ def build_contents_page(page, articles, index_list): for article in check_off: content += "
      • {}
      • \n".format(link_by_title[article.title]) content += "
      \n
      \n" + + # Write by-player div + content += "
      \n
        \n".format( + "block" if config["DEFAULT_SORT"] == "player" else "none") + articles_by_player = {} + extant_phantoms = False + for article in turn_order: + if article.player is not None: + if article.player not in articles_by_player: + articles_by_player[article.player] = [] + articles_by_player[article.player].append(article) + else: + extant_phantoms = True + for player, player_articles in sorted(articles_by_player.items()): + content += "

        {0}

        \n".format(player) + for article in player_articles: + content += "
      • {}
      • \n".format(link_by_title[article.title]) + if extant_phantoms: + content += "

        Unwritten

        \n" + for article in titlesort_order: + if article.player is None: + content += "
      • {}
      • \n".format(link_by_title[article.title]) + content += "
      \n
      \n" + + content += "
    \n" # Fill in the page skeleton return page.format(title="Index", content=content) @@ -477,6 +548,15 @@ def latex_from_directory(directory): return content +def parse_sort_type(sort): + if sort in "?byindex": + return "?byindex" + if sort in "?byturn": + return "?byturn" + if sort in "?byplayer": + return "?byplayer" + return "" + def build_all(path_prefix, lexicon_name): """ Builds all browsable articles and pages in the Lexicon. @@ -490,7 +570,7 @@ def build_all(path_prefix, lexicon_name): lexicon=config["LEXICON_TITLE"], logo=config["LOGO_FILENAME"], prompt=config["PROMPT"], - sort=config["DEFAULT_SORT"]) + sort=parse_sort_type(config["DEFAULT_SORT"])) # Parse the written articles articles = LexiconArticle.parse_from_directory(os.path.join(lex_path, "src")) # Once they've been populated, the articles list has the titles of all articles @@ -528,7 +608,7 @@ def build_all(path_prefix, lexicon_name): # Write default pages print("Writing default pages...") with open(pathto("contents", "index.html"), "w", encoding="utf-8") as f: - f.write(build_contents_page(page, articles, config["INDEX_LIST"])) + f.write(build_contents_page(config, page, articles)) print(" Wrote Contents") with open(pathto("rules", "index.html"), "w", encoding="utf-8") as f: f.write(build_rules_page(page)) diff --git a/lexipython/resources/contents.html b/lexipython/resources/contents.html index a7c2543..eb3b850 100644 --- a/lexipython/resources/contents.html +++ b/lexipython/resources/contents.html @@ -1,28 +1,54 @@ diff --git a/lexipython/resources/lexicon.cfg b/lexipython/resources/lexicon.cfg index 8cbe4f0..66d0d35 100644 --- a/lexipython/resources/lexicon.cfg +++ b/lexipython/resources/lexicon.cfg @@ -24,16 +24,18 @@ logo.png

    Put session information here, like the index grouping and turn count, where to send completed entries, index assignments, turn schedule, and so on.

    <<>>INDEX_LIST>>> char:ABC char:DEF @@ -47,7 +49,7 @@ etc:&c. <<>>DEFAULT_SORT>>> index <<