QScintilla/Exporters/ExporterHTML.py

changeset 945
8cd4d08fa9f6
parent 791
9ec2ac20e54e
child 1112
8a7d1b9d18db
equal deleted inserted replaced
944:1b59c4ba121e 945:8cd4d08fa9f6
20 20
21 from .ExporterBase import ExporterBase 21 from .ExporterBase import ExporterBase
22 22
23 import Preferences 23 import Preferences
24 import Utilities 24 import Utilities
25
25 26
26 class HTMLGenerator(object): 27 class HTMLGenerator(object):
27 """ 28 """
28 Class implementing an HTML generator for exporting source code. 29 Class implementing an HTML generator for exporting source code.
29 """ 30 """
33 34
34 @param editor reference to the editor object (QScintilla.Editor.Editor) 35 @param editor reference to the editor object (QScintilla.Editor.Editor)
35 """ 36 """
36 self.editor = editor 37 self.editor = editor
37 38
38 def generate(self, tabSize = 4, useTabs = False, wysiwyg = True, folding = False, 39 def generate(self, tabSize=4, useTabs=False, wysiwyg=True, folding=False,
39 onlyStylesUsed = False, titleFullPath = False): 40 onlyStylesUsed=False, titleFullPath=False):
40 """ 41 """
41 Public method to generate HTML for the source editor. 42 Public method to generate HTML for the source editor.
42 43
43 @keyparam tabSize size of tabs (integer) 44 @keyparam tabSize size of tabs (integer)
44 @keyparam useTabs flag indicating the use of tab characters (boolean) 45 @keyparam useTabs flag indicating the use of tab characters (boolean)
210 style = self.editor.styleAt(pos) 211 style = self.editor.styleAt(pos)
211 if style != styleCurrent: 212 if style != styleCurrent:
212 if inStyleSpan: 213 if inStyleSpan:
213 html += '''</span>''' 214 html += '''</span>'''
214 inStyleSpan = False 215 inStyleSpan = False
215 if ch not in [b'\r', b'\n']: # no need of a span for the EOL 216 if ch not in [b'\r', b'\n']: # no need of a span for the EOL
216 if styleIsUsed[style]: 217 if styleIsUsed[style]:
217 html += '''<span class="S{0:d}">'''.format(style) 218 html += '''<span class="S{0:d}">'''.format(style)
218 inStyleSpan = True 219 inStyleSpan = True
219 styleCurrent = style 220 styleCurrent = style
220 221
221 if ch == b' ': 222 if ch == b' ':
222 if wysiwyg: 223 if wysiwyg:
223 prevCh = b'' 224 prevCh = b''
224 if column == 0: 225 if column == 0:
225 # at start of line, must put a &nbsp; 226 # at start of line, must put a &nbsp;
226 # because regular space will be collapsed 227 # because regular space will be collapsed
227 prevCh = b' ' 228 prevCh = b' '
228 while pos < lengthDoc and self.editor.byteAt(pos) == b' ': 229 while pos < lengthDoc and self.editor.byteAt(pos) == b' ':
229 if prevCh != b' ': 230 if prevCh != b' ':
230 html += ' ' 231 html += ' '
231 else: 232 else:
232 html += '''&nbsp;''' 233 html += '''&nbsp;'''
233 prevCh = self.editor.byteAt(pos) 234 prevCh = self.editor.byteAt(pos)
234 pos += 1 235 pos += 1
235 column += 1 236 column += 1
236 pos -= 1 237 pos -= 1
237 # the last incrementation will be done by the outer loop 238 # the last incrementation will be done by the outer loop
238 else: 239 else:
239 html += ' ' 240 html += ' '
240 column += 1 241 column += 1
241 elif ch == b'\t': 242 elif ch == b'\t':
256 inStyleSpan = False 257 inStyleSpan = False
257 if inFoldSpan: 258 if inFoldSpan:
258 html += '''</span>''' 259 html += '''</span>'''
259 inFoldSpan = False 260 inFoldSpan = False
260 if ch == b'\r' and self.editor.byteAt(pos + 1) == b'\n': 261 if ch == b'\r' and self.editor.byteAt(pos + 1) == b'\n':
261 pos += 1 # CR+LF line ending, skip the "extra" EOL char 262 pos += 1 # CR+LF line ending, skip the "extra" EOL char
262 column = 0 263 column = 0
263 if wysiwyg: 264 if wysiwyg:
264 html += '''<br />''' 265 html += '''<br />'''
265 266
266 styleCurrent = self.editor.styleAt(pos + 1) 267 styleCurrent = self.editor.styleAt(pos + 1)
270 271
271 if newLevel < level: 272 if newLevel < level:
272 while levelStack[-1] > newLevel: 273 while levelStack[-1] > newLevel:
273 html += '''</span>''' 274 html += '''</span>'''
274 levelStack.pop() 275 levelStack.pop()
275 html += '\n' # here to get clean code 276 html += '\n' # here to get clean code
276 if newLevel > level: 277 if newLevel > level:
277 html += '''<span id="ln{0:d}">'''.format(line) 278 html += '''<span id="ln{0:d}">'''.format(line)
278 levelStack.append(newLevel) 279 levelStack.append(newLevel)
279 if self.editor.foldFlagsAt(line) & \ 280 if self.editor.foldFlagsAt(line) & \
280 QsciScintilla.SC_FOLDLEVELHEADERFLAG: 281 QsciScintilla.SC_FOLDLEVELHEADERFLAG:
310 utf8Len = 4 311 utf8Len = 4
311 elif (utf8Ch[0] & 0xE0) == 0xE0: 312 elif (utf8Ch[0] & 0xE0) == 0xE0:
312 utf8Len = 3 313 utf8Len = 3
313 elif (utf8Ch[0] & 0xC0) == 0xC0: 314 elif (utf8Ch[0] & 0xC0) == 0xC0:
314 utf8Len = 2 315 utf8Len = 2
315 column -= 1 # will be incremented again later 316 column -= 1 # will be incremented again later
316 elif len(utf8Ch) == utf8Len: 317 elif len(utf8Ch) == utf8Len:
317 ch = utf8Ch.decode('utf8') 318 ch = utf8Ch.decode('utf8')
318 html += Utilities.html_encode(ch) 319 html += Utilities.html_encode(ch)
319 utf8Ch = b"" 320 utf8Ch = b""
320 utf8Len = 0 321 utf8Len = 0
321 else: 322 else:
322 column -= 1 # will be incremented again later 323 column -= 1 # will be incremented again later
323 else: 324 else:
324 html += ch.decode() 325 html += ch.decode()
325 column += 1 326 column += 1
326 327
327 pos += 1 328 pos += 1
341 342
342 html += '''</body>\n</html>\n''' 343 html += '''</body>\n</html>\n'''
343 344
344 return html 345 return html
345 346
347
346 class ExporterHTML(ExporterBase): 348 class ExporterHTML(ExporterBase):
347 """ 349 """
348 Class implementing an exporter for HTML. 350 Class implementing an exporter for HTML.
349 """ 351 """
350 def __init__(self, editor, parent = None): 352 def __init__(self, editor, parent=None):
351 """ 353 """
352 Constructor 354 Constructor
353 355
354 @param editor reference to the editor object (QScintilla.Editor.Editor) 356 @param editor reference to the editor object (QScintilla.Editor.Editor)
355 @param parent parent object of the exporter (QObject) 357 @param parent parent object of the exporter (QObject)
377 titleFullPath = Preferences.getEditorExporter("HTML/FullPathAsTitle") 379 titleFullPath = Preferences.getEditorExporter("HTML/FullPathAsTitle")
378 tabs = Preferences.getEditorExporter("HTML/UseTabs") 380 tabs = Preferences.getEditorExporter("HTML/UseTabs")
379 381
380 generator = HTMLGenerator(self.editor) 382 generator = HTMLGenerator(self.editor)
381 html = generator.generate( 383 html = generator.generate(
382 tabSize = tabSize, 384 tabSize=tabSize,
383 useTabs = tabs, 385 useTabs=tabs,
384 wysiwyg = wysiwyg, 386 wysiwyg=wysiwyg,
385 folding = folding, 387 folding=folding,
386 onlyStylesUsed = onlyStylesUsed, 388 onlyStylesUsed=onlyStylesUsed,
387 titleFullPath = titleFullPath 389 titleFullPath=titleFullPath
388 ) 390 )
389 391
390 try: 392 try:
391 f = open(filename, "w", encoding = "utf-8") 393 f = open(filename, "w", encoding="utf-8")
392 f.write(html) 394 f.write(html)
393 f.close() 395 f.close()
394 except IOError as err: 396 except IOError as err:
395 QApplication.restoreOverrideCursor() 397 QApplication.restoreOverrideCursor()
396 E5MessageBox.critical(self.editor, 398 E5MessageBox.critical(self.editor,

eric ide

mercurial