523 """<a href="http://pythonhosted.org/Markdown/install""" |
523 """<a href="http://pythonhosted.org/Markdown/install""" |
524 """.html"> installation instructions.</a></p>""") |
524 """.html"> installation instructions.</a></p>""") |
525 ) |
525 ) |
526 return "" |
526 return "" |
527 |
527 |
528 try: |
528 extensions = [] |
529 import mdx_mathjax # __IGNORE_EXCEPTION__ __IGNORE_WARNING__ |
529 if Preferences.getEditor("PreviewMarkdownUsePyMdownExtensions"): |
530 except ImportError: |
530 try: |
531 # mathjax doesn't require import statement if installed as |
531 import pymdownx # __IGNORE_EXCEPTION__ __IGNORE_WARNING__ |
532 # extension |
532 # PyPI package is 'pymdown-extensions' |
533 pass |
|
534 |
|
535 if Preferences.getEditor("PreviewMarkdownNLtoBR"): |
|
536 extensions = ['fenced_code', 'nl2br', 'extra'] |
|
537 else: |
|
538 extensions = ['fenced_code', 'extra'] |
|
539 |
|
540 # version 2.0 supports only extension names, not instances |
|
541 if ( |
|
542 markdown.version_info[0] > 2 or |
|
543 (markdown.version_info[0] == 2 and |
|
544 markdown.version_info[1] > 0) |
|
545 ): |
|
546 class _StrikeThroughExtension(markdown.Extension): |
|
547 """ |
|
548 Class is placed here, because it depends on imported markdown, |
|
549 and markdown import is lazy. |
|
550 |
533 |
551 (see http://achinghead.com/ |
534 extensions = [ |
552 python-markdown-adding-insert-delete.html this page for |
535 'pymdownx.extra', 'pymdownx.caret', 'pymdownx.emoji', |
553 details) |
536 'pymdownx.mark', 'pymdownx.tilde', 'pymdownx.keys', |
554 """ |
537 'pymdownx.tasklist', 'pymdownx.smartsymbols', |
555 DEL_RE = r'(~~)(.*?)~~' |
538 ] |
556 |
539 if Preferences.getEditor("PreviewMarkdownNLtoBR"): |
557 def extendMarkdown(self, md, md_globals): |
540 extensions.append('nl2br') |
558 # Create the del pattern |
541 except ImportError: |
559 del_tag = markdown.inlinepatterns.SimpleTagPattern( |
542 pass |
560 self.DEL_RE, 'del') |
543 if not extensions: |
561 # Insert del pattern into markdown parser |
544 if Preferences.getEditor("PreviewMarkdownNLtoBR"): |
562 md.inlinePatterns.add('del', del_tag, '>not_strong') |
545 extensions = ['fenced_code', 'nl2br', 'extra'] |
|
546 else: |
|
547 extensions = ['fenced_code', 'extra'] |
563 |
548 |
564 extensions.append(_StrikeThroughExtension()) |
549 # version 2.0 supports only extension names, not instances |
|
550 if ( |
|
551 markdown.version_info[0] > 2 or |
|
552 (markdown.version_info[0] == 2 and |
|
553 markdown.version_info[1] > 0) |
|
554 ): |
|
555 class _TildeExtension(markdown.Extension): |
|
556 """ |
|
557 Class is placed here, because it depends on imported |
|
558 markdown, and markdown import is lazy. |
|
559 |
|
560 (see https://pythonhosted.org/Markdown/extensions/api.html |
|
561 this page for details) |
|
562 """ |
|
563 DEL_RE = r'(~~)(.+?)~~' |
|
564 SUB_RE = r'(~)(.+?)~' |
|
565 |
|
566 def extendMarkdown(self, md, md_globals): |
|
567 # Create the sub pattern and insert it into markdown |
|
568 # parser |
|
569 sub_tag = markdown.inlinepatterns.SimpleTagPattern( |
|
570 self.SUB_RE, 'sub') |
|
571 md.inlinePatterns.add('sub', sub_tag, '>not_strong') |
|
572 |
|
573 # Create the del pattern and insert it into markdown |
|
574 # parser |
|
575 del_tag = markdown.inlinepatterns.SimpleTagPattern( |
|
576 self.DEL_RE, 'del') |
|
577 md.inlinePatterns.add('del', del_tag, '>not_strong') |
|
578 |
|
579 class _CaretExtension(markdown.Extension): |
|
580 """ |
|
581 Class is placed here, because it depends on imported |
|
582 markdown, and markdown import is lazy. |
|
583 |
|
584 (see https://pythonhosted.org/Markdown/extensions/api.html |
|
585 this page for details) |
|
586 """ |
|
587 INS_RE = r'(\^\^)(.*?)\^\^' |
|
588 SUP_RE = r'(\^)(.*?)\^' |
|
589 |
|
590 def extendMarkdown(self, md, md_globals): |
|
591 # Create the sup pattern and insert it into markdown |
|
592 # parser |
|
593 sup_tag = markdown.inlinepatterns.SimpleTagPattern( |
|
594 self.SUP_RE, 'sup') |
|
595 md.inlinePatterns.add('sup', sup_tag, '>not_strong') |
|
596 |
|
597 # Create the ins pattern and insert it into markdown |
|
598 # parser |
|
599 ins_tag = markdown.inlinepatterns.SimpleTagPattern( |
|
600 self.INS_RE, 'ins') |
|
601 md.inlinePatterns.add('ins', ins_tag, '>not_strong') |
|
602 |
|
603 class _MarkExtension(markdown.Extension): |
|
604 """ |
|
605 Class is placed here, because it depends on imported |
|
606 markdown, and markdown import is lazy. |
|
607 |
|
608 (see https://pythonhosted.org/Markdown/extensions/api.html |
|
609 this page for details) |
|
610 """ |
|
611 MARK_RE = r'(==)(.*?)==' |
|
612 |
|
613 def extendMarkdown(self, md, md_globals): |
|
614 # Create the mark pattern and insert it into markdown |
|
615 # parser |
|
616 mark_tag = markdown.inlinepatterns.SimpleTagPattern( |
|
617 self.MARK_RE, 'mark') |
|
618 md.inlinePatterns.add('mark', mark_tag, '>not_strong') |
|
619 |
|
620 extensions.extend([ |
|
621 _TildeExtension(), _CaretExtension(), _MarkExtension() |
|
622 ]) |
|
623 |
|
624 if Preferences.getEditor("PreviewMarkdownMathJax"): |
|
625 mathjax = ( |
|
626 "<script type='text/javascript' id='MathJax-script' async" |
|
627 " src='https://cdn.jsdelivr.net/npm/mathjax@3/es5/" |
|
628 "tex-chtml.js'>\n" |
|
629 "</script>\n" |
|
630 ) |
|
631 else: |
|
632 mathjax = "" |
565 |
633 |
566 htmlFormat = Preferences.getEditor("PreviewMarkdownHTMLFormat").lower() |
634 htmlFormat = Preferences.getEditor("PreviewMarkdownHTMLFormat").lower() |
567 try: |
635 body = markdown.markdown(self.editor.text(), |
568 body = markdown.markdown(self.editor.text(), |
636 extensions=extensions, |
569 extensions=extensions + ['mathjax'], |
637 output_format=htmlFormat) |
570 output_format=htmlFormat) |
|
571 except (ImportError, ValueError): |
|
572 # markdown raises ValueError or ImportError, depends on version |
|
573 # It is not clear, how to distinguish missing mathjax from other |
|
574 # errors. So keep going without mathjax. |
|
575 body = markdown.markdown(self.editor.text(), |
|
576 extensions=extensions, |
|
577 output_format=htmlFormat) |
|
578 |
638 |
579 if htmlFormat == "xhtml1": |
639 if htmlFormat == "xhtml1": |
580 head = ( |
640 head = ( |
581 '''<!DOCTYPE html PUBLIC "-//W3C//DTD''' |
641 '''<!DOCTYPE html PUBLIC "-//W3C//DTD''' |
582 ''' XHTML 1.0 Transitional//EN"\n''' |
642 ''' XHTML 1.0 Transitional//EN"\n''' |