#!/usr/bin/python3 # # gmi2html - convert Gemtext to HTML # # SPDX-FileCopyrightText: 2023 Daniel Kalak # SPDX-License-Identifier: GPL-3.0-or-later import sys # This aims to replace an enum. ( PRE_TOGGLE, PRE, H1, H2, H3, LIST, LINK, QUOTE_TEXT, QUOTE_GAP, BODY_TEXT, BODY_GAP ) = [i for i in range(11)] QUOTE = (QUOTE_TEXT, QUOTE_GAP) BODY = (BODY_TEXT, BODY_GAP) PRE_TOGGLE_PREFIX = "```" # ("", BODY) must come last because "" would match prematurely in categorize(). # Note that QUOTE and BODY don't need brackets because they already are tuples. PREFIXES = [ (PRE_TOGGLE_PREFIX, [PRE_TOGGLE]), ("# ", [H1]), ("## ", [H2]), ("### ", [H3]), ("* ", [LIST]), ("=>", [LINK]), (">", QUOTE), ("", BODY) ] # ("&", "&") must come first so that "&" isn't replaced in the other # replacements in escape(). ESCAPES = [ ("&", "&"), ("<", "<"), (">", ">"), ("\"", """), ("\'", "'") ] def escape(s): for escape in ESCAPES: s = s.replace(escape[0], escape[1]) return s def categorize(line, pre): if pre and not line.startswith(PRE_TOGGLE_PREFIX): return (PRE, escape(line[:-1])) # The loop only returns if PREFIXES contains ("", _). for prefix, categories in PREFIXES: if line.startswith(prefix): line = line[len(prefix):] # line.isspace() works on empty lines because line[-1] is still "\n". # categories[-1] works independently of whether categories has 1 or 2 # elements. category = categories[0] if not line.isspace() else categories[-1] return (category, escape(line[:-1])) def close_tags(prev, curr, pre): # (prev == PRE) instead of (pre) doesn't work because there could be 2 # adjacent PRE_TOGGLE lines with no PRE lines inbetween. if pre and curr == PRE_TOGGLE: sys.stdout.write("\n") elif prev == LIST and curr != LIST: sys.stdout.write("\n") elif prev in QUOTE and curr not in QUOTE: sys.stdout.write("\n") def open_tags(prev, curr, pre): # (prev != PRE) instead of (not pre) doesn't work because there could be 2 # adjacent PRE_TOGGLE lines after a PRE line with no PRE lines inbetween. if not pre and curr == PRE_TOGGLE: sys.stdout.write("
\n")
  elif prev != LIST and curr == LIST:
    sys.stdout.write("