""" Base classes for prompt_toolkit lexers. """ from __future__ import annotations from abc import ABCMeta, abstractmethod from typing import Callable, Hashable from prompt_toolkit.document import Document from prompt_toolkit.formatted_text.base import StyleAndTextTuples __all__ = [ "Lexer", "SimpleLexer", "DynamicLexer", ] class Lexer(metaclass=ABCMeta): """ Base class for all lexers. """ @abstractmethod def lex_document(self, document: Document) -> Callable[[int], StyleAndTextTuples]: """ Takes a :class:`~prompt_toolkit.document.Document` and returns a callable that takes a line number and returns a list of ``(style_str, text)`` tuples for that line. XXX: Note that in the past, this was supposed to return a list of ``(Token, text)`` tuples, just like a Pygments lexer. """ def invalidation_hash(self) -> Hashable: """ When this changes, `lex_document` could give a different output. (Only used for `DynamicLexer`.) """ return id(self) class SimpleLexer(Lexer): """ Lexer that doesn't do any tokenizing and returns the whole input as one token. :param style: The style string for this lexer. """ def __init__(self, style: str = "") -> None: self.style = style def lex_document(self, document: Document) -> Callable[[int], StyleAndTextTuples]: lines = document.lines def get_line(lineno: int) -> StyleAndTextTuples: "Return the tokens for the given line." try: return [(self.style, lines[lineno])] except IndexError: return [] return get_line class DynamicLexer(Lexer): """ Lexer class that can dynamically returns any Lexer. :param get_lexer: Callable that returns a :class:`.Lexer` instance. """ def __init__(self, get_lexer: Callable[[], Lexer | None]) -> None: self.get_lexer = get_lexer self._dummy = SimpleLexer() def lex_document(self, document: Document) -> Callable[[int], StyleAndTextTuples]: lexer = self.get_lexer() or self._dummy return lexer.lex_document(document) def invalidation_hash(self) -> Hashable: lexer = self.get_lexer() or self._dummy return id(lexer)