Coverage for liitos/description_lists.py: 100.00%
36 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-08-31 13:07:35 +00:00
« prev ^ index » next coverage.py v7.10.6, created at 2025-08-31 13:07:35 +00:00
1"""Apply any option command to subsequent description environment.
3Implementation Note: The empty string marker is used to indicate absence of option command.
4"""
6from collections.abc import Iterable
7from enum import Enum
8from typing import Union
10from liitos import log
12Modus = Enum('Modus', 'COPY OPTION')
13ModusOption = tuple[Modus, str]
15NO_OPTION: str = ''
17OPTION_START_TRIGGER_STARTSWITH = r'\option['
18DESCRIPTION_START_TRIGGER_STARTSWITH = r'\begin{description}'
21def filter_seek_option(line: str, slot: int, modus: Modus, opt: str, outgoing: list[str]) -> ModusOption:
22 r"""Filter line, seek for an option command, and return updated mnodus, opt pair.
24 Examples:
26 >>> filtered = []
27 >>> m, opt = filter_seek_option(r'\option[]', 0, Modus.COPY, NO_OPTION, filtered)
28 >>> assert not filtered
29 >>> assert m == Modus.OPTION
30 >>> assert opt == '[]'
32 >>> filtered = []
33 >>> m, opt = filter_seek_option('foo', 0, Modus.COPY, NO_OPTION, filtered)
34 >>> assert filtered == ['foo']
35 >>> assert m == Modus.COPY
36 >>> assert opt == NO_OPTION
38 >>> filtered = []
39 >>> m, opt = filter_seek_option(r'\option[foo=bar]', 0, Modus.COPY, NO_OPTION, filtered)
40 >>> assert not filtered
41 >>> assert m == Modus.OPTION
42 >>> assert opt == '[foo=bar]'
43 """
44 if line.startswith(OPTION_START_TRIGGER_STARTSWITH):
45 log.info(f'trigger an option mod for the next description environment at line #{slot + 1}|{line}')
46 opt = '[' + line.split(OPTION_START_TRIGGER_STARTSWITH, 1)[1].strip()
47 modus = Modus.OPTION
48 log.info(f' -> parsed option as ({opt})')
49 else:
50 outgoing.append(line)
52 return modus, opt
55def filter_seek_description(line: str, slot: int, modus: Modus, opt: str, outgoing: list[str]) -> ModusOption:
56 r"""Filter line, seek for a description, add options if applicable, and return updated mnodus, option pair.
58 Examples:
60 >>> filtered = []
61 >>> m, opt = filter_seek_description('quux', 0, Modus.OPTION, '[foo=bar]', filtered)
62 >>> assert filtered == ['quux']
63 >>> assert m == Modus.OPTION
64 >>> assert opt == '[foo=bar]'
66 >>> filtered = []
67 >>> m, opt = filter_seek_description(r'\begin{description}', 0, Modus.OPTION, NO_OPTION, filtered)
68 >>> assert filtered == [r'\begin{description}']
69 >>> assert m == Modus.COPY
70 >>> assert opt == NO_OPTION
72 >>> filtered = []
73 >>> m, opt = filter_seek_description(r'\begin{description}', 0, Modus.OPTION, '[foo=bar]', filtered)
74 >>> assert filtered == [r'\begin{description}[foo=bar]']
75 >>> assert m == Modus.COPY
76 >>> assert opt == NO_OPTION
77 """
78 if line.startswith(DESCRIPTION_START_TRIGGER_STARTSWITH):
79 if opt != NO_OPTION:
80 log.info(f'- found the option target start at line #{slot + 1}|{line}')
81 outgoing.append(f'{DESCRIPTION_START_TRIGGER_STARTSWITH}{opt}')
82 else:
83 outgoing.append(line)
84 modus = Modus.COPY
85 opt = NO_OPTION
86 else:
87 outgoing.append(line)
89 return modus, opt
92def options(incoming: Iterable[str], lookup: Union[dict[str, str], None] = None) -> list[str]:
93 r"""Later alligator. \option[style=multiline,leftmargin=6em]
95 Examples:
97 >>> in_opts = '[style=multiline,leftmargin=6em]'
98 >>> opt_line = f'\\option{in_opts}'
99 >>> beg_desc = '\\begin{description}'
100 >>> lines_in = ['a', '', opt_line, '', beg_desc, 'whatever']
101 >>> lines_in
102 ['a', '', '\\option[style=multiline,leftmargin=6em]', '', '\\begin{description}', 'whatever']
103 >>> processed = options(lines_in)
104 >>> processed
105 ['a', '', '', '\\begin{description}[style=multiline,leftmargin=6em]', 'whatever']
106 """
107 outgoing: list[str] = []
108 modus = Modus.COPY
109 opt = NO_OPTION
110 for slot, line in enumerate(incoming):
111 if modus == Modus.COPY:
112 modus, opt = filter_seek_option(line, slot, modus, opt, outgoing)
113 else: # if modus == Modus.OPTION:
114 modus, opt = filter_seek_description(line, slot, modus, opt, outgoing)
116 return outgoing