24 |
24 |
25 class ExporterTEX(ExporterBase): |
25 class ExporterTEX(ExporterBase): |
26 """ |
26 """ |
27 Class implementing an exporter for TeX. |
27 Class implementing an exporter for TeX. |
28 """ |
28 """ |
|
29 |
29 CHARZ = 26 |
30 CHARZ = 26 |
30 |
31 |
31 def __init__(self, editor, parent=None): |
32 def __init__(self, editor, parent=None): |
32 """ |
33 """ |
33 Constructor |
34 Constructor |
34 |
35 |
35 @param editor reference to the editor object (QScintilla.Editor.Editor) |
36 @param editor reference to the editor object (QScintilla.Editor.Editor) |
36 @param parent parent object of the exporter (QObject) |
37 @param parent parent object of the exporter (QObject) |
37 """ |
38 """ |
38 ExporterBase.__init__(self, editor, parent) |
39 ExporterBase.__init__(self, editor, parent) |
39 |
40 |
40 def __getTexRGB(self, color): |
41 def __getTexRGB(self, color): |
41 """ |
42 """ |
42 Private method to convert a color object to a TeX color string. |
43 Private method to convert a color object to a TeX color string. |
43 |
44 |
44 @param color color object to convert (QColor) |
45 @param color color object to convert (QColor) |
45 @return TeX color string (string) |
46 @return TeX color string (string) |
46 """ |
47 """ |
47 # texcolor[rgb]{0,0.5,0}{....} |
48 # texcolor[rgb]{0,0.5,0}{....} |
48 rf = color.red() / 256.0 |
49 rf = color.red() / 256.0 |
49 gf = color.green() / 256.0 |
50 gf = color.green() / 256.0 |
50 bf = color.blue() / 256.0 |
51 bf = color.blue() / 256.0 |
51 |
52 |
52 # avoid breakage due to locale setting |
53 # avoid breakage due to locale setting |
53 r = int(rf * 10 + 0.5) |
54 r = int(rf * 10 + 0.5) |
54 g = int(gf * 10 + 0.5) |
55 g = int(gf * 10 + 0.5) |
55 b = int(bf * 10 + 0.5) |
56 b = int(bf * 10 + 0.5) |
56 |
57 |
57 return "{0:d}.{1:d}, {2:d}.{3:d}, {4:d}.{5:d}".format( |
58 return "{0:d}.{1:d}, {2:d}.{3:d}, {4:d}.{5:d}".format( |
58 r // 10, r % 10, g // 10, g % 10, b // 10, b % 10) |
59 r // 10, r % 10, g // 10, g % 10, b // 10, b % 10 |
59 |
60 ) |
|
61 |
60 def __texStyle(self, style): |
62 def __texStyle(self, style): |
61 """ |
63 """ |
62 Private method to calculate a style name string for a given style |
64 Private method to calculate a style name string for a given style |
63 number. |
65 number. |
64 |
66 |
65 @param style style number (integer) |
67 @param style style number (integer) |
66 @return style name string (string) |
68 @return style name string (string) |
67 """ |
69 """ |
68 buf = "" |
70 buf = "" |
69 if style >= 0: |
71 if style >= 0: |
70 start = ord('a') |
72 start = ord("a") |
71 else: |
73 else: |
72 start = ord('A') |
74 start = ord("A") |
73 style = abs(style) |
75 style = abs(style) |
74 |
76 |
75 if style == 0: |
77 if style == 0: |
76 buf = "a" |
78 buf = "a" |
77 else: |
79 else: |
78 while style > 0: |
80 while style > 0: |
79 buf += chr(start + (style % self.CHARZ)) |
81 buf += chr(start + (style % self.CHARZ)) |
80 style //= self.CHARZ |
82 style //= self.CHARZ |
81 return buf |
83 return buf |
82 |
84 |
83 def __defineTexStyle(self, font, color, paper, file, istyle): |
85 def __defineTexStyle(self, font, color, paper, file, istyle): |
84 """ |
86 """ |
85 Private method to define a new TeX style. |
87 Private method to define a new TeX style. |
86 |
88 |
87 @param font the font to be used (QFont) |
89 @param font the font to be used (QFont) |
88 @param color the foreground color to be used (QColor) |
90 @param color the foreground color to be used (QColor) |
89 @param paper the background color to be used (QColor) |
91 @param paper the background color to be used (QColor) |
90 @param file reference to the open file to write to (file object) |
92 @param file reference to the open file to write to (file object) |
91 @param istyle style number (integer) |
93 @param istyle style number (integer) |
92 """ |
94 """ |
93 closing_brackets = 3 |
95 closing_brackets = 3 |
94 file.write( |
96 file.write( |
95 "\\newcommand{{\\eric{0}}}[1]{{\\noindent{{\\ttfamily{{".format( |
97 "\\newcommand{{\\eric{0}}}[1]{{\\noindent{{\\ttfamily{{".format( |
96 self.__texStyle(istyle))) |
98 self.__texStyle(istyle) |
|
99 ) |
|
100 ) |
97 if font.italic(): |
101 if font.italic(): |
98 file.write("\\textit{") |
102 file.write("\\textit{") |
99 closing_brackets += 1 |
103 closing_brackets += 1 |
100 if font.bold(): |
104 if font.bold(): |
101 file.write("\\textbf{") |
105 file.write("\\textbf{") |
102 closing_brackets += 1 |
106 closing_brackets += 1 |
103 if color != self.defaultColor: |
107 if color != self.defaultColor: |
104 file.write( |
108 file.write("\\textcolor[rgb]{{{0}}}{{".format(self.__getTexRGB(color))) |
105 "\\textcolor[rgb]{{{0}}}{{".format(self.__getTexRGB(color))) |
|
106 closing_brackets += 1 |
109 closing_brackets += 1 |
107 if paper != self.defaultPaper: |
110 if paper != self.defaultPaper: |
108 file.write( |
111 file.write("\\colorbox[rgb]{{{0}}}{{".format(self.__getTexRGB(paper))) |
109 "\\colorbox[rgb]{{{0}}}{{".format(self.__getTexRGB(paper))) |
112 closing_brackets += 1 |
110 closing_brackets += 1 |
113 file.write("#1{0}\n".format("}" * closing_brackets)) |
111 file.write("#1{0}\n".format('}' * closing_brackets)) |
114 |
112 |
|
113 def exportSource(self): |
115 def exportSource(self): |
114 """ |
116 """ |
115 Public method performing the export. |
117 Public method performing the export. |
116 """ |
118 """ |
117 filename = self._getFileName(self.tr("TeX Files (*.tex)")) |
119 filename = self._getFileName(self.tr("TeX Files (*.tex)")) |
118 if not filename: |
120 if not filename: |
119 return |
121 return |
120 |
122 |
121 self.editor.recolor(0, -1) |
123 self.editor.recolor(0, -1) |
122 |
124 |
123 tabSize = self.editor.getEditorConfig("TabWidth") |
125 tabSize = self.editor.getEditorConfig("TabWidth") |
124 if tabSize == 0: |
126 if tabSize == 0: |
125 tabSize = 4 |
127 tabSize = 4 |
126 |
128 |
127 onlyStylesUsed = Preferences.getEditorExporter( |
129 onlyStylesUsed = Preferences.getEditorExporter("TeX/OnlyStylesUsed") |
128 "TeX/OnlyStylesUsed") |
130 titleFullPath = Preferences.getEditorExporter("TeX/FullPathAsTitle") |
129 titleFullPath = Preferences.getEditorExporter( |
131 |
130 "TeX/FullPathAsTitle") |
|
131 |
|
132 lex = self.editor.getLexer() |
132 lex = self.editor.getLexer() |
133 self.defaultPaper = ( |
133 self.defaultPaper = ( |
134 lex and |
134 lex and lex.paper(QsciScintilla.STYLE_DEFAULT) or self.editor.paper().name() |
135 lex.paper(QsciScintilla.STYLE_DEFAULT) or |
|
136 self.editor.paper().name() |
|
137 ) |
135 ) |
138 self.defaultColor = ( |
136 self.defaultColor = ( |
139 lex and |
137 lex and lex.color(QsciScintilla.STYLE_DEFAULT) or self.editor.color().name() |
140 lex.color(QsciScintilla.STYLE_DEFAULT) or |
|
141 self.editor.color().name() |
|
142 ) |
138 ) |
143 self.defaultFont = ( |
139 self.defaultFont = ( |
144 lex and |
140 lex |
145 lex.color(QsciScintilla.STYLE_DEFAULT) or |
141 and lex.color(QsciScintilla.STYLE_DEFAULT) |
146 Preferences.getEditorOtherFonts("DefaultFont") |
142 or Preferences.getEditorOtherFonts("DefaultFont") |
147 ) |
143 ) |
148 |
144 |
149 lengthDoc = self.editor.length() |
145 lengthDoc = self.editor.length() |
150 styleIsUsed = {} |
146 styleIsUsed = {} |
151 if onlyStylesUsed: |
147 if onlyStylesUsed: |
152 for index in range(QsciScintilla.STYLE_MAX + 1): |
148 for index in range(QsciScintilla.STYLE_MAX + 1): |
153 styleIsUsed[index] = False |
149 styleIsUsed[index] = False |
171 f.write("\\usepackage{times}\n") |
167 f.write("\\usepackage{times}\n") |
172 if self.editor.isUtf8(): |
168 if self.editor.isUtf8(): |
173 f.write("\\usepackage[utf8]{inputenc}\n") |
169 f.write("\\usepackage[utf8]{inputenc}\n") |
174 else: |
170 else: |
175 f.write("\\usepackage[latin1]{inputenc}\n") |
171 f.write("\\usepackage[latin1]{inputenc}\n") |
176 |
172 |
177 if lex: |
173 if lex: |
178 istyle = 0 |
174 istyle = 0 |
179 while istyle <= QsciScintilla.STYLE_MAX: |
175 while istyle <= QsciScintilla.STYLE_MAX: |
180 if ( |
176 if ( |
181 (istyle <= QsciScintilla.STYLE_DEFAULT or |
177 ( |
182 istyle > QsciScintilla.STYLE_LASTPREDEFINED) and |
178 istyle <= QsciScintilla.STYLE_DEFAULT |
183 styleIsUsed[istyle] and |
179 or istyle > QsciScintilla.STYLE_LASTPREDEFINED |
184 (lex.description(istyle) or |
180 ) |
185 istyle == QsciScintilla.STYLE_DEFAULT) |
181 and styleIsUsed[istyle] |
|
182 and ( |
|
183 lex.description(istyle) |
|
184 or istyle == QsciScintilla.STYLE_DEFAULT |
|
185 ) |
186 ): |
186 ): |
187 font = lex.font(istyle) |
187 font = lex.font(istyle) |
188 colour = lex.color(istyle) |
188 colour = lex.color(istyle) |
189 paper = lex.paper(istyle) |
189 paper = lex.paper(istyle) |
190 |
190 |
191 self.__defineTexStyle( |
191 self.__defineTexStyle(font, colour, paper, f, istyle) |
192 font, colour, paper, f, istyle) |
|
193 # get substyles |
192 # get substyles |
194 subs_start, subs_count = ( |
193 subs_start, subs_count = self.editor.getSubStyleRange( |
195 self.editor.getSubStyleRange(istyle) |
194 istyle |
196 ) |
195 ) |
197 for subs_idx in range(subs_count): |
196 for subs_idx in range(subs_count): |
198 font = lex.font(subs_start + subs_idx) |
197 font = lex.font(subs_start + subs_idx) |
199 colour = lex.color( |
198 colour = lex.color(subs_start + subs_idx) |
200 subs_start + subs_idx) |
199 paper = lex.paper(subs_start + subs_idx) |
201 paper = lex.paper( |
200 |
202 subs_start + subs_idx) |
|
203 |
|
204 self.__defineTexStyle( |
201 self.__defineTexStyle( |
205 font, colour, paper, f, |
202 font, colour, paper, f, subs_idx - subs_start |
206 subs_idx - subs_start) |
203 ) |
207 |
204 |
208 istyle += 1 |
205 istyle += 1 |
209 else: |
206 else: |
210 colour = self.editor.color() |
207 colour = self.editor.color() |
211 paper = self.editor.paper() |
208 paper = self.editor.paper() |
212 font = Preferences.getEditorOtherFonts("DefaultFont") |
209 font = Preferences.getEditorOtherFonts("DefaultFont") |
213 |
210 |
214 self.__defineTexStyle(font, colour, paper, f, 0) |
211 self.__defineTexStyle(font, colour, paper, f, 0) |
215 self.__defineTexStyle(font, colour, paper, f, |
212 self.__defineTexStyle( |
216 QsciScintilla.STYLE_DEFAULT) |
213 font, colour, paper, f, QsciScintilla.STYLE_DEFAULT |
217 |
214 ) |
|
215 |
218 f.write("\\begin{document}\n\n") |
216 f.write("\\begin{document}\n\n") |
219 title = ( |
217 title = ( |
220 self.editor.getFileName() |
218 self.editor.getFileName() |
221 if titleFullPath else |
219 if titleFullPath |
222 os.path.basename(self.editor.getFileName()) |
220 else os.path.basename(self.editor.getFileName()) |
223 ) |
221 ) |
224 f.write( |
222 f.write( |
225 "Source File: {0}\n\n\\noindent\n\\tiny{{\n" |
223 "Source File: {0}\n\n\\noindent\n\\tiny{{\n".format( |
226 .format(title.replace('_', '\\_'))) |
224 title.replace("_", "\\_") |
227 |
225 ) |
|
226 ) |
|
227 |
228 styleCurrent = self.editor.styleAt(0) |
228 styleCurrent = self.editor.styleAt(0) |
229 f.write("\\eric{0}{{" |
229 f.write("\\eric{0}{{".format(self.__texStyle(styleCurrent))) |
230 .format(self.__texStyle(styleCurrent))) |
230 |
231 |
|
232 lineIdx = 0 |
231 lineIdx = 0 |
233 pos = 0 |
232 pos = 0 |
234 utf8 = self.editor.isUtf8() |
233 utf8 = self.editor.isUtf8() |
235 utf8Ch = b"" |
234 utf8Ch = b"" |
236 utf8Len = 0 |
235 utf8Len = 0 |
237 |
236 |
238 while pos < lengthDoc: |
237 while pos < lengthDoc: |
239 ch = self.editor.byteAt(pos) |
238 ch = self.editor.byteAt(pos) |
240 style = self.editor.styleAt(pos) |
239 style = self.editor.styleAt(pos) |
241 if style != styleCurrent: |
240 if style != styleCurrent: |
242 # new style |
241 # new style |
243 f.write( |
242 f.write("}}\n\\eric{0}{{".format(self.__texStyle(style))) |
244 "}}\n\\eric{0}{{".format( |
|
245 self.__texStyle(style))) |
|
246 styleCurrent = style |
243 styleCurrent = style |
247 |
244 |
248 if ch == b'\t': |
245 if ch == b"\t": |
249 ts = tabSize - (lineIdx % tabSize) |
246 ts = tabSize - (lineIdx % tabSize) |
250 lineIdx += ts - 1 |
247 lineIdx += ts - 1 |
251 f.write("\\hspace*{{{0:d}em}}".format(ts)) |
248 f.write("\\hspace*{{{0:d}em}}".format(ts)) |
252 elif ch == b'\\': |
249 elif ch == b"\\": |
253 f.write("{\\textbackslash}") |
250 f.write("{\\textbackslash}") |
254 elif ch in [b'>', b'<', b'@']: |
251 elif ch in [b">", b"<", b"@"]: |
255 f.write("${0}$".format(ch.decode())) |
252 f.write("${0}$".format(ch.decode())) |
256 elif ch in [b'{', b'}', b'^', b'_', b'&', b'$', b'#', |
253 elif ch in [b"{", b"}", b"^", b"_", b"&", b"$", b"#", b"%", b"~"]: |
257 b'%', b'~']: |
|
258 f.write("\\{0}".format(ch.decode())) |
254 f.write("\\{0}".format(ch.decode())) |
259 elif ch in [b'\r', b'\n']: |
255 elif ch in [b"\r", b"\n"]: |
260 lineIdx = -1 # because incremented below |
256 lineIdx = -1 # because incremented below |
261 if ( |
257 if ch == b"\r" and self.editor.byteAt(pos + 1) == b"\n": |
262 ch == b'\r' and |
258 pos += 1 # skip the LF |
263 self.editor.byteAt(pos + 1) == b'\n' |
|
264 ): |
|
265 pos += 1 # skip the LF |
|
266 styleCurrent = self.editor.styleAt(pos + 1) |
259 styleCurrent = self.editor.styleAt(pos + 1) |
267 f.write("}} \\\\\n\\eric{0}{{".format( |
260 f.write( |
268 self.__texStyle(styleCurrent))) |
261 "}} \\\\\n\\eric{0}{{".format(self.__texStyle(styleCurrent)) |
269 elif ch == b' ': |
262 ) |
270 if self.editor.byteAt(pos + 1) == b' ': |
263 elif ch == b" ": |
|
264 if self.editor.byteAt(pos + 1) == b" ": |
271 f.write("{\\hspace*{1em}}") |
265 f.write("{\\hspace*{1em}}") |
272 else: |
266 else: |
273 f.write(' ') |
267 f.write(" ") |
274 else: |
268 else: |
275 if ord(ch) > 127 and utf8: |
269 if ord(ch) > 127 and utf8: |
276 utf8Ch += ch |
270 utf8Ch += ch |
277 if utf8Len == 0: |
271 if utf8Len == 0: |
278 if (utf8Ch[0] & 0xF0) == 0xF0: |
272 if (utf8Ch[0] & 0xF0) == 0xF0: |