📄 states.py
字号:
if text.startswith('pep-'): pepnum = int(match.group('pepnum1')) elif text.startswith('PEP'): pepnum = int(match.group('pepnum2')) else: raise MarkupMismatch ref = self.document.settings.pep_base_url + self.pep_url % pepnum unescaped = unescape(text, 0) return [nodes.reference(unescape(text, 1), unescaped, refuri=ref)] rfc_url = 'rfc%d.html' def rfc_reference(self, match, lineno): text = match.group(0) if text.startswith('RFC'): rfcnum = int(match.group('rfcnum')) ref = self.document.settings.rfc_base_url + self.rfc_url % rfcnum else: raise MarkupMismatch unescaped = unescape(text, 0) return [nodes.reference(unescape(text, 1), unescaped, refuri=ref)] def implicit_inline(self, text, lineno): """ Check each of the patterns in `self.implicit_dispatch` for a match, and dispatch to the stored method for the pattern. Recursively check the text before and after the match. Return a list of `nodes.Text` and inline element nodes. """ if not text: return [] for pattern, method in self.implicit_dispatch: match = pattern.search(text) if match: try: # Must recurse on strings before *and* after the match; # there may be multiple patterns. return (self.implicit_inline(text[:match.start()], lineno) + method(match, lineno) + self.implicit_inline(text[match.end():], lineno)) except MarkupMismatch: pass return [nodes.Text(unescape(text), rawsource=unescape(text, 1))] dispatch = {'*': emphasis, '**': strong, '`': interpreted_or_phrase_ref, '``': literal, '_`': inline_internal_target, ']_': footnote_reference, '|': substitution_reference, '_': reference, '__': anonymous_reference}def _loweralpha_to_int(s, _zero=(ord('a')-1)): return ord(s) - _zerodef _upperalpha_to_int(s, _zero=(ord('A')-1)): return ord(s) - _zerodef _lowerroman_to_int(s): return roman.fromRoman(s.upper())class Body(RSTState): """ Generic classifier of the first line of a block. """ double_width_pad_char = tableparser.TableParser.double_width_pad_char """Padding character for East Asian double-width text.""" enum = Struct() """Enumerated list parsing information.""" enum.formatinfo = { 'parens': Struct(prefix='(', suffix=')', start=1, end=-1), 'rparen': Struct(prefix='', suffix=')', start=0, end=-1), 'period': Struct(prefix='', suffix='.', start=0, end=-1)} enum.formats = enum.formatinfo.keys() enum.sequences = ['arabic', 'loweralpha', 'upperalpha', 'lowerroman', 'upperroman'] # ORDERED! enum.sequencepats = {'arabic': '[0-9]+', 'loweralpha': '[a-z]', 'upperalpha': '[A-Z]', 'lowerroman': '[ivxlcdm]+', 'upperroman': '[IVXLCDM]+',} enum.converters = {'arabic': int, 'loweralpha': _loweralpha_to_int, 'upperalpha': _upperalpha_to_int, 'lowerroman': _lowerroman_to_int, 'upperroman': roman.fromRoman} enum.sequenceregexps = {} for sequence in enum.sequences: enum.sequenceregexps[sequence] = re.compile( enum.sequencepats[sequence] + '$') grid_table_top_pat = re.compile(r'\+-[-+]+-\+ *$') """Matches the top (& bottom) of a full table).""" simple_table_top_pat = re.compile('=+( +=+)+ *$') """Matches the top of a simple table.""" simple_table_border_pat = re.compile('=+[ =]*$') """Matches the bottom & header bottom of a simple table.""" pats = {} """Fragments of patterns used by transitions.""" pats['nonalphanum7bit'] = '[!-/:-@[-`{-~]' pats['alpha'] = '[a-zA-Z]' pats['alphanum'] = '[a-zA-Z0-9]' pats['alphanumplus'] = '[a-zA-Z0-9_-]' pats['enum'] = ('(%(arabic)s|%(loweralpha)s|%(upperalpha)s|%(lowerroman)s' '|%(upperroman)s|#)' % enum.sequencepats) pats['optname'] = '%(alphanum)s%(alphanumplus)s*' % pats # @@@ Loosen up the pattern? Allow Unicode? pats['optarg'] = '(%(alpha)s%(alphanumplus)s*|<[^<>]+>)' % pats pats['shortopt'] = r'(-|\+)%(alphanum)s( ?%(optarg)s)?' % pats pats['longopt'] = r'(--|/)%(optname)s([ =]%(optarg)s)?' % pats pats['option'] = r'(%(shortopt)s|%(longopt)s)' % pats for format in enum.formats: pats[format] = '(?P<%s>%s%s%s)' % ( format, re.escape(enum.formatinfo[format].prefix), pats['enum'], re.escape(enum.formatinfo[format].suffix)) patterns = { 'bullet': r'[-+*]( +|$)', 'enumerator': r'(%(parens)s|%(rparen)s|%(period)s)( +|$)' % pats, 'field_marker': r':(?![: ])([^:\\]|\\.)*(?<! ):( +|$)', 'option_marker': r'%(option)s(, %(option)s)*( +| ?$)' % pats, 'doctest': r'>>>( +|$)', 'line_block': r'\|( +|$)', 'grid_table_top': grid_table_top_pat, 'simple_table_top': simple_table_top_pat, 'explicit_markup': r'\.\.( +|$)', 'anonymous': r'__( +|$)', 'line': r'(%(nonalphanum7bit)s)\1* *$' % pats, 'text': r''} initial_transitions = ( 'bullet', 'enumerator', 'field_marker', 'option_marker', 'doctest', 'line_block', 'grid_table_top', 'simple_table_top', 'explicit_markup', 'anonymous', 'line', 'text') def indent(self, match, context, next_state): """Block quote.""" indented, indent, line_offset, blank_finish = \ self.state_machine.get_indented() blockquote, messages = self.block_quote(indented, line_offset) self.parent += blockquote self.parent += messages if not blank_finish: self.parent += self.unindent_warning('Block quote') return context, next_state, [] def block_quote(self, indented, line_offset): blockquote_lines, attribution_lines, attribution_offset = \ self.check_attribution(indented, line_offset) blockquote = nodes.block_quote() self.nested_parse(blockquote_lines, line_offset, blockquote) messages = [] if attribution_lines: attribution, messages = self.parse_attribution(attribution_lines, attribution_offset) blockquote += attribution return blockquote, messages # u'\u2014' is an em-dash: attribution_pattern = re.compile(ur'(---?(?!-)|\u2014) *(?=[^ \n])') def check_attribution(self, indented, line_offset): """ Check for an attribution in the last contiguous block of `indented`. * First line after last blank line must begin with "--" (etc.). * Every line after that must have consistent indentation. Return a 3-tuple: (block quote lines, attribution lines, attribution offset). """ #import pdb ; pdb.set_trace() blank = None nonblank_seen = None indent = 0 for i in range(len(indented) - 1, 0, -1): # don't check first line this_line_blank = not indented[i].strip() if nonblank_seen and this_line_blank: match = self.attribution_pattern.match(indented[i + 1]) if match: blank = i break elif not this_line_blank: nonblank_seen = 1 if blank and len(indented) - blank > 2: # multi-line attribution indent = (len(indented[blank + 2]) - len(indented[blank + 2].lstrip())) for j in range(blank + 3, len(indented)): if ( indented[j] # may be blank last line and indent != (len(indented[j]) - len(indented[j].lstrip()))): # bad shape blank = None break if blank: a_lines = indented[blank + 1:] a_lines.trim_left(match.end(), end=1) a_lines.trim_left(indent, start=1) return (indented[:blank], a_lines, line_offset + blank + 1) else: return (indented, None, None) def parse_attribution(self, indented, line_offset): text = '\n'.join(indented).rstrip() lineno = self.state_machine.abs_line_number() + line_offset textnodes, messages = self.inline_text(text, lineno) node = nodes.attribution(text, '', *textnodes) node.line = lineno return node, messages def bullet(self, match, context, next_state): """Bullet list item.""" bulletlist = nodes.bullet_list() self.parent += bulletlist bulletlist['bullet'] = match.string[0] i, blank_finish = self.list_item(match.end()) bulletlist += i offset = self.state_machine.line_offset + 1 # next line new_line_offset, blank_finish = self.nested_list_parse( self.state_machine.input_lines[offset:], input_offset=self.state_machine.abs_line_offset() + 1, node=bulletlist, initial_state='BulletList', blank_finish=blank_finish) self.goto_line(new_line_offset) if not blank_finish: self.parent += self.unindent_warning('Bullet list') return [], next_state, [] def list_item(self, indent): if self.state_machine.line[indent:]: indented, line_offset, blank_finish = ( self.state_machine.get_known_indented(indent)) else: indented, indent, line_offset, blank_finish = ( self.state_machine.get_first_known_indented(indent)) listitem = nodes.list_item('\n'.join(indented)) if indented: self.nested_parse(indented, input_offset=line_offset, node=listitem) return listitem, blank_finish def enumerator(self, match, context, next_state): """Enumerated List Item""" format, sequence, text, ordinal = self.parse_enumerator(match) if not self.is_enumerated_list_item(ordinal, sequence, format): raise statemachine.TransitionCorrection('text') enumlist = nodes.enumerated_list() self.parent += enumlist if sequence == '#': enumlist['enumtype'] = 'arabic' else: enumlist['enumtype'] = sequence enumlist['prefix'] = self.enum.formatinfo[format].prefix enumlist['suffix'] = self.enum.formatinfo[format].suffix if ordinal != 1: enumlist['start'] = ordinal msg = self.reporter.info( 'Enumerated list start value not ordinal-1: "%s" (ordinal %s)' % (text, ordinal), line=self.state_machine.abs_line_number()) self.parent += msg listitem, blank_finish = self.list_item(match.end()) enumlist += listitem offset = self.state_machine.line_offset + 1 # next line newline_offset, blank_finish = self.nested_list_parse( self.state_machine.input_lines[offset:], input_offset=self.state_machine.abs_line_offset() + 1, node=enumlist, initial_state='EnumeratedList', blank_finish=blank_finish, extra_settings={'lastordinal': ordinal, 'format': format, 'auto': sequence == '#'}) self.goto_line(newline_offset) if not blank_finish: self.parent += self.unindent_warning('Enumerated list') return [], next_state, [] def parse_enumerator(self, match, expected_sequence=None): """ Analyze an enumerator and return the results. :Return: - the enumerator format ('period', 'parens', or 'rparen'), - the sequence used ('arabic', 'loweralpha', 'upperroman', etc.), - the text of the enumerator, stripped of formatting, and - the ordinal value of the enumerator ('a' -> 1, 'ii' -> 2, etc.;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -