18 |
18 |
19 from .ExporterBase import ExporterBase |
19 from .ExporterBase import ExporterBase |
20 |
20 |
21 import Preferences |
21 import Preferences |
22 import Utilities |
22 import Utilities |
|
23 |
|
24 class HTMLGenerator(object): |
|
25 """ |
|
26 Class implementing an HTML generator for exporting source code. |
|
27 """ |
|
28 def __init__(self, editor): |
|
29 """ |
|
30 Constructor |
|
31 |
|
32 @param editor reference to the editor object (QScintilla.Editor.Editor) |
|
33 """ |
|
34 self.editor = editor |
|
35 |
|
36 def generate(self, tabSize = 4, useTabs = False, wysiwyg = True, folding = False, |
|
37 onlyStylesUsed = False, titleFullPath = False): |
|
38 """ |
|
39 Public method to generate HTML for the source editor. |
|
40 |
|
41 @keyparam tabSize size of tabs (integer) |
|
42 @keyparam useTabs flag indicating the use of tab characters (boolean) |
|
43 @keyparam wysiwyg flag indicating colorization (boolean) |
|
44 @keyparam folding flag indicating usage of fold markers |
|
45 @keyparam onlyStylesUsed flag indicating to include only style definitions |
|
46 for styles used in the source (boolean) |
|
47 @keyparam titleFullPath flag indicating to include the full file path |
|
48 in the title tag (boolean) |
|
49 @return generated HTML text (string) |
|
50 """ |
|
51 self.editor.recolor(0, -1) |
|
52 |
|
53 lengthDoc = self.editor.length() |
|
54 styleIsUsed = {} |
|
55 if onlyStylesUsed: |
|
56 for index in range(QsciScintilla.STYLE_MAX + 1): |
|
57 styleIsUsed[index] = False |
|
58 # check the used styles |
|
59 pos = 0 |
|
60 while pos < lengthDoc: |
|
61 styleIsUsed[self.editor.styleAt(pos) & 0x7F] = True |
|
62 pos += 1 |
|
63 else: |
|
64 for index in range(QsciScintilla.STYLE_MAX + 1): |
|
65 styleIsUsed[index] = True |
|
66 styleIsUsed[QsciScintilla.STYLE_DEFAULT] = True |
|
67 |
|
68 html = '''<!DOCTYPE html PUBLIC "-//W3C//DTD''' \ |
|
69 ''' XHTML 1.0 Transitional//EN"\n''' \ |
|
70 ''' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n''' \ |
|
71 '''<html xmlns="http://www.w3.org/1999/xhtml">\n''' \ |
|
72 '''<head>\n''' |
|
73 if titleFullPath: |
|
74 html += '''<title>{0}</title>\n'''.format(self.editor.getFileName()) |
|
75 else: |
|
76 html += '''<title>{0}</title>\n'''.format( |
|
77 os.path.basename(self.editor.getFileName())) |
|
78 html += '''<meta name="Generator" content="eric5" />\n''' \ |
|
79 '''<meta http-equiv="Content-Type" ''' \ |
|
80 '''content="text/html; charset=utf-8" />\n''' |
|
81 if folding: |
|
82 html += '''<script language="JavaScript" type="text/javascript">\n''' \ |
|
83 '''<!--\n''' \ |
|
84 '''function symbol(id, sym) {\n''' \ |
|
85 ''' if (id.textContent == undefined) {\n''' \ |
|
86 ''' id.innerText = sym;\n''' \ |
|
87 ''' } else {\n''' \ |
|
88 ''' id.textContent = sym;\n''' \ |
|
89 ''' }\n''' \ |
|
90 '''}\n''' \ |
|
91 '''function toggle(id) {\n''' \ |
|
92 ''' var thislayer = document.getElementById('ln' + id);\n''' \ |
|
93 ''' id -= 1;\n''' \ |
|
94 ''' var togline = document.getElementById('hd' + id);\n''' \ |
|
95 ''' var togsym = document.getElementById('bt' + id);\n''' \ |
|
96 ''' if (thislayer.style.display == 'none') {\n''' \ |
|
97 ''' thislayer.style.display = 'block';\n''' \ |
|
98 ''' togline.style.textDecoration = 'none';\n''' \ |
|
99 ''' symbol(togsym, '- ');\n''' \ |
|
100 ''' } else {\n''' \ |
|
101 ''' thislayer.style.display = 'none';\n''' \ |
|
102 ''' togline.style.textDecoration = 'underline';\n''' \ |
|
103 ''' symbol(togsym, '+ ');\n''' \ |
|
104 ''' }\n''' \ |
|
105 '''}\n''' \ |
|
106 '''//-->\n''' \ |
|
107 '''</script>\n''' |
|
108 |
|
109 lex = self.editor.getLexer() |
|
110 if lex: |
|
111 bgColour = lex.paper(QsciScintilla.STYLE_DEFAULT).name() |
|
112 else: |
|
113 bgColour = self.editor.paper().name() |
|
114 |
|
115 html += '''<style type="text/css">\n''' |
|
116 if lex: |
|
117 istyle = 0 |
|
118 while istyle <= QsciScintilla.STYLE_MAX: |
|
119 if (istyle <= QsciScintilla.STYLE_DEFAULT or \ |
|
120 istyle > QsciScintilla.STYLE_LASTPREDEFINED) and \ |
|
121 styleIsUsed[istyle]: |
|
122 if lex.description(istyle) or \ |
|
123 istyle == QsciScintilla.STYLE_DEFAULT: |
|
124 font = lex.font(istyle) |
|
125 colour = lex.color(istyle) |
|
126 paper = lex.paper(istyle) |
|
127 if istyle == QsciScintilla.STYLE_DEFAULT: |
|
128 html += '''span {\n''' |
|
129 else: |
|
130 html += '''.S{0:d} {{\n'''.format(istyle) |
|
131 if font.italic(): |
|
132 html += ''' font-style: italic;\n''' |
|
133 if font.bold(): |
|
134 html += ''' font-weight: bold;\n''' |
|
135 if wysiwyg: |
|
136 html += ''' font-family: '{0}';\n'''.format( |
|
137 font.family()) |
|
138 html += ''' color: {0};\n'''.format(colour.name()) |
|
139 if istyle != QsciScintilla.STYLE_DEFAULT and \ |
|
140 bgColour != paper.name(): |
|
141 html += ''' background: {0};\n'''.format( |
|
142 paper.name()) |
|
143 html += ''' text-decoration: inherit;\n''' |
|
144 if wysiwyg: |
|
145 html += ''' font-size: {0:d}pt;\n'''.format( |
|
146 QFontInfo(font).pointSize()) |
|
147 html += '''}\n''' |
|
148 else: |
|
149 styleIsUsed[istyle] = False |
|
150 istyle += 1 |
|
151 else: |
|
152 colour = self.editor.color() |
|
153 paper = self.editor.paper() |
|
154 font = Preferences.getEditorOtherFonts("DefaultFont") |
|
155 html += '''.S0 {\n''' |
|
156 if font.italic(): |
|
157 html += ''' font-style: italic;\n''' |
|
158 if font.bold(): |
|
159 html += ''' font-weight: bold;\n''' |
|
160 if wysiwyg: |
|
161 html += ''' font-family: '{0}';\n'''.format(font.family()) |
|
162 html += ''' color: {0};\n'''.format(colour.name()) |
|
163 if bgColour != paper.name(): |
|
164 html += ''' background: {0};\n'''.format(paper.name()) |
|
165 html += ''' text-decoration: inherit;\n''' |
|
166 if wysiwyg: |
|
167 html += ''' font-size: {0:d}pt;\n'''.format( |
|
168 QFontInfo(font).pointSize()) |
|
169 html += '''}\n''' |
|
170 html += '''</style>\n''' |
|
171 html += '''</head>\n''' |
|
172 |
|
173 html += '''<body bgcolor="{0}">\n'''.format(bgColour) |
|
174 line = self.editor.lineAt(0) |
|
175 level = self.editor.foldLevelAt(line) - QsciScintilla.SC_FOLDLEVELBASE |
|
176 levelStack = [level] |
|
177 styleCurrent = self.editor.styleAt(0) |
|
178 inStyleSpan = False |
|
179 inFoldSpan = False |
|
180 # Global span for default attributes |
|
181 if wysiwyg: |
|
182 html += '''<span>''' |
|
183 else: |
|
184 html += '''<pre>''' |
|
185 |
|
186 if folding: |
|
187 if self.editor.foldFlagsAt(line) & \ |
|
188 QsciScintilla.SC_FOLDLEVELHEADERFLAG: |
|
189 html += '''<span id="hd{0:d}" onclick="toggle('{1:d}')">'''\ |
|
190 .format(line, line + 1) |
|
191 html += '''<span id="bt{0:d}">- </span>'''.format(line) |
|
192 inFoldSpan = True |
|
193 else: |
|
194 html += ''' ''' |
|
195 |
|
196 if styleIsUsed[styleCurrent]: |
|
197 html += '''<span class="S{0:0d}">'''.format(styleCurrent) |
|
198 inStyleSpan = True |
|
199 |
|
200 column = 0 |
|
201 pos = 0 |
|
202 utf8 = self.editor.isUtf8() |
|
203 utf8Ch = b"" |
|
204 utf8Len = 0 |
|
205 |
|
206 while pos < lengthDoc: |
|
207 ch = self.editor.byteAt(pos) |
|
208 style = self.editor.styleAt(pos) |
|
209 if style != styleCurrent: |
|
210 if inStyleSpan: |
|
211 html += '''</span>''' |
|
212 inStyleSpan = False |
|
213 if ch not in [b'\r', b'\n']: # no need of a span for the EOL |
|
214 if styleIsUsed[style]: |
|
215 html += '''<span class="S{0:d}">'''.format(style) |
|
216 inStyleSpan = True |
|
217 styleCurrent = style |
|
218 |
|
219 if ch == b' ': |
|
220 if wysiwyg: |
|
221 prevCh = b'' |
|
222 if column == 0: |
|
223 # at start of line, must put a |
|
224 # because regular space will be collapsed |
|
225 prevCh = b' ' |
|
226 while pos < lengthDoc and self.editor.byteAt(pos) == b' ': |
|
227 if prevCh != b' ': |
|
228 html += ' ' |
|
229 else: |
|
230 html += ''' ''' |
|
231 prevCh = self.editor.byteAt(pos) |
|
232 pos += 1 |
|
233 column += 1 |
|
234 pos -= 1 |
|
235 # the last incrementation will be done by the outer loop |
|
236 else: |
|
237 html += ' ' |
|
238 column += 1 |
|
239 elif ch == b'\t': |
|
240 ts = tabSize - (column % tabSize) |
|
241 if wysiwyg: |
|
242 html += ''' ''' * ts |
|
243 column += ts |
|
244 else: |
|
245 if tabs: |
|
246 html += '\t' |
|
247 column += 1 |
|
248 else: |
|
249 html += ' ' * ts |
|
250 column += ts |
|
251 elif ch in [b'\r', b'\n']: |
|
252 if inStyleSpan: |
|
253 html += '''</span>''' |
|
254 inStyleSpan = False |
|
255 if inFoldSpan: |
|
256 html += '''</span>''' |
|
257 inFoldSpan = False |
|
258 if ch == b'\r' and self.editor.byteAt(pos + 1) == b'\n': |
|
259 pos += 1 # CR+LF line ending, skip the "extra" EOL char |
|
260 column = 0 |
|
261 if wysiwyg: |
|
262 html += '''<br />''' |
|
263 |
|
264 styleCurrent = self.editor.styleAt(pos + 1) |
|
265 if folding: |
|
266 line = self.editor.lineAt(pos + 1) |
|
267 newLevel = self.editor.foldLevelAt(line) |
|
268 |
|
269 if newLevel < level: |
|
270 while levelStack[-1] > newLevel: |
|
271 html += '''</span>''' |
|
272 levelStack.pop() |
|
273 html += '\n' # here to get clean code |
|
274 if newLevel > level: |
|
275 html += '''<span id="ln{0:d}">'''.format(line) |
|
276 levelStack.append(newLevel) |
|
277 if self.editor.foldFlagsAt(line) & \ |
|
278 QsciScintilla.SC_FOLDLEVELHEADERFLAG: |
|
279 html += \ |
|
280 '''<span id="hd{0:d}" onclick="toggle('{1:d}')">'''\ |
|
281 .format(line, line + 1) |
|
282 html += '''<span id="bt{0:d}">- </span>'''.format(line) |
|
283 inFoldSpan = True |
|
284 else: |
|
285 html += ''' ''' |
|
286 level = newLevel |
|
287 else: |
|
288 html += '\n' |
|
289 |
|
290 if styleIsUsed[styleCurrent] and \ |
|
291 self.editor.byteAt(pos + 1) not in [b'\r', b'\n']: |
|
292 # We know it's the correct next style, |
|
293 # but no (empty) span for an empty line |
|
294 html += '''<span class="S{0:0d}">'''.format(styleCurrent) |
|
295 inStyleSpan = True |
|
296 else: |
|
297 if ch == b'<': |
|
298 html += '''<''' |
|
299 elif ch == b'>': |
|
300 html += '''>''' |
|
301 elif ch == b'&': |
|
302 html += '''&''' |
|
303 else: |
|
304 if ord(ch) > 127 and utf8: |
|
305 utf8Ch += ch |
|
306 if utf8Len == 0: |
|
307 if (utf8Ch[0] & 0xF0) == 0xF0: |
|
308 utf8Len = 4 |
|
309 elif (utf8Ch[0] & 0xE0) == 0xE0: |
|
310 utf8Len = 3 |
|
311 elif (utf8Ch[0] & 0xC0) == 0xC0: |
|
312 utf8Len = 2 |
|
313 column -= 1 # will be incremented again later |
|
314 elif len(utf8Ch) == utf8Len: |
|
315 ch = utf8Ch.decode('utf8') |
|
316 html += Utilities.html_encode(ch) |
|
317 utf8Ch = b"" |
|
318 utf8Len = 0 |
|
319 else: |
|
320 column -= 1 # will be incremented again later |
|
321 else: |
|
322 html += ch.decode() |
|
323 column += 1 |
|
324 |
|
325 pos += 1 |
|
326 |
|
327 if inStyleSpan: |
|
328 html += '''</span>''' |
|
329 |
|
330 if folding: |
|
331 while levelStack: |
|
332 html += '''</span>''' |
|
333 levelStack.pop() |
|
334 |
|
335 if wysiwyg: |
|
336 html += '''</span>''' |
|
337 else: |
|
338 html += '''</pre>''' |
|
339 |
|
340 html += '''</body>\n</html>\n''' |
|
341 |
|
342 return html |
23 |
343 |
24 class ExporterHTML(ExporterBase): |
344 class ExporterHTML(ExporterBase): |
25 """ |
345 """ |
26 Class implementing an exporter for HTML. |
346 Class implementing an exporter for HTML. |
27 """ |
347 """ |
43 return |
363 return |
44 |
364 |
45 try: |
365 try: |
46 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) |
366 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) |
47 QApplication.processEvents() |
367 QApplication.processEvents() |
48 |
|
49 self.editor.recolor(0, -1) |
|
50 |
368 |
51 tabSize = Preferences.getEditor("TabWidth") |
369 tabSize = Preferences.getEditor("TabWidth") |
52 if tabSize == 0: |
370 if tabSize == 0: |
53 tabSize = 4 |
371 tabSize = 4 |
54 wysiwyg = Preferences.getEditorExporter("HTML/WYSIWYG") |
372 wysiwyg = Preferences.getEditorExporter("HTML/WYSIWYG") |
55 folding = Preferences.getEditorExporter("HTML/Folding") |
373 folding = Preferences.getEditorExporter("HTML/Folding") |
56 onlyStylesUsed = Preferences.getEditorExporter("HTML/OnlyStylesUsed") |
374 onlyStylesUsed = Preferences.getEditorExporter("HTML/OnlyStylesUsed") |
57 titleFullPath = Preferences.getEditorExporter("HTML/FullPathAsTitle") |
375 titleFullPath = Preferences.getEditorExporter("HTML/FullPathAsTitle") |
58 tabs = Preferences.getEditorExporter("HTML/UseTabs") |
376 tabs = Preferences.getEditorExporter("HTML/UseTabs") |
59 |
377 |
60 lengthDoc = self.editor.length() |
378 generator = HTMLGenerator(self.editor) |
61 styleIsUsed = {} |
379 html = generator.generate( |
62 if onlyStylesUsed: |
380 tabSize = tabSize, |
63 for index in range(QsciScintilla.STYLE_MAX + 1): |
381 useTabs = tabs, |
64 styleIsUsed[index] = False |
382 wysiwyg = wysiwyg, |
65 # check the used styles |
383 folding = folding, |
66 pos = 0 |
384 onlyStylesUsed = onlyStylesUsed, |
67 while pos < lengthDoc: |
385 titleFullPath = titleFullPath |
68 styleIsUsed[self.editor.styleAt(pos) & 0x7F] = True |
386 ) |
69 pos += 1 |
|
70 else: |
|
71 for index in range(QsciScintilla.STYLE_MAX + 1): |
|
72 styleIsUsed[index] = True |
|
73 styleIsUsed[QsciScintilla.STYLE_DEFAULT] = True |
|
74 |
387 |
75 try: |
388 try: |
76 f = open(filename, "w", encoding = "utf-8") |
389 f = open(filename, "w", encoding = "utf-8") |
77 |
390 f.write(html) |
78 f.write( |
|
79 '''<!DOCTYPE html PUBLIC "-//W3C//DTD''' |
|
80 ''' XHTML 1.0 Transitional//EN"\n''') |
|
81 f.write( |
|
82 ''' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n''') |
|
83 f.write('''<html xmlns="http://www.w3.org/1999/xhtml">\n''') |
|
84 f.write('''<head>\n''') |
|
85 if titleFullPath: |
|
86 f.write('''<title>{0}</title>\n'''.format(self.editor.getFileName())) |
|
87 else: |
|
88 f.write('''<title>{0}</title>\n'''.format( |
|
89 os.path.basename(self.editor.getFileName()))) |
|
90 f.write('''<meta name="Generator" content="eric5" />\n''') |
|
91 f.write('''<meta http-equiv="Content-Type" ''' |
|
92 '''content="text/html; charset=utf-8" />\n''') |
|
93 if folding: |
|
94 f.write('''<script language="JavaScript" type="text/javascript">\n''' |
|
95 '''<!--\n''' |
|
96 '''function symbol(id, sym) {\n''' |
|
97 ''' if (id.textContent == undefined) {\n''' |
|
98 ''' id.innerText = sym;\n''' |
|
99 ''' } else {\n''' |
|
100 ''' id.textContent = sym;\n''' |
|
101 ''' }\n''' |
|
102 '''}\n''' |
|
103 '''function toggle(id) {\n''' |
|
104 ''' var thislayer = document.getElementById('ln' + id);\n''' |
|
105 ''' id -= 1;\n''' |
|
106 ''' var togline = document.getElementById('hd' + id);\n''' |
|
107 ''' var togsym = document.getElementById('bt' + id);\n''' |
|
108 ''' if (thislayer.style.display == 'none') {\n''' |
|
109 ''' thislayer.style.display = 'block';\n''' |
|
110 ''' togline.style.textDecoration = 'none';\n''' |
|
111 ''' symbol(togsym, '- ');\n''' |
|
112 ''' } else {\n''' |
|
113 ''' thislayer.style.display = 'none';\n''' |
|
114 ''' togline.style.textDecoration = 'underline';\n''' |
|
115 ''' symbol(togsym, '+ ');\n''' |
|
116 ''' }\n''' |
|
117 '''}\n''' |
|
118 '''//-->\n''' |
|
119 '''</script>\n''' |
|
120 ) |
|
121 |
|
122 lex = self.editor.getLexer() |
|
123 if lex: |
|
124 bgColour = lex.paper(QsciScintilla.STYLE_DEFAULT).name() |
|
125 else: |
|
126 bgColour = self.editor.paper().name() |
|
127 |
|
128 f.write('''<style type="text/css">\n''') |
|
129 if lex: |
|
130 istyle = 0 |
|
131 while istyle <= QsciScintilla.STYLE_MAX: |
|
132 if (istyle <= QsciScintilla.STYLE_DEFAULT or \ |
|
133 istyle > QsciScintilla.STYLE_LASTPREDEFINED) and \ |
|
134 styleIsUsed[istyle]: |
|
135 if lex.description(istyle) or \ |
|
136 istyle == QsciScintilla.STYLE_DEFAULT: |
|
137 font = lex.font(istyle) |
|
138 colour = lex.color(istyle) |
|
139 paper = lex.paper(istyle) |
|
140 if istyle == QsciScintilla.STYLE_DEFAULT: |
|
141 f.write('''span {\n''') |
|
142 else: |
|
143 f.write('''.S{0:d} {\n'''.format(istyle)) |
|
144 if font.italic(): |
|
145 f.write(''' font-style: italic;\n''') |
|
146 if font.bold(): |
|
147 f.write(''' font-weight: bold;\n''') |
|
148 if wysiwyg: |
|
149 f.write(''' font-family: '{0}';\n'''.format( |
|
150 font.family())) |
|
151 f.write(''' color: {0};\n'''.format(colour.name())) |
|
152 if istyle != QsciScintilla.STYLE_DEFAULT and \ |
|
153 bgColour != paper.name(): |
|
154 f.write(''' background: {0};\n'''.format( |
|
155 paper.name())) |
|
156 f.write(''' text-decoration: inherit;\n''') |
|
157 if wysiwyg: |
|
158 f.write(''' font-size: {0:d}pt;\n'''.format( |
|
159 QFontInfo(font).pointSize())) |
|
160 f.write('''}\n''') |
|
161 else: |
|
162 styleIsUsed[istyle] = False |
|
163 istyle += 1 |
|
164 else: |
|
165 colour = self.editor.color() |
|
166 paper = self.editor.paper() |
|
167 font = Preferences.getEditorOtherFonts("DefaultFont") |
|
168 f.write('''.S0 {\n''') |
|
169 if font.italic(): |
|
170 f.write(''' font-style: italic;\n''') |
|
171 if font.bold(): |
|
172 f.write(''' font-weight: bold;\n''') |
|
173 if wysiwyg: |
|
174 f.write(''' font-family: '{0}';\n'''.format(font.family())) |
|
175 f.write(''' color: {0};\n'''.format(colour.name())) |
|
176 if bgColour != paper.name(): |
|
177 f.write(''' background: {0};\n'''.format(paper.name())) |
|
178 f.write(''' text-decoration: inherit;\n''') |
|
179 if wysiwyg: |
|
180 f.write(''' font-size: {0:d}pt;\n'''.format( |
|
181 QFontInfo(font).pointSize())) |
|
182 f.write('''}\n''') |
|
183 f.write('''</style>\n''') |
|
184 f.write('''</head>\n''') |
|
185 |
|
186 f.write('''<body bgcolor="{0}">\n'''.format(bgColour)) |
|
187 line = self.editor.lineAt(0) |
|
188 level = self.editor.foldLevelAt(line) - QsciScintilla.SC_FOLDLEVELBASE |
|
189 levelStack = [level] |
|
190 styleCurrent = self.editor.styleAt(0) |
|
191 inStyleSpan = False |
|
192 inFoldSpan = False |
|
193 # Global span for default attributes |
|
194 if wysiwyg: |
|
195 f.write('''<span>''') |
|
196 else: |
|
197 f.write('''<pre>''') |
|
198 |
|
199 if folding: |
|
200 if self.editor.foldFlagsAt(line) & \ |
|
201 QsciScintilla.SC_FOLDLEVELHEADERFLAG: |
|
202 f.write('''<span id="hd{0:d}" onclick="toggle('{1:d}')">'''\ |
|
203 .format(line, line + 1)) |
|
204 f.write('''<span id="bt{0:d}">- </span>'''.format(line)) |
|
205 inFoldSpan = True |
|
206 else: |
|
207 f.write(''' ''') |
|
208 |
|
209 if styleIsUsed[styleCurrent]: |
|
210 f.write('''<span class="S{0:0d}">'''.format(styleCurrent)) |
|
211 inStyleSpan = True |
|
212 |
|
213 column = 0 |
|
214 pos = 0 |
|
215 utf8 = self.editor.isUtf8() |
|
216 utf8Ch = b"" |
|
217 utf8Len = 0 |
|
218 |
|
219 while pos < lengthDoc: |
|
220 ch = self.editor.byteAt(pos) |
|
221 style = self.editor.styleAt(pos) |
|
222 if style != styleCurrent: |
|
223 if inStyleSpan: |
|
224 f.write('''</span>''') |
|
225 inStyleSpan = False |
|
226 if ch not in [b'\r', b'\n']: # no need of a span for the EOL |
|
227 if styleIsUsed[style]: |
|
228 f.write('''<span class="S{0:d}">'''.format(style)) |
|
229 inStyleSpan = True |
|
230 styleCurrent = style |
|
231 |
|
232 if ch == b' ': |
|
233 if wysiwyg: |
|
234 prevCh = b'' |
|
235 if column == 0: |
|
236 # at start of line, must put a |
|
237 # because regular space will be collapsed |
|
238 prevCh = b' ' |
|
239 while pos < lengthDoc and self.editor.byteAt(pos) == b' ': |
|
240 if prevCh != b' ': |
|
241 f.write(' ') |
|
242 else: |
|
243 f.write(''' ''') |
|
244 prevCh = self.editor.byteAt(pos) |
|
245 pos += 1 |
|
246 column += 1 |
|
247 pos -= 1 |
|
248 # the last incrementation will be done by the outer loop |
|
249 else: |
|
250 f.write(' ') |
|
251 column += 1 |
|
252 elif ch == b'\t': |
|
253 ts = tabSize - (column % tabSize) |
|
254 if wysiwyg: |
|
255 f.write(''' ''' * ts) |
|
256 column += ts |
|
257 else: |
|
258 if tabs: |
|
259 f.write('\t') |
|
260 column += 1 |
|
261 else: |
|
262 f.write(' ' * ts) |
|
263 column += ts |
|
264 elif ch in [b'\r', b'\n']: |
|
265 if inStyleSpan: |
|
266 f.write('''</span>''') |
|
267 inStyleSpan = False |
|
268 if inFoldSpan: |
|
269 f.write('''</span>''') |
|
270 inFoldSpan = False |
|
271 if ch == b'\r' and self.editor.byteAt(pos + 1) == b'\n': |
|
272 pos += 1 # CR+LF line ending, skip the "extra" EOL char |
|
273 column = 0 |
|
274 if wysiwyg: |
|
275 f.write('''<br />''') |
|
276 |
|
277 styleCurrent = self.editor.styleAt(pos + 1) |
|
278 if folding: |
|
279 line = self.editor.lineAt(pos + 1) |
|
280 newLevel = self.editor.foldLevelAt(line) |
|
281 |
|
282 if newLevel < level: |
|
283 while levelStack[-1] > newLevel: |
|
284 f.write('''</span>''') |
|
285 levelStack.pop() |
|
286 f.write('\n') # here to get clean code |
|
287 if newLevel > level: |
|
288 f.write('''<span id="ln{0:d}">'''.format(line)) |
|
289 levelStack.append(newLevel) |
|
290 if self.editor.foldFlagsAt(line) & \ |
|
291 QsciScintilla.SC_FOLDLEVELHEADERFLAG: |
|
292 f.write( |
|
293 '''<span id="hd{0:d}" onclick="toggle('{1:d}')">'''\ |
|
294 .format(line, line + 1)) |
|
295 f.write('''<span id="bt{0:d}">- </span>'''.format(line)) |
|
296 inFoldSpan = True |
|
297 else: |
|
298 f.write(''' ''') |
|
299 level = newLevel |
|
300 else: |
|
301 f.write('\n') |
|
302 |
|
303 if styleIsUsed[styleCurrent] and \ |
|
304 self.editor.byteAt(pos + 1) not in [b'\r', b'\n']: |
|
305 # We know it's the correct next style, |
|
306 # but no (empty) span for an empty line |
|
307 f.write('''<span class="S{0:0d}">'''.format(styleCurrent)) |
|
308 inStyleSpan = True |
|
309 else: |
|
310 if ch == b'<': |
|
311 f.write('''<''') |
|
312 elif ch == b'>': |
|
313 f.write('''>''') |
|
314 elif ch == b'&': |
|
315 f.write('''&''') |
|
316 else: |
|
317 if ord(ch) > 127 and utf8: |
|
318 utf8Ch += ch |
|
319 if utf8Len == 0: |
|
320 if (utf8Ch[0] & 0xF0) == 0xF0: |
|
321 utf8Len = 4 |
|
322 elif (utf8Ch[0] & 0xE0) == 0xE0: |
|
323 utf8Len = 3 |
|
324 elif (utf8Ch[0] & 0xC0) == 0xC0: |
|
325 utf8Len = 2 |
|
326 column -= 1 # will be incremented again later |
|
327 elif len(utf8Ch) == utf8Len: |
|
328 ch = utf8Ch.decode('utf8') |
|
329 f.write(Utilities.html_encode(ch)) |
|
330 utf8Ch = b"" |
|
331 utf8Len = 0 |
|
332 else: |
|
333 column -= 1 # will be incremented again later |
|
334 else: |
|
335 f.write(ch.decode()) |
|
336 column += 1 |
|
337 |
|
338 pos += 1 |
|
339 |
|
340 if inStyleSpan: |
|
341 f.write('''</span>''') |
|
342 |
|
343 if folding: |
|
344 while levelStack: |
|
345 f.write('''</span>''') |
|
346 levelStack.pop() |
|
347 |
|
348 if wysiwyg: |
|
349 f.write('''</span>''') |
|
350 else: |
|
351 f.write('''</pre>''') |
|
352 |
|
353 f.write('''</body>\n</html>\n''') |
|
354 f.close() |
391 f.close() |
355 except IOError as err: |
392 except IOError as err: |
356 QApplication.restoreOverrideCursor() |
393 QApplication.restoreOverrideCursor() |
357 QMessageBox.critical(self.editor, |
394 QMessageBox.critical(self.editor, |
358 self.trUtf8("Export source"), |
395 self.trUtf8("Export source"), |