431 @param isDocWarning flag indicating a documentation warning page |
429 @param isDocWarning flag indicating a documentation warning page |
432 @type bool |
430 @type bool |
433 """ |
431 """ |
434 self.__ui.activateCodeDocumentationViewer(switchFocus=False) |
432 self.__ui.activateCodeDocumentationViewer(switchFocus=False) |
435 |
433 |
436 self.__lastDocumentation = documentationInfo |
434 if not isWarning and not isDocWarning: |
437 |
435 self.__lastDocumentation = documentationInfo |
438 if documentationInfo is not None: |
436 |
439 if not documentationInfo: |
437 if not documentationInfo: |
440 if self.__selectedProvider == self.__disabledProvider: |
438 if self.__selectedProvider == self.__disabledProvider: |
441 self.documentationReady(self.__disabledString, |
439 self.documentationReady(self.__disabledString, |
442 isWarning=True) |
440 isWarning=True) |
443 else: |
441 else: |
444 self.documentationReady(self.__noDocumentationString, |
442 self.documentationReady(self.__noDocumentationString, |
445 isDocWarning=True) |
443 isDocWarning=True) |
446 return |
444 else: |
447 |
|
448 if self.__showMarkdown: |
445 if self.__showMarkdown: |
449 if isWarning: |
446 if isWarning: |
450 html = prepareDocumentationViewerHtmlWarningDocument( |
447 html = prepareDocumentationViewerHtmlWarningDocument( |
451 documentationInfo) |
448 documentationInfo) |
452 elif isDocWarning: |
449 elif isDocWarning: |
454 documentationInfo) |
451 documentationInfo) |
455 elif isinstance(documentationInfo, dict): |
452 elif isinstance(documentationInfo, dict): |
456 html = prepareDocumentationViewerHtmlDocument( |
453 html = prepareDocumentationViewerHtmlDocument( |
457 documentationInfo) |
454 documentationInfo) |
458 else: |
455 else: |
459 html = "" |
456 html = documentationInfo |
460 if html: |
457 self.__setHtml(html) |
461 self.__setHtml(html) |
458 else: |
462 return |
459 if isinstance(documentationInfo, str): |
463 |
460 fullText = documentationInfo |
464 if isinstance(documentationInfo, str): |
461 elif isinstance(documentationInfo, dict): |
465 fullText = documentationInfo |
462 name = documentationInfo["name"] |
466 elif isinstance(documentationInfo, dict): |
463 if name: |
467 name = documentationInfo["name"] |
464 title = "".join([name, "\n", |
468 if name: |
465 "=" * len(name), "\n\n"]) |
469 title = "".join([name, "\n", |
466 else: |
470 "=" * len(name), "\n\n"]) |
467 title = "" |
471 else: |
468 |
472 title = "" |
469 if documentationInfo["argspec"]: |
473 |
470 definition = self.tr("Definition: {0}{1}\n").format( |
474 if documentationInfo["argspec"]: |
471 name, documentationInfo["argspec"]) |
475 definition = self.tr("Definition: {0}{1}\n").format( |
472 else: |
476 name, documentationInfo["argspec"]) |
473 definition = '' |
477 else: |
474 |
478 definition = '' |
475 if documentationInfo["note"]: |
479 |
476 note = self.tr("Info: {0}\n\n----\n\n").format( |
480 if documentationInfo["note"]: |
477 documentationInfo["note"]) |
481 note = self.tr("Info: {0}\n\n----\n\n").format( |
478 else: |
482 documentationInfo["note"]) |
479 note = "" |
483 else: |
480 |
484 note = "" |
481 if documentationInfo["docstring"] is None: |
|
482 docString = "" |
|
483 else: |
|
484 docString = documentationInfo["docstring"] |
|
485 |
|
486 fullText = "".join([title, definition, note, docString]) |
485 |
487 |
486 if documentationInfo["docstring"] is None: |
|
487 docString = "" |
|
488 else: |
|
489 docString = documentationInfo["docstring"] |
|
490 |
|
491 fullText = "".join([title, definition, note, docString]) |
|
492 |
|
493 if self.__showMarkdown: |
|
494 self.__processingThread.process("markdown", fullText) |
|
495 else: |
|
496 self.__plainTextViewer.setText(fullText) |
488 self.__plainTextViewer.setText(fullText) |
497 |
489 |
498 def __setHtml(self, html): |
490 def __setHtml(self, html): |
499 """ |
491 """ |
500 Private slot to set the prepared HTML text. |
492 Private slot to set the prepared HTML text. |
577 self.__richTextAct.setChecked(richText) |
569 self.__richTextAct.setChecked(richText) |
578 |
570 |
579 self.documentationReady(self.__lastDocumentation) |
571 self.documentationReady(self.__lastDocumentation) |
580 |
572 |
581 Preferences.setDocuViewer("ShowInfoAsRichText", richText) |
573 Preferences.setDocuViewer("ShowInfoAsRichText", richText) |
582 |
|
583 |
|
584 class DocumentProcessingThread(QThread): |
|
585 """ |
|
586 Class implementing a thread to process some text into HTML usable by the |
|
587 viewer. |
|
588 |
|
589 @signal htmlReady(str) emitted with the processed HTML to signal the |
|
590 availability of the processed HTML |
|
591 @signal warning(str) emitted with an error or warning message |
|
592 """ |
|
593 htmlReady = pyqtSignal(str) |
|
594 warning = pyqtSignal(str) |
|
595 |
|
596 def __init__(self, parent=None): |
|
597 """ |
|
598 Constructor |
|
599 |
|
600 @param parent reference to the parent object (QObject) |
|
601 """ |
|
602 super(DocumentProcessingThread, self).__init__() |
|
603 |
|
604 def process(self, language, text): |
|
605 """ |
|
606 Public method to convert the given text to HTML. |
|
607 |
|
608 @param language language of the text |
|
609 @type str |
|
610 @param text text to be processed |
|
611 @type str |
|
612 """ |
|
613 if self.wait(): |
|
614 self.__language = language |
|
615 self.__text = text |
|
616 self.start() |
|
617 |
|
618 def run(self): |
|
619 """ |
|
620 Public thread method to convert the stored data. |
|
621 """ |
|
622 language = self.__language |
|
623 text = self.__text |
|
624 |
|
625 if language == "markdown": |
|
626 html = self.__convertMarkdown(text, True, "html5") |
|
627 self.htmlReady.emit(html) |
|
628 else: |
|
629 html = self.tr("Format <b>{0}</b> is not supported.")\ |
|
630 .format(language) |
|
631 self.warning.emit(html) |
|
632 |
|
633 def __convertMarkdown(self, text, convertNewLineToBreak, htmlFormat): |
|
634 """ |
|
635 Private method to convert Markdown text into HTML. |
|
636 |
|
637 @param text text to be processed |
|
638 @type str |
|
639 @param convertNewLineToBreak flag indicating to convert new lines |
|
640 to HTML break |
|
641 @type bool |
|
642 @param htmlFormat HTML format to be generated by markdown |
|
643 @type str |
|
644 @return processed HTML |
|
645 @rtype str |
|
646 """ |
|
647 try: |
|
648 import markdown # __IGNORE_EXCEPTION__ |
|
649 except ImportError: |
|
650 return self.tr( |
|
651 """<p>Markdown view requires the <b>Markdown</b> """ |
|
652 """package.<br/>Install it with your package manager,""" |
|
653 """ 'pip install Markdown' or see """ |
|
654 """<a href="http://pythonhosted.org/Markdown/install.html">""" |
|
655 """installation instructions.</a></p>""") |
|
656 |
|
657 try: |
|
658 import mdx_mathjax # __IGNORE_EXCEPTION__ __IGNORE_WARNING__ |
|
659 except ImportError: |
|
660 # mathjax doesn't require import statement if installed |
|
661 # as extension |
|
662 pass |
|
663 |
|
664 if convertNewLineToBreak: |
|
665 extensions = ['fenced_code', 'nl2br', 'extra'] |
|
666 else: |
|
667 extensions = ['fenced_code', 'extra'] |
|
668 |
|
669 # version 2.0 supports only extension names, not instances |
|
670 if markdown.version_info[0] > 2 or \ |
|
671 (markdown.version_info[0] == 2 and |
|
672 markdown.version_info[1] > 0): |
|
673 class _StrikeThroughExtension(markdown.Extension): |
|
674 """ |
|
675 Class is placed here, because it depends on imported markdown, |
|
676 and markdown import is lazy. |
|
677 |
|
678 (see https://pythonhosted.org/Markdown/extensions/api.html |
|
679 this page for details) |
|
680 """ |
|
681 DEL_RE = r'(~~)(.*?)~~' |
|
682 |
|
683 def extendMarkdown(self, md, md_globals): |
|
684 # Create the del pattern |
|
685 del_tag = markdown.inlinepatterns.SimpleTagPattern( |
|
686 self.DEL_RE, 'del') |
|
687 # Insert del pattern into markdown parser |
|
688 md.inlinePatterns.add('del', del_tag, '>not_strong') |
|
689 |
|
690 extensions.append(_StrikeThroughExtension()) |
|
691 |
|
692 try: |
|
693 return markdown.markdown(text, extensions=extensions + ['mathjax'], |
|
694 output_format=htmlFormat.lower()) |
|
695 except (ImportError, ValueError): |
|
696 # markdown raises ValueError or ImportError, depends on version |
|
697 # It is not clear, how to distinguish missing mathjax from other |
|
698 # errors. So keep going without mathjax. |
|
699 return markdown.markdown(text, extensions=extensions, |
|
700 output_format=htmlFormat.lower()) |
|