QScintilla/Exporters/ExporterHTML.py

changeset 5837
9ef6a28f1694
parent 5389
9b1c800daff3
child 5861
26250d8ff4e4
equal deleted inserted replaced
5836:159e6057ad34 5837:9ef6a28f1694
7 Module implementing an exporter for HTML. 7 Module implementing an exporter for HTML.
8 """ 8 """
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 11
12 try: # Only for Py2
13 import StringIO as io # __IGNORE_EXCEPTION__
14 except (ImportError, NameError):
15 import io # __IGNORE_WARNING__
16
12 # This code is a port of the C++ code found in SciTE 1.74 17 # This code is a port of the C++ code found in SciTE 1.74
13 # Original code: Copyright 1998-2006 by Neil Hodgson <neilh@scintilla.org> 18 # Original code: Copyright 1998-2006 by Neil Hodgson <neilh@scintilla.org>
14 19
15 import os 20 import os
21 import sys
16 22
17 from PyQt5.QtCore import Qt 23 from PyQt5.QtCore import Qt
18 from PyQt5.QtGui import QCursor, QFontInfo 24 from PyQt5.QtGui import QCursor, QFontInfo
19 from PyQt5.QtWidgets import QApplication 25 from PyQt5.QtWidgets import QApplication
20 from PyQt5.Qsci import QsciScintilla 26 from PyQt5.Qsci import QsciScintilla
376 382
377 try: 383 try:
378 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) 384 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
379 QApplication.processEvents() 385 QApplication.processEvents()
380 386
381 tabSize = Preferences.getEditor("TabWidth") 387 fn = self.editor.getFileName()
382 if tabSize == 0: 388 if fn:
383 tabSize = 4 389 extension = os.path.normcase(os.path.splitext(fn)[1][1:])
384 wysiwyg = Preferences.getEditorExporter("HTML/WYSIWYG") 390 else:
385 folding = Preferences.getEditorExporter("HTML/Folding") 391 extension = ""
386 onlyStylesUsed = Preferences.getEditorExporter(
387 "HTML/OnlyStylesUsed")
388 titleFullPath = Preferences.getEditorExporter(
389 "HTML/FullPathAsTitle")
390 tabs = Preferences.getEditorExporter("HTML/UseTabs")
391 392
392 generator = HTMLGenerator(self.editor) 393 if extension in \
393 html = generator.generate( 394 Preferences.getEditor("PreviewMarkdownFileNameExtensions") or \
394 tabSize=tabSize, 395 self.editor.getLanguage().lower() == "markdown":
395 useTabs=tabs, 396 # export markdown to HTML
396 wysiwyg=wysiwyg, 397 html = self.__generateFromMarkdown()
397 folding=folding, 398 elif extension in \
398 onlyStylesUsed=onlyStylesUsed, 399 Preferences.getEditor("PreviewRestFileNameExtensions") or \
399 titleFullPath=titleFullPath 400 self.editor.getLanguage().lower() == "restructuredtext":
400 ) 401 # export ReST to HTML
402 html = self.__generateFromReSTDocutils()
403 else:
404 tabSize = Preferences.getEditor("TabWidth")
405 if tabSize == 0:
406 tabSize = 4
407 wysiwyg = Preferences.getEditorExporter("HTML/WYSIWYG")
408 folding = Preferences.getEditorExporter("HTML/Folding")
409 onlyStylesUsed = Preferences.getEditorExporter(
410 "HTML/OnlyStylesUsed")
411 titleFullPath = Preferences.getEditorExporter(
412 "HTML/FullPathAsTitle")
413 tabs = Preferences.getEditorExporter("HTML/UseTabs")
414
415 generator = HTMLGenerator(self.editor)
416 html = generator.generate(
417 tabSize=tabSize,
418 useTabs=tabs,
419 wysiwyg=wysiwyg,
420 folding=folding,
421 onlyStylesUsed=onlyStylesUsed,
422 titleFullPath=titleFullPath
423 )
401 424
402 try: 425 if html:
403 f = open(filename, "w", encoding="utf-8") 426 try:
404 f.write(html) 427 f = open(filename, "w", encoding="utf-8")
405 f.close() 428 f.write(html)
406 except IOError as err: 429 f.close()
430 except IOError as err:
431 QApplication.restoreOverrideCursor()
432 E5MessageBox.critical(
433 self.editor,
434 self.tr("Export source"),
435 self.tr(
436 """<p>The source could not be exported to"""
437 """ <b>{0}</b>.</p><p>Reason: {1}</p>""")
438 .format(filename, str(err)))
439 else:
407 QApplication.restoreOverrideCursor() 440 QApplication.restoreOverrideCursor()
408 E5MessageBox.critical( 441 E5MessageBox.critical(
409 self.editor, 442 self.editor,
410 self.tr("Export source"), 443 self.tr("Export source"),
411 self.tr( 444 self.tr(
412 """<p>The source could not be exported to""" 445 """<p>The source could not be exported to"""
413 """ <b>{0}</b>.</p><p>Reason: {1}</p>""") 446 """ <b>{0}</b>.</p><p>Reason: No HTML code"""
414 .format(filename, str(err))) 447 """ generated.</p>""")
448 .format(filename))
415 finally: 449 finally:
416 QApplication.restoreOverrideCursor() 450 QApplication.restoreOverrideCursor()
451
452 def __generateFromReSTDocutils(self):
453 """
454 Private method to convert ReST text into HTML using 'docutils'.
455
456 @return processed HTML (string)
457 """
458 if 'sphinx' in sys.modules:
459 # Make sure any Sphinx polution of docutils has been removed.
460 unloadKeys = [k for k in sys.modules.keys()
461 if k.startswith(('docutils', 'sphinx'))]
462 for key in unloadKeys:
463 sys.modules.pop(key)
464
465 try:
466 import docutils.core # __IGNORE_EXCEPTION__
467 except ImportError:
468 E5MessageBox.critical(
469 self.editor,
470 self.tr("Export source"),
471 self.tr(
472 """<p>ReStructuredText export requires the"""
473 """ <b>python-docutils</b> package.<br/>Install it with"""
474 """ your package manager, 'pip install docutils' or see"""
475 """ <a href="http://pypi.python.org/pypi/docutils">"""
476 """this page.</a></p>""")
477 )
478 return ""
479
480 htmlFormat = Preferences.getEditor(
481 "PreviewRestDocutilsHTMLFormat").lower()
482 # redirect sys.stderr because we are not interested in it here
483 origStderr = sys.stderr
484 sys.stderr = io.StringIO()
485 html = docutils.core.publish_string(
486 self.editor.text(), writer_name=htmlFormat).decode("utf-8")
487 sys.stderr = origStderr
488 return html
489
490 def __generateFromMarkdown(self):
491 """
492 Private method to convert Markdown text into HTML.
493
494 @return processed HTML
495 @rtype str
496 """
497 try:
498 import markdown # __IGNORE_EXCEPTION__
499 except ImportError:
500 E5MessageBox.critical(
501 self.editor,
502 self.tr("Export source"),
503 self.tr(
504 """<p>Markdown export requires the <b>python-markdown"""
505 """</b> package.<br/>Install it with your package"""
506 """ manager, pip install docutils' or see """
507 """<a href="http://pythonhosted.org/Markdown/install"""
508 """.html"> installation instructions.</a></p>""")
509 )
510 return ""
511
512 try:
513 import mdx_mathjax # __IGNORE_EXCEPTION__ __IGNORE_WARNING__
514 except ImportError:
515 # mathjax doesn't require import statement if installed as
516 # extension
517 pass
518
519 if Preferences.getEditor("PreviewMarkdownNLtoBR"):
520 extensions = ['fenced_code', 'nl2br', 'extra']
521 else:
522 extensions = ['fenced_code', 'extra']
523
524 # version 2.0 supports only extension names, not instances
525 if markdown.version_info[0] > 2 or \
526 (markdown.version_info[0] == 2 and
527 markdown.version_info[1] > 0):
528 class _StrikeThroughExtension(markdown.Extension):
529 """
530 Class is placed here, because it depends on imported markdown,
531 and markdown import is lazy.
532
533 (see http://achinghead.com/
534 python-markdown-adding-insert-delete.html this page for
535 details)
536 """
537 DEL_RE = r'(~~)(.*?)~~'
538
539 def extendMarkdown(self, md, md_globals):
540 # Create the del pattern
541 del_tag = markdown.inlinepatterns.SimpleTagPattern(
542 self.DEL_RE, 'del')
543 # Insert del pattern into markdown parser
544 md.inlinePatterns.add('del', del_tag, '>not_strong')
545
546 extensions.append(_StrikeThroughExtension())
547
548 htmlFormat = Preferences.getEditor("PreviewMarkdownHTMLFormat").lower()
549 try:
550 body = markdown.markdown(self.editor.text(),
551 extensions=extensions + ['mathjax'],
552 output_format=htmlFormat)
553 except (ImportError, ValueError):
554 # markdown raises ValueError or ImportError, depends on version
555 # It is not clear, how to distinguish missing mathjax from other
556 # errors. So keep going without mathjax.
557 body = markdown.markdown(self.editor.text(),
558 extensions=extensions,
559 output_format=htmlFormat)
560
561 if htmlFormat == "xhtml1":
562 head = \
563 '''<!DOCTYPE html PUBLIC "-//W3C//DTD''' \
564 ''' XHTML 1.0 Transitional//EN"\n''' \
565 ''' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional''' \
566 '''.dtd">\n''' \
567 '''<html xmlns="http://www.w3.org/1999/xhtml">\n'''
568 elif htmlFormat == "html5":
569 head = \
570 '''<!DOCTYPE html>\n''' \
571 '''<html lang="EN">\n'''
572 else:
573 head = '<html lang="EN">\n'
574 head += '''<head>\n'''
575 if Preferences.getEditorExporter("HTML/FullPathAsTitle"):
576 head += '''<title>{0}</title>\n'''.format(
577 self.editor.getFileName())
578 else:
579 head += '''<title>{0}</title>\n'''.format(
580 os.path.basename(self.editor.getFileName()))
581 head += '''<meta name="Generator" content="eric6" />\n''' \
582 '''<meta http-equiv="Content-Type" ''' \
583 '''content="text/html; charset=utf-8" />\n''' \
584 '''</head>\n''' \
585 '''<body>\n'''
586
587 foot = '''\n</body>\n</html>\n'''
588
589 return head + body + foot

eric ide

mercurial