[文档]defreference(state:StateBlock,startLine,_endLine,silent):LOGGER.debug("entering reference: %s, %s, %s, %s",state,startLine,_endLine,silent)lines=0pos=state.bMarks[startLine]+state.tShift[startLine]maximum=state.eMarks[startLine]nextLine=startLine+1# if it's indented more than 3 spaces, it should be a code blockifstate.sCount[startLine]-state.blkIndent>=4:returnFalseifstate.srcCharCode[pos]!=0x5B:# /* [ */returnFalse# Simple check to quickly interrupt scan on [link](url) at the start of line.# Can be useful on practice: https:#github.com/markdown-it/markdown-it/issues/54whilepos<maximum:# /* ] */ /* \ */ /* : */ifstate.srcCharCode[pos]==0x5Dandstate.srcCharCode[pos-1]!=0x5C:ifpos+1==maximum:returnFalseifstate.srcCharCode[pos+1]!=0x3A:returnFalsebreakpos+=1endLine=state.lineMax# jump line-by-line until empty one or EOFterminatorRules=state.md.block.ruler.getRules("reference")oldParentType=state.parentTypestate.parentType="reference"whilenextLine<endLineandnotstate.isEmpty(nextLine):# this would be a code block normally, but after paragraph# it's considered a lazy continuation regardless of what's thereifstate.sCount[nextLine]-state.blkIndent>3:nextLine+=1continue# quirk for blockquotes, this line should already be checked by that ruleifstate.sCount[nextLine]<0:nextLine+=1continue# Some tags can terminate paragraph without empty line.terminate=FalseforterminatorRuleinterminatorRules:ifterminatorRule(state,nextLine,endLine,True):terminate=Truebreakifterminate:breaknextLine+=1string=state.getLines(startLine,nextLine,state.blkIndent,False).strip()maximum=len(string)labelEnd=Nonepos=1whilepos<maximum:ch=charCodeAt(string,pos)ifch==0x5B:# /* [ */returnFalseelifch==0x5D:# /* ] */labelEnd=posbreakelifch==0x0A:# /* \n */lines+=1elifch==0x5C:# /* \ */pos+=1ifpos<maximumandcharCodeAt(string,pos)==0x0A:lines+=1pos+=1if(labelEndisNoneorlabelEnd<0orcharCodeAt(string,labelEnd+1)!=0x3A):# /* : */returnFalse# [label]: destination 'title'# ^^^ skip optional whitespace herepos=labelEnd+2whilepos<maximum:ch=charCodeAt(string,pos)ifch==0x0A:lines+=1elifisSpace(ch):passelse:breakpos+=1# [label]: destination 'title'# ^^^^^^^^^^^ parse thisres=state.md.helpers.parseLinkDestination(string,pos,maximum)ifnotres.ok:returnFalsehref=state.md.normalizeLink(res.str)ifnotstate.md.validateLink(href):returnFalsepos=res.poslines+=res.lines# save cursor state, we could require to rollback laterdestEndPos=posdestEndLineNo=lines# [label]: destination 'title'# ^^^ skipping those spacesstart=poswhilepos<maximum:ch=charCodeAt(string,pos)ifch==0x0A:lines+=1elifisSpace(ch):passelse:breakpos+=1# [label]: destination 'title'# ^^^^^^^ parse thisres=state.md.helpers.parseLinkTitle(string,pos,maximum)ifpos<maximumandstart!=posandres.ok:title=res.strpos=res.poslines+=res.lineselse:title=""pos=destEndPoslines=destEndLineNo# skip trailing spaces until the rest of the linewhilepos<maximum:ch=charCodeAt(string,pos)ifnotisSpace(ch):breakpos+=1ifpos<maximumandcharCodeAt(string,pos)!=0x0A:iftitle:# garbage at the end of the line after title,# but it could still be a valid reference if we roll backtitle=""pos=destEndPoslines=destEndLineNowhilepos<maximum:ch=charCodeAt(string,pos)ifnotisSpace(ch):breakpos+=1ifpos<maximumandcharCodeAt(string,pos)!=0x0A:# garbage at the end of the linereturnFalselabel=normalizeReference(string[1:labelEnd])ifnotlabel:# CommonMark 0.20 disallows empty labelsreturnFalse# Reference can not terminate anything. This check is for safety only.ifsilent:returnTrueif"references"notinstate.env:state.env["references"]={}state.line=startLine+lines+1iflabelnotinstate.env["references"]:state.env["references"][label]={"title":title,"href":href,"map":[startLine,state.line],}else:state.env.setdefault("duplicate_refs",[]).append({"title":title,"href":href,"label":label,"map":[startLine,state.line],})state.parentType=oldParentTypereturnTrue