eric6/UI/Previewers/PreviewerHTML.py

changeset 7301
6df711503ec0
parent 7264
bedbe458d792
child 7304
b072a364dd8d
equal deleted inserted replaced
7300:7622b6330e62 7301:6df711503ec0
209 self.__processingThread.process( 209 self.__processingThread.process(
210 fn, language, editor.text(), 210 fn, language, editor.text(),
211 self.ssiCheckBox.isChecked(), rootPath, 211 self.ssiCheckBox.isChecked(), rootPath,
212 Preferences.getEditor("PreviewRestUseSphinx"), 212 Preferences.getEditor("PreviewRestUseSphinx"),
213 Preferences.getEditor("PreviewMarkdownNLtoBR"), 213 Preferences.getEditor("PreviewMarkdownNLtoBR"),
214 Preferences.getEditor(
215 "PreviewMarkdownUsePyMdownExtensions"),
214 Preferences.getEditor("PreviewMarkdownHTMLFormat"), 216 Preferences.getEditor("PreviewMarkdownHTMLFormat"),
215 Preferences.getEditor("PreviewRestDocutilsHTMLFormat")) 217 Preferences.getEditor("PreviewRestDocutilsHTMLFormat"))
216 218
217 def __setHtml(self, filePath, html, rootPath): 219 def __setHtml(self, filePath, html, rootPath):
218 """ 220 """
336 super(PreviewProcessingThread, self).__init__() 338 super(PreviewProcessingThread, self).__init__()
337 339
338 self.__lock = threading.Lock() 340 self.__lock = threading.Lock()
339 341
340 def process(self, filePath, language, text, ssiEnabled, rootPath, 342 def process(self, filePath, language, text, ssiEnabled, rootPath,
341 useSphinx, convertNewLineToBreak, markdownHtmlFormat, 343 useSphinx, convertNewLineToBreak, usePyMdownExtensions,
342 restDocutilsHtmlFormat): 344 markdownHtmlFormat, restDocutilsHtmlFormat):
343 """ 345 """
344 Public method to convert the given text to HTML. 346 Public method to convert the given text to HTML.
345 347
346 @param filePath file path of the text (string) 348 @param filePath file path of the text
347 @param language language of the text (string) 349 @type str
348 @param text text to be processed (string) 350 @param language language of the text
351 @type str
352 @param text text to be processed
353 @type str
349 @param ssiEnabled flag indicating to do some (limited) SSI processing 354 @param ssiEnabled flag indicating to do some (limited) SSI processing
350 (boolean) 355 @type bool
351 @param rootPath root path to be used for SSI processing (str) 356 @param rootPath root path to be used for SSI processing
357 @type str
352 @param useSphinx flag indicating to use Sphinx to generate the 358 @param useSphinx flag indicating to use Sphinx to generate the
353 ReST preview (boolean) 359 ReST preview
360 @type bool
354 @param convertNewLineToBreak flag indicating to convert new lines 361 @param convertNewLineToBreak flag indicating to convert new lines
355 to HTML break (Markdown only) (boolean) 362 to HTML break (Markdown only)
363 @type bool
364 @param usePyMdownExtensions flag indicating to enable the PyMdown
365 extensions, if they are available
366 @type bool
356 @param markdownHtmlFormat HTML format to be generated by markdown 367 @param markdownHtmlFormat HTML format to be generated by markdown
357 (string) 368 @type str
358 @param restDocutilsHtmlFormat HTML format to be generated by docutils 369 @param restDocutilsHtmlFormat HTML format to be generated by docutils
359 (string) 370 @type str
360 """ 371 """
361 with self.__lock: 372 with self.__lock:
362 self.__filePath = filePath 373 self.__filePath = filePath
363 self.__language = language 374 self.__language = language
364 self.__text = text 375 self.__text = text
365 self.__ssiEnabled = ssiEnabled 376 self.__ssiEnabled = ssiEnabled
366 self.__rootPath = rootPath 377 self.__rootPath = rootPath
367 self.__haveData = True 378 self.__haveData = True
368 self.__useSphinx = useSphinx 379 self.__useSphinx = useSphinx
369 self.__convertNewLineToBreak = convertNewLineToBreak 380 self.__convertNewLineToBreak = convertNewLineToBreak
381 self.__usePyMdownExtensions = usePyMdownExtensions
370 self.__markdownHtmlFormat = markdownHtmlFormat 382 self.__markdownHtmlFormat = markdownHtmlFormat
371 self.__restDocutilsHtmlFormat = restDocutilsHtmlFormat 383 self.__restDocutilsHtmlFormat = restDocutilsHtmlFormat
372 if not self.isRunning(): 384 if not self.isRunning():
373 self.start(QThread.LowPriority) 385 self.start(QThread.LowPriority)
374 386
384 text = self.__text 396 text = self.__text
385 ssiEnabled = self.__ssiEnabled 397 ssiEnabled = self.__ssiEnabled
386 rootPath = self.__rootPath 398 rootPath = self.__rootPath
387 useSphinx = self.__useSphinx 399 useSphinx = self.__useSphinx
388 convertNewLineToBreak = self.__convertNewLineToBreak 400 convertNewLineToBreak = self.__convertNewLineToBreak
401 usePyMdownExtensions = self.__usePyMdownExtensions
389 markdownHtmlFormat = self.__markdownHtmlFormat 402 markdownHtmlFormat = self.__markdownHtmlFormat
390 restDocutilsHtmlFormat = self.__restDocutilsHtmlFormat 403 restDocutilsHtmlFormat = self.__restDocutilsHtmlFormat
391 404
392 self.__haveData = False 405 self.__haveData = False
393 406
394 html = self.__getHtml(language, text, ssiEnabled, filePath, 407 html = self.__getHtml(language, text, ssiEnabled, filePath,
395 rootPath, useSphinx, convertNewLineToBreak, 408 rootPath, useSphinx, convertNewLineToBreak,
396 markdownHtmlFormat, restDocutilsHtmlFormat) 409 usePyMdownExtensions, markdownHtmlFormat,
410 restDocutilsHtmlFormat)
397 411
398 with self.__lock: 412 with self.__lock:
399 if not self.__haveData: 413 if not self.__haveData:
400 self.htmlReady.emit(filePath, html, rootPath) 414 self.htmlReady.emit(filePath, html, rootPath)
401 break 415 break
402 # else - next iteration 416 # else - next iteration
403 417
404 def __getHtml(self, language, text, ssiEnabled, filePath, rootPath, 418 def __getHtml(self, language, text, ssiEnabled, filePath, rootPath,
405 useSphinx, convertNewLineToBreak, markdownHtmlFormat, 419 useSphinx, convertNewLineToBreak, usePyMdownExtensions,
406 restDocutilsHtmlFormat): 420 markdownHtmlFormat, restDocutilsHtmlFormat):
407 """ 421 """
408 Private method to process the given text depending upon the given 422 Private method to process the given text depending upon the given
409 language. 423 language.
410 424
411 @param language language of the text (string) 425 @param language language of the text
412 @param text to be processed (string) 426 @type str
427 @param text to be processed
428 @type str
413 @param ssiEnabled flag indicating to do some (limited) SSI processing 429 @param ssiEnabled flag indicating to do some (limited) SSI processing
414 (boolean) 430 @type bool
415 @param filePath file path of the text (string) 431 @param filePath file path of the text
416 @param rootPath root path to be used for SSI processing (str) 432 @type str
433 @param rootPath root path to be used for SSI processing
434 @type str
417 @param useSphinx flag indicating to use Sphinx to generate the 435 @param useSphinx flag indicating to use Sphinx to generate the
418 ReST preview (boolean) 436 ReST preview
437 @type bool
419 @param convertNewLineToBreak flag indicating to convert new lines 438 @param convertNewLineToBreak flag indicating to convert new lines
420 to HTML break (Markdown only) (boolean) 439 to HTML break (Markdown only)
440 @type bool
441 @param usePyMdownExtensions flag indicating to enable the PyMdown
442 extensions, if they are available
443 @type bool
421 @param markdownHtmlFormat HTML format to be generated by markdown 444 @param markdownHtmlFormat HTML format to be generated by markdown
422 (string) 445 @type str
423 @param restDocutilsHtmlFormat HTML format to be generated by docutils 446 @param restDocutilsHtmlFormat HTML format to be generated by docutils
424 (string) 447 @type str
425 @return processed HTML text (string) 448 @return processed HTML text
449 @rtype str
426 """ 450 """
427 if language == "HTML": 451 if language == "HTML":
428 if ssiEnabled: 452 if ssiEnabled:
429 html = self.__processSSI(text, filePath, rootPath) 453 html = self.__processSSI(text, filePath, rootPath)
430 else: 454 else:
431 html = text 455 html = text
432 return self.__processRootPath(html, rootPath) 456 return self.__processRootPath(html, rootPath)
433 elif language == "Markdown": 457 elif language == "Markdown":
434 return self.__convertMarkdown(text, convertNewLineToBreak, 458 return self.__convertMarkdown(
435 markdownHtmlFormat) 459 text, convertNewLineToBreak, usePyMdownExtensions,
460 markdownHtmlFormat)
436 elif language == "ReST": 461 elif language == "ReST":
437 return self.__convertReST(text, useSphinx, restDocutilsHtmlFormat) 462 return self.__convertReST(text, useSphinx, restDocutilsHtmlFormat)
438 else: 463 else:
439 return self.tr( 464 return self.tr(
440 "<p>No preview available for this type of file.</p>") 465 "<p>No preview available for this type of file.</p>")
623 ).format(errStr) 648 ).format(errStr)
624 649
625 sys.stderr = origStderr 650 sys.stderr = origStderr
626 return html 651 return html
627 652
628 def __convertMarkdown(self, text, convertNewLineToBreak, htmlFormat): 653 def __convertMarkdown(self, text, convertNewLineToBreak,
654 usePyMdownExtensions, htmlFormat):
629 """ 655 """
630 Private method to convert Markdown text into HTML. 656 Private method to convert Markdown text into HTML.
631 657
632 @param text text to be processed (string) 658 @param text text to be processed
659 @type str
633 @param convertNewLineToBreak flag indicating to convert new lines 660 @param convertNewLineToBreak flag indicating to convert new lines
634 to HTML break (Markdown only) (boolean) 661 to HTML break (Markdown only)
635 @param htmlFormat HTML format to be generated by markdown (string) 662 @type bool
636 @return processed HTML (string) 663 @param usePyMdownExtensions flag indicating to enable the PyMdown
664 extensions, if they are available
665 @type bool
666 @param htmlFormat HTML format to be generated by markdown
667 @type str
668 @return processed HTML
669 @rtype str
637 """ 670 """
638 try: 671 try:
639 import markdown # __IGNORE_EXCEPTION__ 672 import markdown # __IGNORE_EXCEPTION__
640 except ImportError: 673 except ImportError:
641 return self.tr( 674 return self.tr(
650 except ImportError: 683 except ImportError:
651 # mathjax doesn't require import statement if installed 684 # mathjax doesn't require import statement if installed
652 # as extension 685 # as extension
653 pass 686 pass
654 687
655 if convertNewLineToBreak: 688 extensions = []
656 extensions = ['fenced_code', 'nl2br', 'extra'] 689 if usePyMdownExtensions:
657 else: 690 try:
658 extensions = ['fenced_code', 'extra'] 691 import pymdownx # __IGNORE_EXCEPTION__ __IGNORE_WARNING__
659 692 # PyPI package is 'pymdown-extensions'
660 # version 2.0 supports only extension names, not instances
661 if (
662 markdown.version_info[0] > 2 or
663 (markdown.version_info[0] == 2 and
664 markdown.version_info[1] > 0)
665 ):
666 class _StrikeThroughExtension(markdown.Extension):
667 """
668 Class is placed here, because it depends on imported markdown,
669 and markdown import is lazy.
670 693
671 (see https://pythonhosted.org/Markdown/extensions/api.html 694 extensions = [
672 this page for details) 695 'pymdownx.extra', 'pymdownx.caret', 'pymdownx.emoji',
673 """ 696 'pymdownx.mark', 'pymdownx.tilde', 'pymdownx.keys',
674 DEL_RE = r'(~~)(.*?)~~' 697 'pymdownx.tasklist', 'pymdownx.smartsymbols',
675 698 ]
676 def extendMarkdown(self, md, md_globals): 699 if convertNewLineToBreak:
677 # Create the del pattern 700 extensions.append('nl2br')
678 del_tag = markdown.inlinepatterns.SimpleTagPattern( 701 except ImportError:
679 self.DEL_RE, 'del') 702 pass
680 # Insert del pattern into markdown parser 703 if not extensions:
681 md.inlinePatterns.add('del', del_tag, '>not_strong') 704 if convertNewLineToBreak:
705 extensions = ['extra', 'toc', 'nl2br']
706 else:
707 extensions = ['extra', 'toc']
682 708
683 extensions.append(_StrikeThroughExtension()) 709 # version 2.0 supports only extension names, not instances
684 710 if (
685 try: 711 markdown.version_info[0] > 2 or
686 return markdown.markdown(text, extensions=extensions + ['mathjax'], 712 (markdown.version_info[0] == 2 and
687 output_format=htmlFormat.lower()) 713 markdown.version_info[1] > 0)
714 ):
715 class _TildeExtension(markdown.Extension):
716 """
717 Class is placed here, because it depends on imported
718 markdown, and markdown import is lazy.
719
720 (see https://pythonhosted.org/Markdown/extensions/api.html
721 this page for details)
722 """
723 DEL_RE = r'(~~)(.+?)~~'
724 SUB_RE = r'(~)(.+?)~'
725
726 def extendMarkdown(self, md, md_globals):
727 # Create the sub pattern and insert it into markdown
728 # parser
729 sub_tag = markdown.inlinepatterns.SimpleTagPattern(
730 self.SUB_RE, 'sub')
731 md.inlinePatterns.add('sub', sub_tag, '>not_strong')
732
733 # Create the del pattern and insert it into markdown
734 # parser
735 del_tag = markdown.inlinepatterns.SimpleTagPattern(
736 self.DEL_RE, 'del')
737 md.inlinePatterns.add('del', del_tag, '>not_strong')
738
739 class _CaretExtension(markdown.Extension):
740 """
741 Class is placed here, because it depends on imported
742 markdown, and markdown import is lazy.
743
744 (see https://pythonhosted.org/Markdown/extensions/api.html
745 this page for details)
746 """
747 INS_RE = r'(\^\^)(.*?)\^\^'
748 SUP_RE = r'(\^)(.*?)\^'
749
750 def extendMarkdown(self, md, md_globals):
751 # Create the sup pattern and insert it into markdown
752 # parser
753 sup_tag = markdown.inlinepatterns.SimpleTagPattern(
754 self.SUP_RE, 'sup')
755 md.inlinePatterns.add('sup', sup_tag, '>not_strong')
756
757 # Create the ins pattern and insert it into markdown
758 # parser
759 ins_tag = markdown.inlinepatterns.SimpleTagPattern(
760 self.INS_RE, 'ins')
761 md.inlinePatterns.add('ins', ins_tag, '>not_strong')
762
763 class _MarkExtension(markdown.Extension):
764 """
765 Class is placed here, because it depends on imported
766 markdown, and markdown import is lazy.
767
768 (see https://pythonhosted.org/Markdown/extensions/api.html
769 this page for details)
770 """
771 MARK_RE = r'(==)(.*?)=='
772
773 def extendMarkdown(self, md, md_globals):
774 # Create the mark pattern and insert it into markdown
775 # parser
776 mark_tag = markdown.inlinepatterns.SimpleTagPattern(
777 self.MARK_RE, 'mark')
778 md.inlinePatterns.add('mark', mark_tag, '>not_strong')
779
780 extensions.extend([
781 _TildeExtension(), _CaretExtension(), _MarkExtension()
782 ])
783
784 try:
785 return markdown.markdown(
786 text, extensions=extensions + ['mdx_mathjax'],
787 output_format=htmlFormat.lower())
688 except (ImportError, ValueError): 788 except (ImportError, ValueError):
689 # markdown raises ValueError or ImportError, depends on version 789 # markdown raises ValueError or ImportError, depends on version
690 # It is not clear, how to distinguish missing mathjax from other 790 # It is not clear, how to distinguish missing mathjax from other
691 # errors. So keep going without mathjax. 791 # errors. So keep going without mathjax.
692 return markdown.markdown(text, extensions=extensions, 792 return markdown.markdown(
693 output_format=htmlFormat.lower()) 793 text, extensions=extensions,
794 output_format=htmlFormat.lower())

eric ide

mercurial