1""" 
    2Base classes for prompt_toolkit lexers. 
    3""" 
    4 
    5from __future__ import annotations 
    6 
    7from abc import ABCMeta, abstractmethod 
    8from typing import Callable, Hashable 
    9 
    10from prompt_toolkit.document import Document 
    11from prompt_toolkit.formatted_text.base import StyleAndTextTuples 
    12 
    13__all__ = [ 
    14    "Lexer", 
    15    "SimpleLexer", 
    16    "DynamicLexer", 
    17] 
    18 
    19 
    20class Lexer(metaclass=ABCMeta): 
    21    """ 
    22    Base class for all lexers. 
    23    """ 
    24 
    25    @abstractmethod 
    26    def lex_document(self, document: Document) -> Callable[[int], StyleAndTextTuples]: 
    27        """ 
    28        Takes a :class:`~prompt_toolkit.document.Document` and returns a 
    29        callable that takes a line number and returns a list of 
    30        ``(style_str, text)`` tuples for that line. 
    31 
    32        XXX: Note that in the past, this was supposed to return a list 
    33             of ``(Token, text)`` tuples, just like a Pygments lexer. 
    34        """ 
    35 
    36    def invalidation_hash(self) -> Hashable: 
    37        """ 
    38        When this changes, `lex_document` could give a different output. 
    39        (Only used for `DynamicLexer`.) 
    40        """ 
    41        return id(self) 
    42 
    43 
    44class SimpleLexer(Lexer): 
    45    """ 
    46    Lexer that doesn't do any tokenizing and returns the whole input as one 
    47    token. 
    48 
    49    :param style: The style string for this lexer. 
    50    """ 
    51 
    52    def __init__(self, style: str = "") -> None: 
    53        self.style = style 
    54 
    55    def lex_document(self, document: Document) -> Callable[[int], StyleAndTextTuples]: 
    56        lines = document.lines 
    57 
    58        def get_line(lineno: int) -> StyleAndTextTuples: 
    59            "Return the tokens for the given line." 
    60            try: 
    61                return [(self.style, lines[lineno])] 
    62            except IndexError: 
    63                return [] 
    64 
    65        return get_line 
    66 
    67 
    68class DynamicLexer(Lexer): 
    69    """ 
    70    Lexer class that can dynamically returns any Lexer. 
    71 
    72    :param get_lexer: Callable that returns a :class:`.Lexer` instance. 
    73    """ 
    74 
    75    def __init__(self, get_lexer: Callable[[], Lexer | None]) -> None: 
    76        self.get_lexer = get_lexer 
    77        self._dummy = SimpleLexer() 
    78 
    79    def lex_document(self, document: Document) -> Callable[[int], StyleAndTextTuples]: 
    80        lexer = self.get_lexer() or self._dummy 
    81        return lexer.lex_document(document) 
    82 
    83    def invalidation_hash(self) -> Hashable: 
    84        lexer = self.get_lexer() or self._dummy 
    85        return id(lexer)