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

1"""Apply any option command to subsequent description environment. 

2 

3Implementation Note: The empty string marker is used to indicate absence of option command. 

4""" 

5 

6from collections.abc import Iterable 

7from enum import Enum 

8 

9from liitos import log 

10 

11Modus = Enum('Modus', 'COPY OPTION') 

12ModusOption = tuple[Modus, str] 

13 

14NO_OPTION: str = '' 

15 

16OPTION_START_TRIGGER_STARTSWITH = r'\option[' 

17DESCRIPTION_START_TRIGGER_STARTSWITH = r'\begin{description}' 

18 

19 

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. 

22 

23 Examples: 

24 

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 == '[]' 

30 

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 

36 

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) 

50 

51 return modus, opt 

52 

53 

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. 

56 

57 Examples: 

58 

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]' 

64 

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 

70 

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) 

87 

88 return modus, opt 

89 

90 

91def options(incoming: Iterable[str], lookup: dict[str, str] | None = None) -> list[str]: 

92 r"""Later alligator. \option[style=multiline,leftmargin=6em] 

93 

94 Examples: 

95 

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) 

114 

115 return outgoing