Coverage for liitos / description_lists.py: 95.56%
35 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 22:54:48 +00:00
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 22:54:48 +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
9from liitos import log
11Modus = Enum('Modus', 'COPY OPTION')
12ModusOption = tuple[Modus, str]
14NO_OPTION: str = ''
16OPTION_START_TRIGGER_STARTSWITH = r'\option['
17DESCRIPTION_START_TRIGGER_STARTSWITH = r'\begin{description}'
20def filter_seek_option(line: str, slot: int, modus: Modus, opt: str, outgoing: list[str]) -> ModusOption:
21 r"""Filter line, seek for an option command, and return updated mnodus, opt pair.
23 Examples:
25 >>> filtered = []
26 >>> m, opt = filter_seek_option(r'\option[]', 0, Modus.COPY, NO_OPTION, filtered)
27 >>> assert not filtered
28 >>> assert m == Modus.OPTION
29 >>> assert opt == '[]'
31 >>> filtered = []
32 >>> m, opt = filter_seek_option('foo', 0, Modus.COPY, NO_OPTION, filtered)
33 >>> assert filtered == ['foo']
34 >>> assert m == Modus.COPY
35 >>> assert opt == NO_OPTION
37 >>> filtered = []
38 >>> m, opt = filter_seek_option(r'\option[foo=bar]', 0, Modus.COPY, NO_OPTION, filtered)
39 >>> assert not filtered
40 >>> assert m == Modus.OPTION
41 >>> assert opt == '[foo=bar]'
42 """
43 if line.startswith(OPTION_START_TRIGGER_STARTSWITH):
44 log.info(f'trigger an option mod for the next description environment at line #{slot + 1}|{line}')
45 opt = '[' + line.split(OPTION_START_TRIGGER_STARTSWITH, 1)[1].strip()
46 modus = Modus.OPTION
47 log.info(f' -> parsed option as ({opt})')
48 else:
49 outgoing.append(line)
51 return modus, opt
54def filter_seek_description(line: str, slot: int, modus: Modus, opt: str, outgoing: list[str]) -> ModusOption:
55 r"""Filter line, seek for a description, add options if applicable, and return updated mnodus, option pair.
57 Examples:
59 >>> filtered = []
60 >>> m, opt = filter_seek_description('quux', 0, Modus.OPTION, '[foo=bar]', filtered)
61 >>> assert filtered == ['quux']
62 >>> assert m == Modus.OPTION
63 >>> assert opt == '[foo=bar]'
65 >>> filtered = []
66 >>> m, opt = filter_seek_description(r'\begin{description}', 0, Modus.OPTION, NO_OPTION, filtered)
67 >>> assert filtered == [r'\begin{description}']
68 >>> assert m == Modus.COPY
69 >>> assert opt == NO_OPTION
71 >>> filtered = []
72 >>> m, opt = filter_seek_description(r'\begin{description}', 0, Modus.OPTION, '[foo=bar]', filtered)
73 >>> assert filtered == [r'\begin{description}[foo=bar]']
74 >>> assert m == Modus.COPY
75 >>> assert opt == NO_OPTION
76 """
77 if line.startswith(DESCRIPTION_START_TRIGGER_STARTSWITH):
78 if opt != NO_OPTION: 78 ↛ 82line 78 didn't jump to line 82 because the condition on line 78 was always true
79 log.info(f'- found the option target start at line #{slot + 1}|{line}')
80 outgoing.append(f'{DESCRIPTION_START_TRIGGER_STARTSWITH}{opt}')
81 else:
82 outgoing.append(line)
83 modus = Modus.COPY
84 opt = NO_OPTION
85 else:
86 outgoing.append(line)
88 return modus, opt
91def options(incoming: Iterable[str], lookup: dict[str, str] | None = None) -> list[str]:
92 r"""Later alligator. \option[style=multiline,leftmargin=6em]
94 Examples:
96 >>> in_opts = '[style=multiline,leftmargin=6em]'
97 >>> opt_line = f'\\option{in_opts}'
98 >>> beg_desc = '\\begin{description}'
99 >>> lines_in = ['a', '', opt_line, '', beg_desc, 'whatever']
100 >>> lines_in
101 ['a', '', '\\option[style=multiline,leftmargin=6em]', '', '\\begin{description}', 'whatever']
102 >>> processed = options(lines_in)
103 >>> processed
104 ['a', '', '', '\\begin{description}[style=multiline,leftmargin=6em]', 'whatever']
105 """
106 outgoing: list[str] = []
107 modus = Modus.COPY
108 opt = NO_OPTION
109 for slot, line in enumerate(incoming):
110 if modus == Modus.COPY:
111 modus, opt = filter_seek_option(line, slot, modus, opt, outgoing)
112 else: # if modus == Modus.OPTION:
113 modus, opt = filter_seek_description(line, slot, modus, opt, outgoing)
115 return outgoing