[文档]classStateBlock(StateBase):def__init__(self,src:str,md:"MarkdownIt",env,tokens:List[Token],srcCharCode:Optional[Tuple[int,...]]=None,):ifsrcCharCodeisnotNone:self._src=srcself.srcCharCode=srcCharCodeelse:self.src=src# link to parser instanceself.md=mdself.env=env## Internal state variables#self.tokens=tokensself.bMarks=[]# line begin offsets for fast jumpsself.eMarks=[]# line end offsets for fast jumps# offsets of the first non-space characters (tabs not expanded)self.tShift=[]self.sCount=[]# indents for each line (tabs expanded)# An amount of virtual spaces (tabs expanded) between beginning# of each line (bMarks) and real beginning of that line.## It exists only as a hack because blockquotes override bMarks# losing information in the process.## It's used only when expanding tabs, you can think about it as# an initial tab length, e.g. bsCount=21 applied to string `\t123`# means first tab should be expanded to 4-21%4 === 3 spaces.#self.bsCount=[]# block parser variablesself.blkIndent=0# required block content indent (for example, if we are# inside a list, it would be positioned after list marker)self.line=0# line index in srcself.lineMax=0# lines countself.tight=False# loose/tight mode for listsself.ddIndent=-1# indent of the current dd block (-1 if there isn't any)self.listIndent=-1# indent of the current list block (-1 if there isn't any)# can be 'blockquote', 'list', 'root', 'paragraph' or 'reference'# used in lists to determine if they interrupt a paragraphself.parentType="root"self.level=0# rendererself.result=""# Create caches# Generate markers.indent_found=Falsestart=pos=indent=offset=0length=len(self.src)forpos,characterinenumerate(self.srcCharCode):ifnotindent_found:ifisSpace(character):indent+=1ifcharacter==0x09:offset+=4-offset%4else:offset+=1continueelse:indent_found=Trueifcharacter==0x0Aorpos==length-1:ifcharacter!=0x0A:pos+=1self.bMarks.append(start)self.eMarks.append(pos)self.tShift.append(indent)self.sCount.append(offset)self.bsCount.append(0)indent_found=Falseindent=0offset=0start=pos+1# Push fake entry to simplify cache bounds checksself.bMarks.append(length)self.eMarks.append(length)self.tShift.append(0)self.sCount.append(0)self.bsCount.append(0)self.lineMax=len(self.bMarks)-1# don't count last fake linedef__repr__(self):return(f"{self.__class__.__name__}"f"(line={self.line},level={self.level},tokens={len(self.tokens)})")
[文档]defpush(self,ttype:str,tag:str,nesting:int)->Token:"""Push new token to "stream"."""token=Token(ttype,tag,nesting)token.block=Trueifnesting<0:self.level-=1# closing tagtoken.level=self.levelifnesting>0:self.level+=1# opening tagself.tokens.append(token)returntoken
[文档]defskipSpaces(self,pos:int)->int:"""Skip spaces from given position."""whilepos<len(self.src):ifnotisSpace(self.srcCharCode[pos]):breakpos+=1returnpos
[文档]defskipSpacesBack(self,pos:int,minimum:int)->int:"""Skip spaces from given position in reverse."""ifpos<=minimum:returnposwhilepos>minimum:pos-=1ifnotisSpace(self.srcCharCode[pos]):returnpos+1returnpos
[文档]defskipChars(self,pos:int,code:int)->int:"""Skip char codes from given position."""whilepos<len(self.src):ifself.srcCharCode[pos]!=code:breakpos+=1returnpos
[文档]defskipCharsBack(self,pos:int,code:int,minimum:int)->int:"""Skip char codes reverse from given position - 1."""ifpos<=minimum:returnposwhilepos>minimum:pos-=1ifcode!=self.srcCharCode[pos]:returnpos+1returnpos
[文档]defgetLines(self,begin:int,end:int,indent:int,keepLastLF:bool)->str:"""Cut lines range from source."""line=beginifbegin>=end:return""queue=[""]*(end-begin)i=1whileline<end:lineIndent=0lineStart=first=self.bMarks[line]ifline+1<endorkeepLastLF:last=self.eMarks[line]+1else:last=self.eMarks[line]while(first<last)and(lineIndent<indent):ch=self.srcCharCode[first]ifisSpace(ch):ifch==0x09:lineIndent+=4-(lineIndent+self.bsCount[line])%4else:lineIndent+=1eliffirst-lineStart<self.tShift[line]:lineIndent+=1else:breakfirst+=1iflineIndent>indent:# partially expanding tabs in code blocks, e.g '\t\tfoobar'# with indent=2 becomes ' \tfoobar'queue[i-1]=(" "*(lineIndent-indent))+self.src[first:last]else:queue[i-1]=self.src[first:last]line+=1i+=1return"".join(queue)