Skip to content

PygmentsHighlighter

Qt Base Class: QSyntaxHighlighter

Signature: QSyntaxHighlighter(self, parent: PySide6.QtCore.QObject) -> None QSyntaxHighlighter(self, parent: PySide6.QtGui.QTextDocument) -> None

Base classes

Name Children Inherits
SyntaxHighlighter
prettyqt.gui.syntaxhighlighter

⋔ Inheritance diagram

graph TD
  1473296297856["syntaxhighlighters.PygmentsHighlighter"]
  1473245668528["gui.SyntaxHighlighter"]
  1473245664624["gui.SyntaxHighlighterMixin"]
  1473299815024["core.ObjectMixin"]
  140713234304496["builtins.object"]
  1473289231040["QtGui.QSyntaxHighlighter"]
  1473288842240["QtCore.QObject"]
  1473291690208["Shiboken.Object"]
  1473245668528 --> 1473296297856
  1473245664624 --> 1473245668528
  1473299815024 --> 1473245664624
  140713234304496 --> 1473299815024
  1473289231040 --> 1473245668528
  1473288842240 --> 1473289231040
  1473291690208 --> 1473288842240
  140713234304496 --> 1473291690208

🛈 DocStrings

Bases: SyntaxHighlighter

Syntax highlighter that uses Pygments for parsing.

Source code in prettyqt\syntaxhighlighters\pygmentshighlighter.py
class PygmentsHighlighter(gui.SyntaxHighlighter):
    """Syntax highlighter that uses Pygments for parsing."""

    # ---------------------------------------------------------------------------
    #  "QSyntaxHighlighter" interface
    # ---------------------------------------------------------------------------

    def __init__(
        self,
        parent: gui.QTextDocument,
        lexer: str,
        style: None | StyleStr = None,
    ):
        super().__init__(parent)
        self._document = self.document()
        self._formatter = html.HtmlFormatter(nowrap=True)
        self._style = None
        self._stylename = ""
        if style is None:
            gui.GuiApplication.styleHints().colorSchemeChanged.connect(
                self.adjust_style_to_palette
            )
        self.set_style(style)
        if lexer == "regex":
            self._lexer = lexers.load_lexer_from_file(str(paths.RE_LEXER_PATH))
        else:
            self._lexer = lexers.get_lexer_by_name(lexer)

    def __repr__(self):
        return get_repr(self, lexer=self._lexer.aliases[0])

    def highlightBlock(self, string):
        """Highlight a block of text."""
        if (prev_data := self.currentBlock().previous().userData()) is not None:
            self._lexer._saved_state_stack = prev_data.syntax_stack
        elif hasattr(self._lexer, "_saved_state_stack"):
            del self._lexer._saved_state_stack

        # Lex the text using Pygments
        index = 0
        for token, text in self._lexer.get_tokens(string):
            length = qstring_length(text)
            self.setFormat(index, length, self._get_format(token))
            index += length

        if hasattr(self._lexer, "_saved_state_stack"):
            data = gui.TextBlockUserData(syntax_stack=self._lexer._saved_state_stack)
            self.currentBlock().setUserData(data)
            # Clean up for the next go-round.
            del self._lexer._saved_state_stack

    # ---------------------------------------------------------------------------
    # "PygmentsHighlighter" interface
    # ---------------------------------------------------------------------------

    def set_style(self, style: None | StyleStr):
        match style:
            case None:
                self.adjust_style_to_palette()
                return
            case str():
                self._style = styles.get_style_by_name(style)
                self._stylename = style
            case _:
                raise TypeError(style)
        self._clear_caches()

    def get_style(self) -> StyleStr:
        return self._stylename

    def adjust_style_to_palette(self):
        pal = gui.GuiApplication.get_palette()
        style = "monokai" if pal.is_dark() else "default"
        self.set_style(style)

    def set_style_sheet(self, stylesheet: str):
        """Sets a CSS stylesheet.

        The classes in the stylesheet should correspond to those generated by:

            pygmentize -S <style> -f html

        Note that "set_style" and "set_style_sheet" completely override each
        other, i.e. they cannot be used in conjunction.
        """
        self._document.setDefaultStyleSheet(stylesheet)
        self._style = None
        self._clear_caches()

    # ---------------------------------------------------------------------------
    # Protected interface
    # ---------------------------------------------------------------------------

    def _clear_caches(self):
        """Clear caches for brushes and formats."""
        _get_brush.cache_clear()
        self._get_format.cache_clear()

    @functools.cache  # noqa: B019
    def _get_format(self, token: str) -> gui.QTextCharFormat:
        """Returns a QTextCharFormat for token or None."""
        if self._style is None:
            return self._get_format_from_document(token, self._document)
        else:
            return _get_format_from_style(token, self._style)

    def _get_format_from_document(
        self, token: str, document: gui.QTextDocument
    ) -> gui.QTextCharFormat:
        """Return a QTextCharFormat for token from document."""
        _, html = next(self._formatter._format_lines([(token, "dummy")]))
        document.setHtml(html)
        return gui.TextCursor(document).charFormat()

    style = core.Property(
        str,
        get_style,
        set_style,
        doc="Pygments style for the highlighter",
    )

highlightBlock(string)

Highlight a block of text.

Source code in prettyqt\syntaxhighlighters\pygmentshighlighter.py
def highlightBlock(self, string):
    """Highlight a block of text."""
    if (prev_data := self.currentBlock().previous().userData()) is not None:
        self._lexer._saved_state_stack = prev_data.syntax_stack
    elif hasattr(self._lexer, "_saved_state_stack"):
        del self._lexer._saved_state_stack

    # Lex the text using Pygments
    index = 0
    for token, text in self._lexer.get_tokens(string):
        length = qstring_length(text)
        self.setFormat(index, length, self._get_format(token))
        index += length

    if hasattr(self._lexer, "_saved_state_stack"):
        data = gui.TextBlockUserData(syntax_stack=self._lexer._saved_state_stack)
        self.currentBlock().setUserData(data)
        # Clean up for the next go-round.
        del self._lexer._saved_state_stack

set_style_sheet(stylesheet: str)

Sets a CSS stylesheet.

The classes in the stylesheet should correspond to those generated by:

pygmentize -S <style> -f html

Note that "set_style" and "set_style_sheet" completely override each other, i.e. they cannot be used in conjunction.

Source code in prettyqt\syntaxhighlighters\pygmentshighlighter.py
def set_style_sheet(self, stylesheet: str):
    """Sets a CSS stylesheet.

    The classes in the stylesheet should correspond to those generated by:

        pygmentize -S <style> -f html

    Note that "set_style" and "set_style_sheet" completely override each
    other, i.e. they cannot be used in conjunction.
    """
    self._document.setDefaultStyleSheet(stylesheet)
    self._style = None
    self._clear_caches()

⌗ Property table

Qt Property Type Doc
objectName QString
style QString Pygments style for the highlighter