#! /usr/bin/env python3 # Copyright 2021 Steinar Knutsen # # Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); You may # not use this work except in compliance with the Licence. You may obtain a copy # of the Licence at: # # https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 # # Unless required by applicable law or agreed to in writing, software # distributed under the Licence is distributed on an "AS IS" basis, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # Licence for the specific language governing permissions and limitations under # the Licence. import sys, getopt HELP_TEXT = """litxt2html [-h] [-s] -c add a small CSS and Javascript snippet to make for adjustable column width -h print this text -s strip the monospace markers from the generated HTML Convert limited ITXT to HTML. Only monospace blocks and unindented paragraphs of text are accepted as input.""" TITLE_MISSING = "Mandatory HTML document title missing, use -h for synopsis." HEAD = """<!DOCTYPE html> <html> <head> """ BODY = "</head><body>\n" FOOTER = "</body></html>\n" TITLE_TEMPLATE = "<title>{title}" MONO = "--------------------------------------------------------------------------------" MONO_START = "
\n"
MONO_END= "
\n" PARA_START = "

\n" PARA_END = "

\n" STYLES = """ """ BUTTONS = """
n% n%
""" quote_table = { '&': "&", '<': "<", '>': ">" } def cook(line): unwritten = i = 0 buffer = [] while i < len(line): subst = quote_table.get(line[i]) if subst != None: if unwritten != i: buffer.append(line[unwritten:i]) unwritten = i + 1 buffer.append(subst) i += 1 if unwritten < len(line): buffer.append(line[unwritten:]) return "".join(buffer) def ismonomarker(line): return line.rstrip() == MONO def write_line(destination, line, stripped_output): if not stripped_output: destination.write(cook(line)) return if ismonomarker(line): return destination.write(cook(line)) def start_para(destination, para_started): if not para_started: destination.write(PARA_START) return True def end_para(destination, para_started): if para_started: destination.write(PARA_END) return False def main(source, destination, title, stripped_output, widthbuttons): in_mono = False para_started = False destination.write(HEAD) if widthbuttons: destination.write(STYLES) destination.write(TITLE_TEMPLATE.format(title=cook(title))) destination.write(BODY) if widthbuttons: destination.write(BUTTONS) for line in source: if in_mono: write_line(destination, line, stripped_output) if ismonomarker(line): in_mono = False para_started = False destination.write(MONO_END) else: if len(line.strip()) == 0: para_started = end_para(destination, para_started) continue elif ismonomarker(line): para_started = end_para(destination, para_started) in_mono = True destination.write(MONO_START) write_line(destination, line, stripped_output) else: if line[0].isspace(): raise ValueError("Indents outside monospace not supported.") para_started = start_para(destination, para_started) write_line(destination, line, stripped_output) if in_mono: raise ValueError("Unterminated monospace block.") para_started = end_para(destination, para_started) destination.write(FOOTER) if __name__ == "__main__": stripped_output = False widthbuttons = False options, arguments = getopt.gnu_getopt(sys.argv[1:], "chs") for name, value in options: if name == "-c": widthbuttons = True elif name == "-h": print(HELP_TEXT) sys.exit(0) if name == "-s": stripped_output = True if len(arguments) != 1: print(TITLE_MISSING, file=sys.stderr) sys.exit(1) main(sys.stdin, sys.stdout, arguments[0], stripped_output, widthbuttons)