Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
state_block.py262 linesDownload Raw Back to rules_block
1from __future__ import annotations2 3from typing import TYPE_CHECKING, Literal4 5from ..common.utils import isStrSpace6from ..ruler import StateBase7from ..token import Token8from ..utils import EnvType9 10if TYPE_CHECKING:11    from markdown_it.main import MarkdownIt12 13 14class StateBlock(StateBase):15    def __init__(16        self, src: str, md: MarkdownIt, env: EnvType, tokens: list[Token]17    ) -> None:18        self.src = src19 20        # link to parser instance21        self.md = md22 23        self.env = env24 25        #26        # Internal state variables27        #28 29        self.tokens = tokens30 31        self.bMarks: list[int] = []  # line begin offsets for fast jumps32        self.eMarks: list[int] = []  # line end offsets for fast jumps33        # offsets of the first non-space characters (tabs not expanded)34        self.tShift: list[int] = []35        self.sCount: list[int] = []  # indents for each line (tabs expanded)36 37        # An amount of virtual spaces (tabs expanded) between beginning38        # of each line (bMarks) and real beginning of that line.39        #40        # It exists only as a hack because blockquotes override bMarks41        # losing information in the process.42        #43        # It's used only when expanding tabs, you can think about it as44        # an initial tab length, e.g. bsCount=21 applied to string `\t123`45        # means first tab should be expanded to 4-21%4 === 3 spaces.46        #47        self.bsCount: list[int] = []48 49        # block parser variables50        self.blkIndent = 0  # required block content indent (for example, if we are51        # inside a list, it would be positioned after list marker)52        self.line = 0  # line index in src53        self.lineMax = 0  # lines count54        self.tight = False  # loose/tight mode for lists55        self.ddIndent = -1  # indent of the current dd block (-1 if there isn't any)56        self.listIndent = -1  # indent of the current list block (-1 if there isn't any)57 58        # can be 'blockquote', 'list', 'root', 'paragraph' or 'reference'59        # used in lists to determine if they interrupt a paragraph60        self.parentType = "root"61 62        self.level = 063 64        # renderer65        self.result = ""66 67        # Create caches68        # Generate markers.69        indent_found = False70 71        start = pos = indent = offset = 072        length = len(self.src)73 74        for pos, character in enumerate(self.src):75            if not indent_found:76                if isStrSpace(character):77                    indent += 178 79                    if character == "\t":80                        offset += 4 - offset % 481                    else:82                        offset += 183                    continue84                else:85                    indent_found = True86 87            if character == "\n" or pos == length - 1:88                if character != "\n":89                    pos += 190                self.bMarks.append(start)91                self.eMarks.append(pos)92                self.tShift.append(indent)93                self.sCount.append(offset)94                self.bsCount.append(0)95 96                indent_found = False97                indent = 098                offset = 099                start = pos + 1100 101        # Push fake entry to simplify cache bounds checks102        self.bMarks.append(length)103        self.eMarks.append(length)104        self.tShift.append(0)105        self.sCount.append(0)106        self.bsCount.append(0)107 108        self.lineMax = len(self.bMarks) - 1  # don't count last fake line109 110        # pre-check if code blocks are enabled, to speed up is_code_block method111        self._code_enabled = "code" in self.md["block"].ruler.get_active_rules()112 113    def __repr__(self) -> str:114        return (115            f"{self.__class__.__name__}"116            f"(line={self.line},level={self.level},tokens={len(self.tokens)})"117        )118 119    def push(self, ttype: str, tag: str, nesting: Literal[-1, 0, 1]) -> Token:120        """Push new token to "stream"."""121        token = Token(ttype, tag, nesting)122        token.block = True123        if nesting < 0:124            self.level -= 1  # closing tag125        token.level = self.level126        if nesting > 0:127            self.level += 1  # opening tag128        self.tokens.append(token)129        return token130 131    def isEmpty(self, line: int) -> bool:132        """."""133        return (self.bMarks[line] + self.tShift[line]) >= self.eMarks[line]134 135    def skipEmptyLines(self, from_pos: int) -> int:136        """."""137        while from_pos < self.lineMax:138            try:139                if (self.bMarks[from_pos] + self.tShift[from_pos]) < self.eMarks[140                    from_pos141                ]:142                    break143            except IndexError:144                pass145            from_pos += 1146        return from_pos147 148    def skipSpaces(self, pos: int) -> int:149        """Skip spaces from given position."""150        while True:151            try:152                current = self.src[pos]153            except IndexError:154                break155            if not isStrSpace(current):156                break157            pos += 1158        return pos159 160    def skipSpacesBack(self, pos: int, minimum: int) -> int:161        """Skip spaces from given position in reverse."""162        if pos <= minimum:163            return pos164        while pos > minimum:165            pos -= 1166            if not isStrSpace(self.src[pos]):167                return pos + 1168        return pos169 170    def skipChars(self, pos: int, code: int) -> int:171        """Skip character code from given position."""172        while True:173            try:174                current = self.srcCharCode[pos]175            except IndexError:176                break177            if current != code:178                break179            pos += 1180        return pos181 182    def skipCharsStr(self, pos: int, ch: str) -> int:183        """Skip character string from given position."""184        while True:185            try:186                current = self.src[pos]187            except IndexError:188                break189            if current != ch:190                break191            pos += 1192        return pos193 194    def skipCharsBack(self, pos: int, code: int, minimum: int) -> int:195        """Skip character code reverse from given position - 1."""196        if pos <= minimum:197            return pos198        while pos > minimum:199            pos -= 1200            if code != self.srcCharCode[pos]:201                return pos + 1202        return pos203 204    def skipCharsStrBack(self, pos: int, ch: str, minimum: int) -> int:205        """Skip character string reverse from given position - 1."""206        if pos <= minimum:207            return pos208        while pos > minimum:209            pos -= 1210            if ch != self.src[pos]:211                return pos + 1212        return pos213 214    def getLines(self, begin: int, end: int, indent: int, keepLastLF: bool) -> str:215        """Cut lines range from source."""216        line = begin217        if begin >= end:218            return ""219 220        queue = [""] * (end - begin)221 222        i = 1223        while line < end:224            lineIndent = 0225            lineStart = first = self.bMarks[line]226            last = (227                self.eMarks[line] + 1228                if line + 1 < end or keepLastLF229                else self.eMarks[line]230            )231 232            while (first < last) and (lineIndent < indent):233                ch = self.src[first]234                if isStrSpace(ch):235                    if ch == "\t":236                        lineIndent += 4 - (lineIndent + self.bsCount[line]) % 4237                    else:238                        lineIndent += 1239                elif first - lineStart < self.tShift[line]:240                    lineIndent += 1241                else:242                    break243                first += 1244 245            if lineIndent > indent:246                # partially expanding tabs in code blocks, e.g '\t\tfoobar'247                # with indent=2 becomes '  \tfoobar'248                queue[i - 1] = (" " * (lineIndent - indent)) + self.src[first:last]249            else:250                queue[i - 1] = self.src[first:last]251 252            line += 1253            i += 1254 255        return "".join(queue)256 257    def is_code_block(self, line: int) -> bool:258        """Check if line is a code block,259        i.e. the code block rule is enabled and text is indented by more than 3 spaces.260        """261        return self._code_enabled and (self.sCount[line] - self.blkIndent) >= 4262 
codekingpro/portable-devtools · Team Ai