Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pygments/formatters/groff.py: 74%

96 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-26 07:45 +0000

1""" 

2 pygments.formatters.groff 

3 ~~~~~~~~~~~~~~~~~~~~~~~~~ 

4 

5 Formatter for groff output. 

6 

7 :copyright: Copyright 2006-2022 by the Pygments team, see AUTHORS. 

8 :license: BSD, see LICENSE for details. 

9""" 

10 

11import math 

12from pygments.formatter import Formatter 

13from pygments.util import get_bool_opt, get_int_opt 

14 

15__all__ = ['GroffFormatter'] 

16 

17 

18class GroffFormatter(Formatter): 

19 """ 

20 Format tokens with groff escapes to change their color and font style. 

21 

22 .. versionadded:: 2.11 

23 

24 Additional options accepted: 

25 

26 `style` 

27 The style to use, can be a string or a Style subclass (default: 

28 ``'default'``). 

29 

30 `monospaced` 

31 If set to true, monospace font will be used (default: ``true``). 

32 

33 `linenos` 

34 If set to true, print the line numbers (default: ``false``). 

35 

36 `wrap` 

37 Wrap lines to the specified number of characters. Disabled if set to 0 

38 (default: ``0``). 

39 """ 

40 

41 name = 'groff' 

42 aliases = ['groff','troff','roff'] 

43 filenames = [] 

44 

45 def __init__(self, **options): 

46 Formatter.__init__(self, **options) 

47 

48 self.monospaced = get_bool_opt(options, 'monospaced', True) 

49 self.linenos = get_bool_opt(options, 'linenos', False) 

50 self._lineno = 0 

51 self.wrap = get_int_opt(options, 'wrap', 0) 

52 self._linelen = 0 

53 

54 self.styles = {} 

55 self._make_styles() 

56 

57 

58 def _make_styles(self): 

59 regular = '\\f[CR]' if self.monospaced else '\\f[R]' 

60 bold = '\\f[CB]' if self.monospaced else '\\f[B]' 

61 italic = '\\f[CI]' if self.monospaced else '\\f[I]' 

62 

63 for ttype, ndef in self.style: 

64 start = end = '' 

65 if ndef['color']: 

66 start += '\\m[%s]' % ndef['color'] 

67 end = '\\m[]' + end 

68 if ndef['bold']: 

69 start += bold 

70 end = regular + end 

71 if ndef['italic']: 

72 start += italic 

73 end = regular + end 

74 if ndef['bgcolor']: 

75 start += '\\M[%s]' % ndef['bgcolor'] 

76 end = '\\M[]' + end 

77 

78 self.styles[ttype] = start, end 

79 

80 

81 def _define_colors(self, outfile): 

82 colors = set() 

83 for _, ndef in self.style: 

84 if ndef['color'] is not None: 

85 colors.add(ndef['color']) 

86 

87 for color in sorted(colors): 

88 outfile.write('.defcolor ' + color + ' rgb #' + color + '\n') 

89 

90 

91 def _write_lineno(self, outfile): 

92 self._lineno += 1 

93 outfile.write("%s% 4d " % (self._lineno != 1 and '\n' or '', self._lineno)) 

94 

95 

96 def _wrap_line(self, line): 

97 length = len(line.rstrip('\n')) 

98 space = ' ' if self.linenos else '' 

99 newline = '' 

100 

101 if length > self.wrap: 

102 for i in range(0, math.floor(length / self.wrap)): 

103 chunk = line[i*self.wrap:i*self.wrap+self.wrap] 

104 newline += (chunk + '\n' + space) 

105 remainder = length % self.wrap 

106 if remainder > 0: 

107 newline += line[-remainder-1:] 

108 self._linelen = remainder 

109 elif self._linelen + length > self.wrap: 

110 newline = ('\n' + space) + line 

111 self._linelen = length 

112 else: 

113 newline = line 

114 self._linelen += length 

115 

116 return newline 

117 

118 

119 def _escape_chars(self, text): 

120 text = text.replace('\\', '\\[u005C]'). \ 

121 replace('.', '\\[char46]'). \ 

122 replace('\'', '\\[u0027]'). \ 

123 replace('`', '\\[u0060]'). \ 

124 replace('~', '\\[u007E]') 

125 copy = text 

126 

127 for char in copy: 

128 if len(char) != len(char.encode()): 

129 uni = char.encode('unicode_escape') \ 

130 .decode()[1:] \ 

131 .replace('x', 'u00') \ 

132 .upper() 

133 text = text.replace(char, '\\[u' + uni[1:] + ']') 

134 

135 return text 

136 

137 

138 def format_unencoded(self, tokensource, outfile): 

139 self._define_colors(outfile) 

140 

141 outfile.write('.nf\n\\f[CR]\n') 

142 

143 if self.linenos: 

144 self._write_lineno(outfile) 

145 

146 for ttype, value in tokensource: 

147 while ttype not in self.styles: 

148 ttype = ttype.parent 

149 start, end = self.styles[ttype] 

150 

151 for line in value.splitlines(True): 

152 if self.wrap > 0: 

153 line = self._wrap_line(line) 

154 

155 if start and end: 

156 text = self._escape_chars(line.rstrip('\n')) 

157 if text != '': 

158 outfile.write(''.join((start, text, end))) 

159 else: 

160 outfile.write(self._escape_chars(line.rstrip('\n'))) 

161 

162 if line.endswith('\n'): 

163 if self.linenos: 

164 self._write_lineno(outfile) 

165 self._linelen = 0 

166 else: 

167 outfile.write('\n') 

168 self._linelen = 0 

169 

170 outfile.write('\n.fi')