"""class RulerHelper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and[[MarkdownIt#inline]] to manage sequences of functions (rules):- keep rules in defined order- assign the name to each rule- enable/disable rules- add/replace rules- allow assign rules to additional named chains (in the same)- cacheing lists of active rulesYou will not need use this class directly until write plugins. For simplerules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and[[MarkdownIt.use]]."""fromtypingimport(Callable,Dict,Iterable,List,MutableMapping,Optional,Tuple,TYPE_CHECKING,Union,)importattrifTYPE_CHECKING:frommarkdown_itimportMarkdownIt
# The first positional arg is always a subtype of `StateBase`. Other# arguments may or may not exist, based on the rule's type (block,# core, inline). Return type is either `None` or `bool` based on the# rule's type.RuleFunc=Callable
[文档]classRuler:def__init__(self):# List of added rules.self.__rules__:List[Rule]=[]# Cached rule chains.# First level - chain name, '' for default.# Second level - diginal anchor for fast filtering by charcodes.self.__cache__:Optional[Dict[str,List[RuleFunc]]]=Nonedef__find__(self,name:str)->int:"""Find rule index by name"""fori,ruleinenumerate(self.__rules__):ifrule.name==name:returnireturn-1def__compile__(self)->None:"""Build rules lookup cache"""chains={""}# collect unique namesforruleinself.__rules__:ifnotrule.enabled:continuefornameinrule.alt:chains.add(name)self.__cache__={}forchaininchains:self.__cache__[chain]=[]forruleinself.__rules__:ifnotrule.enabled:continueifchainand(chainnotinrule.alt):continueself.__cache__[chain].append(rule.fn)
[文档]defat(self,ruleName:str,fn:RuleFunc,options=None):"""Replace rule by name with new function & options. :param ruleName: rule name to replace. :param fn: new rule function. :param options: new rule options (not mandatory). :raises: KeyError if name not found """index=self.__find__(ruleName)options=optionsor{}ifindex==-1:raiseKeyError(f"Parser rule not found: {ruleName}")self.__rules__[index].fn=fnself.__rules__[index].alt=options.get("alt",[])self.__cache__=None
[文档]defbefore(self,beforeName:str,ruleName:str,fn:RuleFunc,options=None):"""Add new rule to chain before one with given name. :param beforeName: new rule will be added before this one. :param ruleName: new rule will be added before this one. :param fn: new rule function. :param options: new rule options (not mandatory). :raises: KeyError if name not found """index=self.__find__(beforeName)options=optionsor{}ifindex==-1:raiseKeyError(f"Parser rule not found: {beforeName}")self.__rules__.insert(index,Rule(ruleName,True,fn,options.get("alt",[])))self.__cache__=None
[文档]defafter(self,afterName:str,ruleName:str,fn:RuleFunc,options=None):"""Add new rule to chain after one with given name. :param afterName: new rule will be added after this one. :param ruleName: new rule will be added after this one. :param fn: new rule function. :param options: new rule options (not mandatory). :raises: KeyError if name not found """index=self.__find__(afterName)options=optionsor{}ifindex==-1:raiseKeyError(f"Parser rule not found: {afterName}")self.__rules__.insert(index+1,Rule(ruleName,True,fn,options.get("alt",[])))self.__cache__=None
[文档]defpush(self,ruleName:str,fn:RuleFunc,options=None):"""Push new rule to the end of chain. :param ruleName: new rule will be added to the end of chain. :param fn: new rule function. :param options: new rule options (not mandatory). """self.__rules__.append(Rule(ruleName,True,fn,(optionsor{}).get("alt",[])))self.__cache__=None
[文档]defenable(self,names:Union[str,Iterable[str]],ignoreInvalid:bool=False):"""Enable rules with given names. :param names: name or list of rule names to enable. :param ignoreInvalid: ignore errors when rule not found :raises: KeyError if name not found and not ignoreInvalid :return: list of found rule names """ifisinstance(names,str):names=[names]result=[]fornameinnames:idx=self.__find__(name)if(idx<0)andignoreInvalid:continueif(idx<0)andnotignoreInvalid:raiseKeyError(f"Rules manager: invalid rule name {name}")self.__rules__[idx].enabled=Trueresult.append(name)self.__cache__=Nonereturnresult
[文档]defenableOnly(self,names:Union[str,Iterable[str]],ignoreInvalid:bool=False):"""Enable rules with given names, and disable everything else. :param names: name or list of rule names to enable. :param ignoreInvalid: ignore errors when rule not found :raises: KeyError if name not found and not ignoreInvalid :return: list of found rule names """ifisinstance(names,str):names=[names]forruleinself.__rules__:rule.enabled=Falseself.enable(names,ignoreInvalid)
[文档]defdisable(self,names:Union[str,Iterable[str]],ignoreInvalid:bool=False):"""Disable rules with given names. :param names: name or list of rule names to enable. :param ignoreInvalid: ignore errors when rule not found :raises: KeyError if name not found and not ignoreInvalid :return: list of found rule names """ifisinstance(names,str):names=[names]result=[]fornameinnames:idx=self.__find__(name)if(idx<0)andignoreInvalid:continueif(idx<0)andnotignoreInvalid:raiseKeyError(f"Rules manager: invalid rule name {name}")self.__rules__[idx].enabled=Falseresult.append(name)self.__cache__=Nonereturnresult
[文档]defgetRules(self,chainName:str)->List[RuleFunc]:"""Return array of active functions (rules) for given chain name. It analyzes rules configuration, compiles caches if not exists and returns result. Default chain name is `''` (empty string). It can't be skipped. That's done intentionally, to keep signature monomorphic for high speed. """ifself.__cache__isNone:self.__compile__()assertself.__cache__isnotNone# Chain can be empty, if rules disabled. But we still have to return Array.returnself.__cache__.get(chainName,[])or[]
[文档]defget_all_rules(self)->List[str]:"""Return all available rule names."""return[r.nameforrinself.__rules__]
[文档]defget_active_rules(self)->List[str]:"""Return the active rule names."""return[r.nameforrinself.__rules__ifr.enabled]