69 pos += 1 |
77 pos += 1 |
70 else: |
78 else: |
71 for index in range(QsciScintilla.STYLE_MAX + 1): |
79 for index in range(QsciScintilla.STYLE_MAX + 1): |
72 styleIsUsed[index] = True |
80 styleIsUsed[index] = True |
73 styleIsUsed[QsciScintilla.STYLE_DEFAULT] = True |
81 styleIsUsed[QsciScintilla.STYLE_DEFAULT] = True |
74 |
82 |
75 html = ( |
83 html = ( |
76 '''<!DOCTYPE html PUBLIC "-//W3C//DTD''' |
84 """<!DOCTYPE html PUBLIC "-//W3C//DTD""" |
77 ''' XHTML 1.0 Transitional//EN"\n''' |
85 """ XHTML 1.0 Transitional//EN"\n""" |
78 ''' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">''' |
86 """ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">""" |
79 '''\n''' |
87 """\n""" |
80 '''<html xmlns="http://www.w3.org/1999/xhtml">\n''' |
88 """<html xmlns="http://www.w3.org/1999/xhtml">\n""" |
81 '''<head>\n''' |
89 """<head>\n""" |
82 ) |
90 ) |
83 if titleFullPath: |
91 if titleFullPath: |
84 html += '''<title>{0}</title>\n'''.format( |
92 html += """<title>{0}</title>\n""".format(self.editor.getFileName()) |
85 self.editor.getFileName()) |
93 else: |
86 else: |
94 html += """<title>{0}</title>\n""".format( |
87 html += '''<title>{0}</title>\n'''.format( |
95 os.path.basename(self.editor.getFileName()) |
88 os.path.basename(self.editor.getFileName())) |
96 ) |
89 html += ( |
97 html += ( |
90 '''<meta name="Generator" content="eric" />\n''' |
98 """<meta name="Generator" content="eric" />\n""" |
91 '''<meta http-equiv="Content-Type" ''' |
99 """<meta http-equiv="Content-Type" """ |
92 '''content="text/html; charset=utf-8" />\n''' |
100 """content="text/html; charset=utf-8" />\n""" |
93 ) |
101 ) |
94 if folding: |
102 if folding: |
95 html += ( |
103 html += ( |
96 '''<script language="JavaScript" type="text/javascript">\n''' |
104 """<script language="JavaScript" type="text/javascript">\n""" |
97 '''<!--\n''' |
105 """<!--\n""" |
98 '''function symbol(id, sym) {\n''' |
106 """function symbol(id, sym) {\n""" |
99 ''' if (id.textContent == undefined) {\n''' |
107 """ if (id.textContent == undefined) {\n""" |
100 ''' id.innerText = sym;\n''' |
108 """ id.innerText = sym;\n""" |
101 ''' } else {\n''' |
109 """ } else {\n""" |
102 ''' id.textContent = sym;\n''' |
110 """ id.textContent = sym;\n""" |
103 ''' }\n''' |
111 """ }\n""" |
104 '''}\n''' |
112 """}\n""" |
105 '''function toggle(id) {\n''' |
113 """function toggle(id) {\n""" |
106 ''' var thislayer = document.getElementById('ln' + id);\n''' |
114 """ var thislayer = document.getElementById('ln' + id);\n""" |
107 ''' id -= 1;\n''' |
115 """ id -= 1;\n""" |
108 ''' var togline = document.getElementById('hd' + id);\n''' |
116 """ var togline = document.getElementById('hd' + id);\n""" |
109 ''' var togsym = document.getElementById('bt' + id);\n''' |
117 """ var togsym = document.getElementById('bt' + id);\n""" |
110 ''' if (thislayer.style.display == 'none') {\n''' |
118 """ if (thislayer.style.display == 'none') {\n""" |
111 ''' thislayer.style.display = 'block';\n''' |
119 """ thislayer.style.display = 'block';\n""" |
112 ''' togline.style.textDecoration = 'none';\n''' |
120 """ togline.style.textDecoration = 'none';\n""" |
113 ''' symbol(togsym, '- ');\n''' |
121 """ symbol(togsym, '- ');\n""" |
114 ''' } else {\n''' |
122 """ } else {\n""" |
115 ''' thislayer.style.display = 'none';\n''' |
123 """ thislayer.style.display = 'none';\n""" |
116 ''' togline.style.textDecoration = 'underline';\n''' |
124 """ togline.style.textDecoration = 'underline';\n""" |
117 ''' symbol(togsym, '+ ');\n''' |
125 """ symbol(togsym, '+ ');\n""" |
118 ''' }\n''' |
126 """ }\n""" |
119 '''}\n''' |
127 """}\n""" |
120 '''//-->\n''' |
128 """//-->\n""" |
121 '''</script>\n''' |
129 """</script>\n""" |
122 ) |
130 ) |
123 |
131 |
124 lex = self.editor.getLexer() |
132 lex = self.editor.getLexer() |
125 bgColour = ( |
133 bgColour = ( |
126 lex.paper(QsciScintilla.STYLE_DEFAULT).name() |
134 lex.paper(QsciScintilla.STYLE_DEFAULT).name() |
127 if lex else |
135 if lex |
128 self.editor.paper().name() |
136 else self.editor.paper().name() |
129 ) |
137 ) |
130 |
138 |
131 html += '''<style type="text/css">\n''' |
139 html += """<style type="text/css">\n""" |
132 if lex: |
140 if lex: |
133 istyle = 0 |
141 istyle = 0 |
134 while istyle <= QsciScintilla.STYLE_MAX: |
142 while istyle <= QsciScintilla.STYLE_MAX: |
135 if ( |
143 if ( |
136 (istyle <= QsciScintilla.STYLE_DEFAULT or |
144 istyle <= QsciScintilla.STYLE_DEFAULT |
137 istyle > QsciScintilla.STYLE_LASTPREDEFINED) and |
145 or istyle > QsciScintilla.STYLE_LASTPREDEFINED |
138 styleIsUsed[istyle] |
146 ) and styleIsUsed[istyle]: |
139 ): |
147 if lex.description(istyle) or istyle == QsciScintilla.STYLE_DEFAULT: |
140 if ( |
|
141 lex.description(istyle) or |
|
142 istyle == QsciScintilla.STYLE_DEFAULT |
|
143 ): |
|
144 font = lex.font(istyle) |
148 font = lex.font(istyle) |
145 colour = lex.color(istyle) |
149 colour = lex.color(istyle) |
146 paper = lex.paper(istyle) |
150 paper = lex.paper(istyle) |
147 if istyle == QsciScintilla.STYLE_DEFAULT: |
151 if istyle == QsciScintilla.STYLE_DEFAULT: |
148 html += '''span {\n''' |
152 html += """span {\n""" |
149 else: |
153 else: |
150 html += '''.S{0:d} {{\n'''.format(istyle) |
154 html += """.S{0:d} {{\n""".format(istyle) |
151 if font.italic(): |
155 if font.italic(): |
152 html += ''' font-style: italic;\n''' |
156 html += """ font-style: italic;\n""" |
153 if font.bold(): |
157 if font.bold(): |
154 html += ''' font-weight: bold;\n''' |
158 html += """ font-weight: bold;\n""" |
155 if wysiwyg: |
159 if wysiwyg: |
156 html += ''' font-family: '{0}';\n'''.format( |
160 html += """ font-family: '{0}';\n""".format( |
157 font.family()) |
161 font.family() |
158 html += ''' color: {0};\n'''.format(colour.name()) |
162 ) |
|
163 html += """ color: {0};\n""".format(colour.name()) |
159 if ( |
164 if ( |
160 istyle != QsciScintilla.STYLE_DEFAULT and |
165 istyle != QsciScintilla.STYLE_DEFAULT |
161 bgColour != paper.name() |
166 and bgColour != paper.name() |
162 ): |
167 ): |
163 html += ''' background: {0};\n'''.format( |
168 html += """ background: {0};\n""".format(paper.name()) |
164 paper.name()) |
169 html += """ text-decoration: inherit;\n""" |
165 html += ''' text-decoration: inherit;\n''' |
|
166 if wysiwyg: |
170 if wysiwyg: |
167 html += ''' font-size: {0:d}pt;\n'''.format( |
171 html += """ font-size: {0:d}pt;\n""".format( |
168 QFontInfo(font).pointSize()) |
172 QFontInfo(font).pointSize() |
169 html += '''}\n''' |
173 ) |
170 |
174 html += """}\n""" |
|
175 |
171 # get substyles |
176 # get substyles |
172 subs_start, subs_count = self.editor.getSubStyleRange( |
177 subs_start, subs_count = self.editor.getSubStyleRange(istyle) |
173 istyle) |
|
174 for subs_idx in range(subs_count): |
178 for subs_idx in range(subs_count): |
175 styleIsUsed[subs_idx - subs_start] = True |
179 styleIsUsed[subs_idx - subs_start] = True |
176 font = lex.font(subs_start + subs_idx) |
180 font = lex.font(subs_start + subs_idx) |
177 colour = lex.color(subs_start + subs_idx) |
181 colour = lex.color(subs_start + subs_idx) |
178 paper = lex.paper(subs_start + subs_idx) |
182 paper = lex.paper(subs_start + subs_idx) |
179 html += '.S{0:d} {{\n'.format( |
183 html += ".S{0:d} {{\n".format(subs_idx - subs_start) |
180 subs_idx - subs_start) |
|
181 if font.italic(): |
184 if font.italic(): |
182 html += ' font-style: italic;\n' |
185 html += " font-style: italic;\n" |
183 if font.bold(): |
186 if font.bold(): |
184 html += ' font-weight: bold;\n' |
187 html += " font-weight: bold;\n" |
185 if wysiwyg: |
188 if wysiwyg: |
186 html += " font-family: '{0}';\n".format( |
189 html += " font-family: '{0}';\n".format( |
187 font.family()) |
190 font.family() |
188 html += ' color: {0};\n'.format(colour.name()) |
191 ) |
|
192 html += " color: {0};\n".format(colour.name()) |
189 if wysiwyg: |
193 if wysiwyg: |
190 html += ' font-size: {0:d}pt;\n'.format( |
194 html += " font-size: {0:d}pt;\n".format( |
191 QFontInfo(font).pointSize()) |
195 QFontInfo(font).pointSize() |
192 html += '}\n' |
196 ) |
|
197 html += "}\n" |
193 # __IGNORE_WARNING_Y113__ |
198 # __IGNORE_WARNING_Y113__ |
194 else: |
199 else: |
195 styleIsUsed[istyle] = False |
200 styleIsUsed[istyle] = False |
196 istyle += 1 |
201 istyle += 1 |
197 else: |
202 else: |
198 colour = self.editor.color() |
203 colour = self.editor.color() |
199 paper = self.editor.paper() |
204 paper = self.editor.paper() |
200 font = Preferences.getEditorOtherFonts("DefaultFont") |
205 font = Preferences.getEditorOtherFonts("DefaultFont") |
201 html += '''.S0 {\n''' |
206 html += """.S0 {\n""" |
202 if font.italic(): |
207 if font.italic(): |
203 html += ''' font-style: italic;\n''' |
208 html += """ font-style: italic;\n""" |
204 if font.bold(): |
209 if font.bold(): |
205 html += ''' font-weight: bold;\n''' |
210 html += """ font-weight: bold;\n""" |
206 if wysiwyg: |
211 if wysiwyg: |
207 html += ''' font-family: '{0}';\n'''.format(font.family()) |
212 html += """ font-family: '{0}';\n""".format(font.family()) |
208 html += ''' color: {0};\n'''.format(colour.name()) |
213 html += """ color: {0};\n""".format(colour.name()) |
209 if bgColour != paper.name(): |
214 if bgColour != paper.name(): |
210 html += ''' background: {0};\n'''.format(paper.name()) |
215 html += """ background: {0};\n""".format(paper.name()) |
211 html += ''' text-decoration: inherit;\n''' |
216 html += """ text-decoration: inherit;\n""" |
212 if wysiwyg: |
217 if wysiwyg: |
213 html += ''' font-size: {0:d}pt;\n'''.format( |
218 html += """ font-size: {0:d}pt;\n""".format( |
214 QFontInfo(font).pointSize()) |
219 QFontInfo(font).pointSize() |
215 html += '''}\n''' |
220 ) |
216 html += '''</style>\n''' |
221 html += """}\n""" |
217 html += '''</head>\n''' |
222 html += """</style>\n""" |
218 |
223 html += """</head>\n""" |
219 html += '''<body bgcolor="{0}">\n'''.format(bgColour) |
224 |
|
225 html += """<body bgcolor="{0}">\n""".format(bgColour) |
220 line = self.editor.lineAt(0) |
226 line = self.editor.lineAt(0) |
221 level = self.editor.foldLevelAt(line) - QsciScintilla.SC_FOLDLEVELBASE |
227 level = self.editor.foldLevelAt(line) - QsciScintilla.SC_FOLDLEVELBASE |
222 levelStack = [level] |
228 levelStack = [level] |
223 styleCurrent = self.editor.styleAt(0) |
229 styleCurrent = self.editor.styleAt(0) |
224 inStyleSpan = False |
230 inStyleSpan = False |
225 inFoldSpan = False |
231 inFoldSpan = False |
226 # Global span for default attributes |
232 # Global span for default attributes |
227 if wysiwyg: |
233 if wysiwyg: |
228 html += '''<span>''' |
234 html += """<span>""" |
229 else: |
235 else: |
230 html += '''<pre>''' |
236 html += """<pre>""" |
231 |
237 |
232 if folding: |
238 if folding: |
233 if ( |
239 if self.editor.foldFlagsAt(line) & QsciScintilla.SC_FOLDLEVELHEADERFLAG: |
234 self.editor.foldFlagsAt(line) & |
240 html += ("""<span id="hd{0:d}" onclick="toggle('{1:d}')">""").format( |
235 QsciScintilla.SC_FOLDLEVELHEADERFLAG |
241 line, line + 1 |
236 ): |
242 ) |
237 html += ( |
243 html += """<span id="bt{0:d}">- </span>""".format(line) |
238 '''<span id="hd{0:d}" onclick="toggle('{1:d}')">''' |
|
239 ).format(line, line + 1) |
|
240 html += '''<span id="bt{0:d}">- </span>'''.format(line) |
|
241 inFoldSpan = True |
244 inFoldSpan = True |
242 else: |
245 else: |
243 html += ''' ''' |
246 html += """ """ |
244 |
247 |
245 if styleIsUsed[styleCurrent]: |
248 if styleIsUsed[styleCurrent]: |
246 html += '''<span class="S{0:0d}">'''.format(styleCurrent) |
249 html += """<span class="S{0:0d}">""".format(styleCurrent) |
247 inStyleSpan = True |
250 inStyleSpan = True |
248 |
251 |
249 column = 0 |
252 column = 0 |
250 pos = 0 |
253 pos = 0 |
251 utf8 = self.editor.isUtf8() |
254 utf8 = self.editor.isUtf8() |
252 utf8Ch = b"" |
255 utf8Ch = b"" |
253 utf8Len = 0 |
256 utf8Len = 0 |
254 |
257 |
255 while pos < lengthDoc: |
258 while pos < lengthDoc: |
256 ch = self.editor.byteAt(pos) |
259 ch = self.editor.byteAt(pos) |
257 style = self.editor.styleAt(pos) |
260 style = self.editor.styleAt(pos) |
258 if style != styleCurrent: |
261 if style != styleCurrent: |
259 if inStyleSpan: |
262 if inStyleSpan: |
260 html += '''</span>''' |
263 html += """</span>""" |
261 inStyleSpan = False |
264 inStyleSpan = False |
262 if ch not in [b'\r', b'\n']: # no need of a span for the EOL |
265 if ch not in [b"\r", b"\n"]: # no need of a span for the EOL |
263 if styleIsUsed[style]: |
266 if styleIsUsed[style]: |
264 html += '''<span class="S{0:d}">'''.format(style) |
267 html += """<span class="S{0:d}">""".format(style) |
265 inStyleSpan = True |
268 inStyleSpan = True |
266 styleCurrent = style |
269 styleCurrent = style |
267 |
270 |
268 if ch == b' ': |
271 if ch == b" ": |
269 if wysiwyg: |
272 if wysiwyg: |
270 prevCh = b'' |
273 prevCh = b"" |
271 if column == 0: |
274 if column == 0: |
272 # at start of line, must put a |
275 # at start of line, must put a |
273 # because regular space will be collapsed |
276 # because regular space will be collapsed |
274 prevCh = b' ' |
277 prevCh = b" " |
275 while pos < lengthDoc and self.editor.byteAt(pos) == b' ': |
278 while pos < lengthDoc and self.editor.byteAt(pos) == b" ": |
276 if prevCh != b' ': |
279 if prevCh != b" ": |
277 html += ' ' |
280 html += " " |
278 else: |
281 else: |
279 html += ''' ''' |
282 html += """ """ |
280 prevCh = self.editor.byteAt(pos) |
283 prevCh = self.editor.byteAt(pos) |
281 pos += 1 |
284 pos += 1 |
282 column += 1 |
285 column += 1 |
283 pos -= 1 |
286 pos -= 1 |
284 # the last incrementation will be done by the outer loop |
287 # the last incrementation will be done by the outer loop |
285 else: |
288 else: |
286 html += ' ' |
289 html += " " |
287 column += 1 |
290 column += 1 |
288 elif ch == b'\t': |
291 elif ch == b"\t": |
289 ts = tabSize - (column % tabSize) |
292 ts = tabSize - (column % tabSize) |
290 if wysiwyg: |
293 if wysiwyg: |
291 html += ''' ''' * ts |
294 html += """ """ * ts |
292 column += ts |
295 column += ts |
293 else: |
296 else: |
294 if useTabs: |
297 if useTabs: |
295 html += '\t' |
298 html += "\t" |
296 column += 1 |
299 column += 1 |
297 else: |
300 else: |
298 html += ' ' * ts |
301 html += " " * ts |
299 column += ts |
302 column += ts |
300 elif ch in [b'\r', b'\n']: |
303 elif ch in [b"\r", b"\n"]: |
301 if inStyleSpan: |
304 if inStyleSpan: |
302 html += '''</span>''' |
305 html += """</span>""" |
303 inStyleSpan = False |
306 inStyleSpan = False |
304 if inFoldSpan: |
307 if inFoldSpan: |
305 html += '''</span>''' |
308 html += """</span>""" |
306 inFoldSpan = False |
309 inFoldSpan = False |
307 if ch == b'\r' and self.editor.byteAt(pos + 1) == b'\n': |
310 if ch == b"\r" and self.editor.byteAt(pos + 1) == b"\n": |
308 pos += 1 # CR+LF line ending, skip the "extra" EOL char |
311 pos += 1 # CR+LF line ending, skip the "extra" EOL char |
309 column = 0 |
312 column = 0 |
310 if wysiwyg: |
313 if wysiwyg: |
311 html += '''<br />''' |
314 html += """<br />""" |
312 |
315 |
313 styleCurrent = self.editor.styleAt(pos + 1) |
316 styleCurrent = self.editor.styleAt(pos + 1) |
314 if folding: |
317 if folding: |
315 line = self.editor.lineAt(pos + 1) |
318 line = self.editor.lineAt(pos + 1) |
316 newLevel = self.editor.foldLevelAt(line) |
319 newLevel = self.editor.foldLevelAt(line) |
317 |
320 |
318 if newLevel < level: |
321 if newLevel < level: |
319 while levelStack[-1] > newLevel: |
322 while levelStack[-1] > newLevel: |
320 html += '''</span>''' |
323 html += """</span>""" |
321 levelStack.pop() |
324 levelStack.pop() |
322 html += '\n' # here to get clean code |
325 html += "\n" # here to get clean code |
323 if newLevel > level: |
326 if newLevel > level: |
324 html += '''<span id="ln{0:d}">'''.format(line) |
327 html += """<span id="ln{0:d}">""".format(line) |
325 levelStack.append(newLevel) |
328 levelStack.append(newLevel) |
326 if ( |
329 if ( |
327 self.editor.foldFlagsAt(line) & |
330 self.editor.foldFlagsAt(line) |
328 QsciScintilla.SC_FOLDLEVELHEADERFLAG |
331 & QsciScintilla.SC_FOLDLEVELHEADERFLAG |
329 ): |
332 ): |
330 html += ( |
333 html += ( |
331 '''<span id="hd{0:d}"''' |
334 '''<span id="hd{0:d}"''' """ onclick="toggle('{1:d}')">""" |
332 ''' onclick="toggle('{1:d}')">''' |
|
333 ).format(line, line + 1) |
335 ).format(line, line + 1) |
334 html += '''<span id="bt{0:d}">- </span>'''.format(line) |
336 html += """<span id="bt{0:d}">- </span>""".format(line) |
335 inFoldSpan = True |
337 inFoldSpan = True |
336 else: |
338 else: |
337 html += ''' ''' |
339 html += """ """ |
338 level = newLevel |
340 level = newLevel |
339 else: |
341 else: |
340 html += '\n' |
342 html += "\n" |
341 |
343 |
342 if ( |
344 if styleIsUsed[styleCurrent] and self.editor.byteAt(pos + 1) not in [ |
343 styleIsUsed[styleCurrent] and |
345 b"\r", |
344 self.editor.byteAt(pos + 1) not in [b'\r', b'\n'] |
346 b"\n", |
345 ): |
347 ]: |
346 # We know it's the correct next style, |
348 # We know it's the correct next style, |
347 # but no (empty) span for an empty line |
349 # but no (empty) span for an empty line |
348 html += '''<span class="S{0:0d}">'''.format(styleCurrent) |
350 html += """<span class="S{0:0d}">""".format(styleCurrent) |
349 inStyleSpan = True |
351 inStyleSpan = True |
350 else: |
352 else: |
351 if ch == b'<': |
353 if ch == b"<": |
352 html += '''<''' |
354 html += """<""" |
353 elif ch == b'>': |
355 elif ch == b">": |
354 html += '''>''' |
356 html += """>""" |
355 elif ch == b'&': |
357 elif ch == b"&": |
356 html += '''&''' |
358 html += """&""" |
357 else: |
359 else: |
358 if ord(ch) > 127 and utf8: |
360 if ord(ch) > 127 and utf8: |
359 utf8Ch += ch |
361 utf8Ch += ch |
360 if utf8Len == 0: |
362 if utf8Len == 0: |
361 if (utf8Ch[0] & 0xF0) == 0xF0: |
363 if (utf8Ch[0] & 0xF0) == 0xF0: |
433 colorScheme, ok = QInputDialog.getItem( |
435 colorScheme, ok = QInputDialog.getItem( |
434 None, |
436 None, |
435 self.tr("Markdown Export"), |
437 self.tr("Markdown Export"), |
436 self.tr("Select color scheme:"), |
438 self.tr("Select color scheme:"), |
437 colorSchemes, |
439 colorSchemes, |
438 0, False) |
440 0, |
|
441 False, |
|
442 ) |
439 if ok: |
443 if ok: |
440 colorSchemeIndex = colorSchemes.index(colorScheme) |
444 colorSchemeIndex = colorSchemes.index(colorScheme) |
441 else: |
445 else: |
442 # light background as default |
446 # light background as default |
443 colorSchemeIndex = 0 |
447 colorSchemeIndex = 0 |
444 with EricOverrideCursor(): |
448 with EricOverrideCursor(): |
445 html = self.__generateFromMarkdown(colorSchemeIndex == 1) |
449 html = self.__generateFromMarkdown(colorSchemeIndex == 1) |
446 elif ( |
450 elif ( |
447 extension in Preferences.getEditor( |
451 extension in Preferences.getEditor("PreviewRestFileNameExtensions") |
448 "PreviewRestFileNameExtensions") or |
452 or self.editor.getLanguage().lower() == "restructuredtext" |
449 self.editor.getLanguage().lower() == "restructuredtext" |
|
450 ): |
453 ): |
451 # export ReST to HTML |
454 # export ReST to HTML |
452 with EricOverrideCursor(): |
455 with EricOverrideCursor(): |
453 html = self.__generateFromReSTDocutils() |
456 html = self.__generateFromReSTDocutils() |
454 else: |
457 else: |
455 tabSize = self.editor.getEditorConfig("TabWidth") |
458 tabSize = self.editor.getEditorConfig("TabWidth") |
456 if tabSize == 0: |
459 if tabSize == 0: |
457 tabSize = 4 |
460 tabSize = 4 |
458 wysiwyg = Preferences.getEditorExporter("HTML/WYSIWYG") |
461 wysiwyg = Preferences.getEditorExporter("HTML/WYSIWYG") |
459 folding = Preferences.getEditorExporter("HTML/Folding") |
462 folding = Preferences.getEditorExporter("HTML/Folding") |
460 onlyStylesUsed = Preferences.getEditorExporter( |
463 onlyStylesUsed = Preferences.getEditorExporter("HTML/OnlyStylesUsed") |
461 "HTML/OnlyStylesUsed") |
464 titleFullPath = Preferences.getEditorExporter("HTML/FullPathAsTitle") |
462 titleFullPath = Preferences.getEditorExporter( |
|
463 "HTML/FullPathAsTitle") |
|
464 tabs = Preferences.getEditorExporter("HTML/UseTabs") |
465 tabs = Preferences.getEditorExporter("HTML/UseTabs") |
465 |
466 |
466 with EricOverrideCursor(): |
467 with EricOverrideCursor(): |
467 generator = HTMLGenerator(self.editor) |
468 generator = HTMLGenerator(self.editor) |
468 html = generator.generate( |
469 html = generator.generate( |
469 tabSize=tabSize, |
470 tabSize=tabSize, |
470 useTabs=tabs, |
471 useTabs=tabs, |
471 wysiwyg=wysiwyg, |
472 wysiwyg=wysiwyg, |
472 folding=folding, |
473 folding=folding, |
473 onlyStylesUsed=onlyStylesUsed, |
474 onlyStylesUsed=onlyStylesUsed, |
474 titleFullPath=titleFullPath |
475 titleFullPath=titleFullPath, |
475 ) |
476 ) |
476 |
477 |
477 if html: |
478 if html: |
478 with EricOverrideCursor(), open(filename, "w", encoding="utf-8" |
479 with EricOverrideCursor(), open(filename, "w", encoding="utf-8") as f: |
479 ) as f: |
|
480 try: |
480 try: |
481 f.write(html) |
481 f.write(html) |
482 except OSError as err: |
482 except OSError as err: |
483 EricMessageBox.critical( |
483 EricMessageBox.critical( |
484 self.editor, |
484 self.editor, |
485 self.tr("Export source"), |
485 self.tr("Export source"), |
486 self.tr( |
486 self.tr( |
487 """<p>The source could not be exported to""" |
487 """<p>The source could not be exported to""" |
488 """ <b>{0}</b>.</p><p>Reason: {1}</p>""") |
488 """ <b>{0}</b>.</p><p>Reason: {1}</p>""" |
489 .format(filename, str(err))) |
489 ).format(filename, str(err)), |
|
490 ) |
490 else: |
491 else: |
491 EricMessageBox.critical( |
492 EricMessageBox.critical( |
492 self.editor, |
493 self.editor, |
493 self.tr("Export source"), |
494 self.tr("Export source"), |
494 self.tr( |
495 self.tr( |
495 """<p>The source could not be exported to""" |
496 """<p>The source could not be exported to""" |
496 """ <b>{0}</b>.</p><p>Reason: No HTML code""" |
497 """ <b>{0}</b>.</p><p>Reason: No HTML code""" |
497 """ generated.</p>""") |
498 """ generated.</p>""" |
498 .format(filename)) |
499 ).format(filename), |
499 |
500 ) |
|
501 |
500 def __generateFromReSTDocutils(self): |
502 def __generateFromReSTDocutils(self): |
501 """ |
503 """ |
502 Private method to convert ReST text into HTML using 'docutils'. |
504 Private method to convert ReST text into HTML using 'docutils'. |
503 |
505 |
504 @return processed HTML (string) |
506 @return processed HTML (string) |
505 """ |
507 """ |
506 if 'sphinx' in sys.modules: |
508 if "sphinx" in sys.modules: |
507 # Make sure any Sphinx polution of docutils has been removed. |
509 # Make sure any Sphinx polution of docutils has been removed. |
508 unloadKeys = [k for k in sys.modules.keys() |
510 unloadKeys = [ |
509 if k.startswith(('docutils', 'sphinx'))] |
511 k for k in sys.modules.keys() if k.startswith(("docutils", "sphinx")) |
|
512 ] |
510 for key in unloadKeys: |
513 for key in unloadKeys: |
511 sys.modules.pop(key) |
514 sys.modules.pop(key) |
512 |
515 |
513 try: |
516 try: |
514 import docutils.core # __IGNORE_EXCEPTION__ |
517 import docutils.core # __IGNORE_EXCEPTION__ |
515 except ImportError: |
518 except ImportError: |
516 EricMessageBox.critical( |
519 EricMessageBox.critical( |
517 self.editor, |
520 self.editor, |
518 self.tr("Export source"), |
521 self.tr("Export source"), |
519 self.tr( |
522 self.tr( |
520 """<p>ReStructuredText export requires the""" |
523 """<p>ReStructuredText export requires the""" |
521 """ <b>python-docutils</b> package.<br/>Install it with""" |
524 """ <b>python-docutils</b> package.<br/>Install it with""" |
522 """ your package manager, 'pip install docutils' or see""" |
525 """ your package manager, 'pip install docutils' or see""" |
523 """ <a href="http://pypi.python.org/pypi/docutils">""" |
526 """ <a href="http://pypi.python.org/pypi/docutils">""" |
524 """this page.</a></p>""") |
527 """this page.</a></p>""" |
|
528 ), |
525 ) |
529 ) |
526 return "" |
530 return "" |
527 |
531 |
528 htmlFormat = Preferences.getEditor( |
532 htmlFormat = Preferences.getEditor("PreviewRestDocutilsHTMLFormat").lower() |
529 "PreviewRestDocutilsHTMLFormat").lower() |
|
530 # redirect sys.stderr because we are not interested in it here |
533 # redirect sys.stderr because we are not interested in it here |
531 origStderr = sys.stderr |
534 origStderr = sys.stderr |
532 sys.stderr = io.StringIO() |
535 sys.stderr = io.StringIO() |
533 html = docutils.core.publish_string( |
536 html = docutils.core.publish_string( |
534 self.editor.text(), writer_name=htmlFormat).decode("utf-8") |
537 self.editor.text(), writer_name=htmlFormat |
|
538 ).decode("utf-8") |
535 sys.stderr = origStderr |
539 sys.stderr = origStderr |
536 return html |
540 return html |
537 |
541 |
538 def __generateFromMarkdown(self, useDarkScheme): |
542 def __generateFromMarkdown(self, useDarkScheme): |
539 """ |
543 """ |
540 Private method to convert Markdown text into HTML. |
544 Private method to convert Markdown text into HTML. |
541 |
545 |
542 @param useDarkScheme flag indicating to export using a dark color |
546 @param useDarkScheme flag indicating to export using a dark color |
543 scheme |
547 scheme |
544 @type bool |
548 @type bool |
545 @return processed HTML |
549 @return processed HTML |
546 @rtype str |
550 @rtype str |
547 """ |
551 """ |
548 try: |
552 try: |
549 import markdown # __IGNORE_EXCEPTION__ |
553 import markdown # __IGNORE_EXCEPTION__ |
550 except ImportError: |
554 except ImportError: |
551 EricMessageBox.critical( |
555 EricMessageBox.critical( |
552 self.editor, |
556 self.editor, |
553 self.tr("Export source"), |
557 self.tr("Export source"), |
554 self.tr( |
558 self.tr( |
555 """<p>Markdown export requires the <b>python-markdown""" |
559 """<p>Markdown export requires the <b>python-markdown""" |
556 """</b> package.<br/>Install it with your package""" |
560 """</b> package.<br/>Install it with your package""" |
557 """ manager, 'pip install docutils' or see """ |
561 """ manager, 'pip install docutils' or see """ |
558 """<a href="http://pythonhosted.org/Markdown/install""" |
562 """<a href="http://pythonhosted.org/Markdown/install""" |
559 """.html"> installation instructions.</a></p>""") |
563 """.html"> installation instructions.</a></p>""" |
|
564 ), |
560 ) |
565 ) |
561 return "" |
566 return "" |
562 |
567 |
563 from UI.Previewers import PreviewerHTMLStyles |
568 from UI.Previewers import PreviewerHTMLStyles |
564 from UI.Previewers import MarkdownExtensions |
569 from UI.Previewers import MarkdownExtensions |
565 |
570 |
566 extensions = [] |
571 extensions = [] |
567 |
572 |
568 text = self.editor.text() |
573 text = self.editor.text() |
569 |
574 |
570 mermaidNeeded = False |
575 mermaidNeeded = False |
571 if ( |
576 if Preferences.getEditor( |
572 Preferences.getEditor("PreviewMarkdownMermaid") and |
577 "PreviewMarkdownMermaid" |
573 MarkdownExtensions.MermaidRegexFullText.search(text) |
578 ) and MarkdownExtensions.MermaidRegexFullText.search(text): |
574 ): |
|
575 extensions.append(MarkdownExtensions.MermaidExtension()) |
579 extensions.append(MarkdownExtensions.MermaidExtension()) |
576 mermaidNeeded = True |
580 mermaidNeeded = True |
577 |
581 |
578 if Preferences.getEditor("PreviewMarkdownNLtoBR"): |
582 if Preferences.getEditor("PreviewMarkdownNLtoBR"): |
579 extensions.append('nl2br') |
583 extensions.append("nl2br") |
580 |
584 |
581 pyMdown = False |
585 pyMdown = False |
582 if Preferences.getEditor("PreviewMarkdownUsePyMdownExtensions"): |
586 if Preferences.getEditor("PreviewMarkdownUsePyMdownExtensions"): |
583 with contextlib.suppress(ImportError): |
587 with contextlib.suppress(ImportError): |
584 import pymdownx # __IGNORE_EXCEPTION__ __IGNORE_WARNING__ |
588 import pymdownx # __IGNORE_EXCEPTION__ __IGNORE_WARNING__ |
|
589 |
585 # PyPI package is 'pymdown-extensions' |
590 # PyPI package is 'pymdown-extensions' |
586 |
591 |
587 extensions.extend([ |
592 extensions.extend( |
588 'toc', |
593 [ |
589 'pymdownx.extra', 'pymdownx.caret', 'pymdownx.emoji', |
594 "toc", |
590 'pymdownx.mark', 'pymdownx.tilde', 'pymdownx.keys', |
595 "pymdownx.extra", |
591 'pymdownx.tasklist', 'pymdownx.smartsymbols', |
596 "pymdownx.caret", |
592 ]) |
597 "pymdownx.emoji", |
|
598 "pymdownx.mark", |
|
599 "pymdownx.tilde", |
|
600 "pymdownx.keys", |
|
601 "pymdownx.tasklist", |
|
602 "pymdownx.smartsymbols", |
|
603 ] |
|
604 ) |
593 pyMdown = True |
605 pyMdown = True |
594 |
606 |
595 if not pyMdown: |
607 if not pyMdown: |
596 extensions.extend(['extra', 'toc']) |
608 extensions.extend(["extra", "toc"]) |
597 |
609 |
598 # version 2.0 supports only extension names, not instances |
610 # version 2.0 supports only extension names, not instances |
599 if ( |
611 if markdown.version_info[0] > 2 or ( |
600 markdown.version_info[0] > 2 or |
612 markdown.version_info[0] == 2 and markdown.version_info[1] > 0 |
601 (markdown.version_info[0] == 2 and |
|
602 markdown.version_info[1] > 0) |
|
603 ): |
613 ): |
604 extensions.append(MarkdownExtensions.SimplePatternExtension()) |
614 extensions.append(MarkdownExtensions.SimplePatternExtension()) |
605 |
615 |
606 if Preferences.getEditor("PreviewMarkdownMathJax"): |
616 if Preferences.getEditor("PreviewMarkdownMathJax"): |
607 mathjax = ( |
617 mathjax = ( |
608 "<script type='text/javascript' id='MathJax-script' async" |
618 "<script type='text/javascript' id='MathJax-script' async" |
609 " src='https://cdn.jsdelivr.net/npm/mathjax@3/es5/" |
619 " src='https://cdn.jsdelivr.net/npm/mathjax@3/es5/" |
610 "tex-chtml.js'>\n" |
620 "tex-chtml.js'>\n" |
611 "</script>\n" |
621 "</script>\n" |
612 ) |
622 ) |
613 # prepare text for mathjax |
623 # prepare text for mathjax |
614 text = ( |
624 text = ( |
615 text |
625 text.replace(r"\(", r"\\(") |
616 .replace(r"\(", r"\\(") |
|
617 .replace(r"\)", r"\\)") |
626 .replace(r"\)", r"\\)") |
618 .replace(r"\[", r"\\[") |
627 .replace(r"\[", r"\\[") |
619 .replace(r"\]", r"\\]") |
628 .replace(r"\]", r"\\]") |
620 ) |
629 ) |
621 else: |
630 else: |
622 mathjax = "" |
631 mathjax = "" |
623 |
632 |
624 if mermaidNeeded: |
633 if mermaidNeeded: |
625 mermaid = ( |
634 mermaid = ( |
626 "<script type='text/javascript' id='Mermaid-script'" |
635 "<script type='text/javascript' id='Mermaid-script'" |
627 " src='https://unpkg.com/mermaid@8/dist/mermaid.min.js'>\n" |
636 " src='https://unpkg.com/mermaid@8/dist/mermaid.min.js'>\n" |
628 "</script>\n" |
637 "</script>\n" |
642 "});</script>" |
651 "});</script>" |
643 ) |
652 ) |
644 else: |
653 else: |
645 mermaid = "" |
654 mermaid = "" |
646 mermaid_initialize = "" |
655 mermaid_initialize = "" |
647 |
656 |
648 htmlFormat = Preferences.getEditor("PreviewMarkdownHTMLFormat").lower() |
657 htmlFormat = Preferences.getEditor("PreviewMarkdownHTMLFormat").lower() |
649 body = markdown.markdown(text, extensions=extensions, |
658 body = markdown.markdown(text, extensions=extensions, output_format=htmlFormat) |
650 output_format=htmlFormat) |
|
651 style = ( |
659 style = ( |
652 (PreviewerHTMLStyles.css_markdown_dark + |
660 ( |
653 PreviewerHTMLStyles.css_pygments_dark) |
661 PreviewerHTMLStyles.css_markdown_dark |
654 if useDarkScheme else |
662 + PreviewerHTMLStyles.css_pygments_dark |
655 (PreviewerHTMLStyles.css_markdown_light + |
663 ) |
656 PreviewerHTMLStyles.css_pygments_light) |
664 if useDarkScheme |
|
665 else ( |
|
666 PreviewerHTMLStyles.css_markdown_light |
|
667 + PreviewerHTMLStyles.css_pygments_light |
|
668 ) |
657 ) |
669 ) |
658 |
670 |
659 if htmlFormat == "xhtml1": |
671 if htmlFormat == "xhtml1": |
660 head = ( |
672 head = ( |
661 '''<!DOCTYPE html PUBLIC "-//W3C//DTD''' |
673 """<!DOCTYPE html PUBLIC "-//W3C//DTD""" |
662 ''' XHTML 1.0 Transitional//EN"\n''' |
674 """ XHTML 1.0 Transitional//EN"\n""" |
663 ''' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional''' |
675 """ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional""" |
664 '''.dtd">\n''' |
676 """.dtd">\n""" |
665 '''<html xmlns="http://www.w3.org/1999/xhtml">\n''' |
677 """<html xmlns="http://www.w3.org/1999/xhtml">\n""" |
666 ) |
678 ) |
667 elif htmlFormat == "html5": |
679 elif htmlFormat == "html5": |
668 head = ( |
680 head = """<!DOCTYPE html>\n""" """<html lang="EN">\n""" |
669 '''<!DOCTYPE html>\n''' |
|
670 '''<html lang="EN">\n''' |
|
671 ) |
|
672 else: |
681 else: |
673 head = '<html lang="EN">\n' |
682 head = '<html lang="EN">\n' |
674 head += '''<head>\n''' |
683 head += """<head>\n""" |
675 if Preferences.getEditorExporter("HTML/FullPathAsTitle"): |
684 if Preferences.getEditorExporter("HTML/FullPathAsTitle"): |
676 head += '''<title>{0}</title>\n'''.format( |
685 head += """<title>{0}</title>\n""".format(self.editor.getFileName()) |
677 self.editor.getFileName()) |
686 else: |
678 else: |
687 head += """<title>{0}</title>\n""".format( |
679 head += '''<title>{0}</title>\n'''.format( |
688 os.path.basename(self.editor.getFileName()) |
680 os.path.basename(self.editor.getFileName())) |
689 ) |
681 head += ( |
690 head += ( |
682 '''<meta name="Generator" content="eric" />\n''' |
691 """<meta name="Generator" content="eric" />\n""" |
683 '''<meta http-equiv="Content-Type" ''' |
692 """<meta http-equiv="Content-Type" """ |
684 '''content="text/html; charset=utf-8" />\n''' |
693 """content="text/html; charset=utf-8" />\n""" |
685 '''{0}''' |
694 """{0}""" |
686 '''{1}''' |
695 """{1}""" |
687 '''<style type="text/css">''' |
696 """<style type="text/css">""" |
688 '''{2}''' |
697 """{2}""" |
689 '''</style>\n''' |
698 """</style>\n""" |
690 '''</head>\n''' |
699 """</head>\n""" |
691 '''<body>\n''' |
700 """<body>\n""" |
692 ).format(mathjax, mermaid, style) |
701 ).format(mathjax, mermaid, style) |
693 |
702 |
694 foot = '''\n</body>\n</html>\n''' |
703 foot = """\n</body>\n</html>\n""" |
695 |
704 |
696 return head + body + mermaid_initialize + foot |
705 return head + body + mermaid_initialize + foot |