#! /usr/bin/env python3
# Copyright 2019, 2020 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 = """itxt2html [-h] [-s]
\n'
PADDING = '
\n'
PARA_END = "
\n"
BREAK_MARKER = "_|"
BREAK = "
\n"
quote_table = {
'&': "&",
'<': "<",
'>': ">"
}
def get_indent(line):
indent = 0
for c in line:
if c == SPACE:
indent += 1
else:
break
if (indent % INDENT) != 0:
raise Exception("Indent not multiplum of INDENT constant.")
return indent >> 2
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, in_mono, stripped_output):
if not stripped_output:
destination.write(cook(line))
return
if ismonomarker(line):
return
if in_mono:
destination.write(cook(line))
else:
if line.rstrip().endswith(BREAK_MARKER):
stripped = line.rstrip()[:-len(BREAK_MARKER)] + "\n"
destination.write(cook(stripped))
else:
destination.write(cook(line))
def main(source, destination, title, stripped_output):
previndent = currindent = 0
in_mono = False
previous_line_empty = False
suppress_vertical_padding = False
padstack = []
prevline = ""
destination.write(HEAD)
destination.write(TITLE_TEMPLATE % cook(title))
destination.write(BODY)
for line in source:
if in_mono:
write_line(destination, line, in_mono, stripped_output)
if ismonomarker(line):
in_mono = False
destination.write(END_MONO)
suppress_vertical_padding = True
prevline = line
else:
if len(line.strip()) == 0:
previous_line_empty = True
while len(padstack) > 0 and padstack[-1] == PADDING:
padstack.pop()
destination.write(PARA_END)
prevline = line
continue
elif ismonomarker(line):
in_mono = True
for p in padstack:
destination.write(PARA_END)
del padstack[:]
destination.write(START_MONO)
previndent = 0
write_line(destination, line, in_mono, stripped_output)
prevline = line
continue
currindent = get_indent(line)
if previndent > currindent:
i = 0
while i < (previndent - currindent):
destination.write(PARA_END)
removed = padstack.pop()
if removed == SHIFT_RIGHT:
i += 1
# not really needed to check for vertical padding suppression
# here, but do it for maintanability
if previous_line_empty and not suppress_vertical_padding:
destination.write(PADDING)
padstack.append(PADDING)
elif currindent > previndent:
for i in range(currindent - previndent):
destination.write(SHIFT_RIGHT)
padstack.append(SHIFT_RIGHT)
if previous_line_empty and not suppress_vertical_padding:
destination.write(PADDING)
padstack.append(PADDING)
elif previous_line_empty and not suppress_vertical_padding:
destination.write(PADDING)
padstack.append(PADDING)
elif prevline.rstrip().endswith(BREAK_MARKER):
destination.write(BREAK)
previous_line_empty = False
prevline = line
previndent = currindent
suppress_vertical_padding = False
write_line(destination, line, in_mono, stripped_output)
for p in padstack:
destination.write(PARA_END)
destination.write(FOOTER)
if __name__ == "__main__":
stripped_output = False
options, arguments = getopt.gnu_getopt(sys.argv[1:], "hs")
for name, value in options:
if name == "-h":
print(help_text)
sys.exit(0)
if name == "-s":
stripped_output = True
main(sys.stdin, sys.stdout, arguments[0], stripped_output)