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 |