📄 states.py
字号:
if self.check_subsection(source, style, lineno): self.new_subsection(title, lineno, messages) def check_subsection(self, source, style, lineno): """ Check for a valid subsection header. Return 1 (true) or None (false). When a new section is reached that isn't a subsection of the current section, back up the line count (use ``previous_line(-x)``), then ``raise EOFError``. The current StateMachine will finish, then the calling StateMachine can re-examine the title. This will work its way back up the calling chain until the correct section level isreached. @@@ Alternative: Evaluate the title, store the title info & level, and back up the chain until that level is reached. Store in memo? Or return in results? :Exception: `EOFError` when a sibling or supersection encountered. """ memo = self.memo title_styles = memo.title_styles mylevel = memo.section_level try: # check for existing title style level = title_styles.index(style) + 1 except ValueError: # new title style if len(title_styles) == memo.section_level: # new subsection title_styles.append(style) return 1 else: # not at lowest level self.parent += self.title_inconsistent(source, lineno) return None if level <= mylevel: # sibling or supersection memo.section_level = level # bubble up to parent section if len(style) == 2: memo.section_bubble_up_kludge = 1 # back up 2 lines for underline title, 3 for overline title self.state_machine.previous_line(len(style) + 1) raise EOFError # let parent section re-evaluate if level == mylevel + 1: # immediate subsection return 1 else: # invalid subsection self.parent += self.title_inconsistent(source, lineno) return None def title_inconsistent(self, sourcetext, lineno): error = self.reporter.severe( 'Title level inconsistent:', nodes.literal_block('', sourcetext), line=lineno) return error def new_subsection(self, title, lineno, messages): """Append new subsection to document tree. On return, check level.""" memo = self.memo mylevel = memo.section_level memo.section_level += 1 section_node = nodes.section() self.parent += section_node textnodes, title_messages = self.inline_text(title, lineno) titlenode = nodes.title(title, '', *textnodes) name = normalize_name(titlenode.astext()) section_node['names'].append(name) section_node += titlenode section_node += messages section_node += title_messages self.document.note_implicit_target(section_node, section_node) offset = self.state_machine.line_offset + 1 absoffset = self.state_machine.abs_line_offset() + 1 newabsoffset = self.nested_parse( self.state_machine.input_lines[offset:], input_offset=absoffset, node=section_node, match_titles=1) self.goto_line(newabsoffset) if memo.section_level <= mylevel: # can't handle next section? raise EOFError # bubble up to supersection # reset section_level; next pass will detect it properly memo.section_level = mylevel def paragraph(self, lines, lineno): """ Return a list (paragraph & messages) & a boolean: literal_block next? """ data = '\n'.join(lines).rstrip() if re.search(r'(?<!\\)(\\\\)*::$', data): if len(data) == 2: return [], 1 elif data[-3] in ' \n': text = data[:-3].rstrip() else: text = data[:-1] literalnext = 1 else: text = data literalnext = 0 textnodes, messages = self.inline_text(text, lineno) p = nodes.paragraph(data, '', *textnodes) p.line = lineno return [p] + messages, literalnext def inline_text(self, text, lineno): """ Return 2 lists: nodes (text and inline elements), and system_messages. """ return self.inliner.parse(text, lineno, self.memo, self.parent) def unindent_warning(self, node_name): return self.reporter.warning( '%s ends without a blank line; unexpected unindent.' % node_name, line=(self.state_machine.abs_line_number() + 1))def build_regexp(definition, compile=1): """ Build, compile and return a regular expression based on `definition`. :Parameter: `definition`: a 4-tuple (group name, prefix, suffix, parts), where "parts" is a list of regular expressions and/or regular expression definitions to be joined into an or-group. """ name, prefix, suffix, parts = definition part_strings = [] for part in parts: if type(part) is TupleType: part_strings.append(build_regexp(part, None)) else: part_strings.append(part) or_group = '|'.join(part_strings) regexp = '%(prefix)s(?P<%(name)s>%(or_group)s)%(suffix)s' % locals() if compile: return re.compile(regexp, re.UNICODE) else: return regexpclass Inliner: """ Parse inline markup; call the `parse()` method. """ def __init__(self): self.implicit_dispatch = [(self.patterns.uri, self.standalone_uri),] """List of (pattern, bound method) tuples, used by `self.implicit_inline`.""" def init_customizations(self, settings): """Setting-based customizations; run when parsing begins.""" if settings.pep_references: self.implicit_dispatch.append((self.patterns.pep, self.pep_reference)) if settings.rfc_references: self.implicit_dispatch.append((self.patterns.rfc, self.rfc_reference)) def parse(self, text, lineno, memo, parent): # Needs to be refactored for nested inline markup. # Add nested_parse() method? """ Return 2 lists: nodes (text and inline elements), and system_messages. Using `self.patterns.initial`, a pattern which matches start-strings (emphasis, strong, interpreted, phrase reference, literal, substitution reference, and inline target) and complete constructs (simple reference, footnote reference), search for a candidate. When one is found, check for validity (e.g., not a quoted '*' character). If valid, search for the corresponding end string if applicable, and check it for validity. If not found or invalid, generate a warning and ignore the start-string. Implicit inline markup (e.g. standalone URIs) is found last. """ self.reporter = memo.reporter self.document = memo.document self.language = memo.language self.parent = parent pattern_search = self.patterns.initial.search dispatch = self.dispatch remaining = escape2null(text) processed = [] unprocessed = [] messages = [] while remaining: match = pattern_search(remaining) if match: groups = match.groupdict() method = dispatch[groups['start'] or groups['backquote'] or groups['refend'] or groups['fnend']] before, inlines, remaining, sysmessages = method(self, match, lineno) unprocessed.append(before) messages += sysmessages if inlines: processed += self.implicit_inline(''.join(unprocessed), lineno) processed += inlines unprocessed = [] else: break remaining = ''.join(unprocessed) + remaining if remaining: processed += self.implicit_inline(remaining, lineno) return processed, messages openers = '\'"([{<' closers = '\'")]}>' start_string_prefix = (r'((?<=^)|(?<=[-/: \n%s]))' % re.escape(openers)) end_string_suffix = (r'((?=$)|(?=[-/:.,;!? \n\x00%s]))' % re.escape(closers)) non_whitespace_before = r'(?<![ \n])' non_whitespace_escape_before = r'(?<![ \n\x00])' non_whitespace_after = r'(?![ \n])' # Alphanumerics with isolated internal [-._] chars (i.e. not 2 together): simplename = r'(?:(?!_)\w)+(?:[-._](?:(?!_)\w)+)*' # Valid URI characters (see RFC 2396 & RFC 2732); # final \x00 allows backslash escapes in URIs: uric = r"""[-_.!~*'()[\];/:@&=+$,%a-zA-Z0-9\x00]""" # Delimiter indicating the end of a URI (not part of the URI): uri_end_delim = r"""[>]""" # Last URI character; same as uric but no punctuation: urilast = r"""[_~*/=+a-zA-Z0-9]""" # End of a URI (either 'urilast' or 'uric followed by a # uri_end_delim'): uri_end = r"""(?:%(urilast)s|%(uric)s(?=%(uri_end_delim)s))""" % locals() emailc = r"""[-_!~*'{|}/#?^`&=+$%a-zA-Z0-9\x00]""" email_pattern = r""" %(emailc)s+(?:\.%(emailc)s+)* # name (?<!\x00)@ # at %(emailc)s+(?:\.%(emailc)s*)* # host %(uri_end)s # final URI char """ parts = ('initial_inline', start_string_prefix, '', [('start', '', non_whitespace_after, # simple start-strings [r'\*\*', # strong r'\*(?!\*)', # emphasis but not strong r'``', # literal r'_`', # inline internal target r'\|(?!\|)'] # substitution reference ), ('whole', '', end_string_suffix, # whole constructs [# reference name & end-string r'(?P<refname>%s)(?P<refend>__?)' % simplename, ('footnotelabel', r'\[', r'(?P<fnend>\]_)', [r'[0-9]+', # manually numbered r'\#(%s)?' % simplename, # auto-numbered (w/ label?) r'\*', # auto-symbol r'(?P<citationlabel>%s)' % simplename] # citation reference ) ] ), ('backquote', # interpreted text or phrase reference '(?P<role>(:%s:)?)' % simplename, # optional role non_whitespace_after, ['`(?!`)'] # but not literal ) ] ) patterns = Struct( initial=build_regexp(parts), emphasis=re.compile(non_whitespace_escape_before + r'(\*)' + end_string_suffix), strong=re.compile(non_whitespace_escape_before + r'(\*\*)' + end_string_suffix), interpreted_or_phrase_ref=re.compile( r""" %(non_whitespace_escape_before)s ( ` (?P<suffix> (?P<role>:%(simplename)s:)? (?P<refend>__?)? ) ) %(end_string_suffix)s """ % locals(), re.VERBOSE | re.UNICODE), embedded_uri=re.compile( r""" ( (?:[ \n]+|^) # spaces or beginning of line/string < # open bracket %(non_whitespace_after)s ([^<>\x00]+) # anything but angle brackets & nulls %(non_whitespace_before)s > # close bracket w/o whitespace before ) $ # end of string """ % locals(), re.VERBOSE), literal=re.compile(non_whitespace_before + '(``)' + end_string_suffix), target=re.compile(non_whitespace_escape_before + r'(`)' + end_string_suffix), substitution_ref=re.compile(non_whitespace_escape_before + r'(\|_{0,2})' + end_string_suffix), email=re.compile(email_pattern % locals() + '$', re.VERBOSE), uri=re.compile( (r""" %(start_string_prefix)s (?P<whole> (?P<absolute> # absolute URI (?P<scheme> # scheme (http, ftp, mailto) [a-zA-Z][a-zA-Z0-9.+-]* ) : ( ( # either: (//?)? # hierarchical URI %(uric)s* # URI characters %(uri_end)s # final URI char ) ( # optional query
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -