def scanHeadlineForOptions(self, p): '''Return a dictionary containing the options implied by p's headline.''' h = p.h.strip() if p == self.topNode: return {} # Don't mess with the root node. if g.match_word(h, 0, self.getOption('@rst-options')): return self.scanOptions(p, p.b) else: # Careful: can't use g.match_word because options may have '-' chars. i = g.skip_id(h, 0, chars='@-') word = h[0:i] for option, ivar, val in ( ('@rst-no-head', 'ignore_this_headline', True), ('@rst-head', 'show_this_headline', True), ('@rst-no-headlines', 'show_headlines', False), ('@rst-ignore', 'ignore_this_tree', True), ('@rst-ignore-node', 'ignore_this_node', True), ('@rst-ignore-tree', 'ignore_this_tree', True), # ('@rst-preformat','preformat_this_node',True), ): name = self.getOption(option) if name: d = {name: val} return d return {}
def adjustDefStart(self, s, i): '''A hook to allow the Python importer to adjust the start of a class or function to include decorators. ''' # Invariant: i does not change. # Invariant: start is the present return value. try: assert s[i] != '\n' start = j = g.find_line_start(s, i) if i > 0 else 0 # g.trace('entry',j,i,repr(s[j:i+10])) assert j == 0 or s[j - 1] == '\n' while j > 0: progress = j j1 = j = g.find_line_start(s, j - 2) # g.trace('line',repr(s[j:progress])) j = g.skip_ws(s, j) if not g.match(s, j, '@'): break k = g.skip_id(s, j + 1) word = s[j:k] # Leo directives halt the scan. if word and word in g.globalDirectiveList: break # A decorator. start = j = j1 assert j < progress # g.trace('**returns %s, %s' % (repr(s[start:i]),repr(s[i:i+20]))) return start except AssertionError: g.es_exception() return i
def parseHeadline(s): """ Parse a headline of the form @kind:name=val Return (kind,name,val). Leo 4.11.1: Ignore everything after @data name. """ kind = name = val = None if g.match(s, 0, g.u('@')): i = g.skip_id(s, 1, chars=g.u('-')) i = g.skip_ws(s, i) kind = s[1:i].strip() if kind: # name is everything up to '=' if kind == g.u('data'): # i = g.skip_ws(s,i) j = s.find(g.u(' '), i) if j == -1: name = s[i:].strip() else: name = s[i:j].strip() else: j = s.find(g.u('='), i) if j == -1: name = s[i:].strip() else: name = s[i:j].strip() # val is everything after the '=' val = s[j + 1:].strip() # g.trace("%50s %10s %s" %(name,kind,val)) return kind, name, val
def scanHeadlineForOptions (self,p): '''Return a dictionary containing the options implied by p's headline.''' h = p.h.strip() if p == self.topNode: return {} # Don't mess with the root node. if g.match_word(h,0,self.getOption('@rst-options')): return self.scanOptions(p,p.b) else: # Careful: can't use g.match_word because options may have '-' chars. i = g.skip_id(h,0,chars='@-') word = h[0:i] for option,ivar,val in ( ('@rst-no-head','ignore_this_headline',True), ('@rst-head' ,'show_this_headline',True), ('@rst-no-headlines','show_headlines',False), ('@rst-ignore','ignore_this_tree',True), ('@rst-ignore-node','ignore_this_node',True), ('@rst-ignore-tree','ignore_this_tree',True), # ('@rst-preformat','preformat_this_node',True), ): name = self.getOption(option) if name: d = { name: val } return d return {}
def comment_leo_lines(p): '''Replace lines with Leonine syntax with special comments.''' # Choose the comment string so it appears nowhere in s. s0 = p.b n = 5 while s0.find('#' + ('!' * n)) > -1: n += 1 comment = '#' + ('!' * n) # Create a dict of directives. d = {} for z in g.globalDirectiveList: d[z] = True # Convert all Leonine lines to special comments. i, lines, result = 0, g.splitLines(s0), [] while i < len(lines): progress = i s = lines[i] # Comment out any containing a section reference. j = s.find('<<') k = s.find('>>') if j > -1 else -1 if -1 < j < k: result.append(comment + s) # Generate a properly-indented pass line. j2 = g.skip_ws(s, 0) result.append('%spass\n' % (' ' * j2)) elif s.lstrip().startswith('@'): # Comment out all other Leonine constructs. if starts_doc_part(s): # Comment the entire doc part, until @c or @code. result.append(comment + s) i += 1 while i < len(lines): s = lines[i] result.append(comment + s) i += 1 if ends_doc_part(s): break else: j = g.skip_ws(s, 0) assert s[j] == '@' j += 1 k = g.skip_id(s, j, chars='-') if k > j: word = s[j: k] if word == 'others': # Remember the original @others line. result.append(comment + s) # Generate a properly-indented pass line. result.append('%spass\n' % (' ' * (j - 1))) else: # Comment only Leo directives, not decorators. result.append(comment + s if word in d else s) else: result.append(s) else: # A plain line. result.append(s) if i == progress: i += 1 return comment, ''.join(result)
def write_slides(self, p): """Convert p's children to slides.""" c = self.c p = p.copy() h = p.h i = g.skip_id(h, 1) # Skip the '@' kind, fn = h[:i].strip(), h[i:].strip() if not fn: g.error(f"{kind} requires file name") return title = p.firstChild().h if p and p.firstChild() else '<no slide>' title = title.strip().capitalize() n_tot = p.numberOfChildren() n = 1 d = c.scanAllDirectives(p) self.encoding = d.get('encoding') or 'utf-8' self.path = d.get('path') or '' for child in p.children(): # Compute the slide's file name. fn2, ext = g.os_path_splitext(fn) fn2 = f"{fn2}-{n:03d}{ext}" # Use leading zeros for :glob:. n += 1 # Write the rst sources. self.result_list = [] self.writeSlideTitle(title, n - 1, n_tot) self.result_list.append(child.b) source = self.compute_result() self.write_docutils_files(fn2, p, source)
def parseHeadline(s): """ Parse a headline of the form @kind:name=val Return (kind,name,val). Leo 4.11.1: Ignore everything after @data name. """ kind = name = val = None if g.match(s, 0, g.u('@')): i = g.skip_id(s, 1, chars=g.u('-')) i = g.skip_ws(s, i) kind = s[1: i].strip() if kind: # name is everything up to '=' if kind == g.u('data'): # i = g.skip_ws(s,i) j = s.find(g.u(' '), i) if j == -1: name = s[i:].strip() else: name = s[i: j].strip() else: j = s.find(g.u('='), i) if j == -1: name = s[i:].strip() else: name = s[i: j].strip() # val is everything after the '=' val = s[j + 1:].strip() # g.trace("%50s %10s %s" %(name,kind,val)) return kind, name, val
def adjustDefStart(self, s, i): '''A hook to allow the Python importer to adjust the start of a class or function to include decorators. ''' # Invariant: i does not change. # Invariant: start is the present return value. try: assert s[i] != '\n' start = j = g.find_line_start(s, i) if i > 0 else 0 # g.trace('entry',j,i,repr(s[j:i+10])) assert j == 0 or s[j - 1] == '\n' while j > 0: progress = j j1 = j = g.find_line_start(s, j - 2) # g.trace('line',repr(s[j:progress])) j = g.skip_ws(s, j) if not g.match(s, j, '@'): break k = g.skip_id(s, j + 1) word = s[j: k] # Leo directives halt the scan. if word and word in g.globalDirectiveList: break # A decorator. start = j = j1 assert j < progress # g.trace('**returns %s, %s' % (repr(s[start:i]),repr(s[i:i+20]))) return start except AssertionError: g.es_exception() return i
def comment_leo_lines(p): '''Replace lines with Leonine syntax with special comments.''' # Choose the comment string so it appears nowhere in s. s0 = p.b n = 5 while s0.find('#' + ('!' * n)) > -1: n += 1 comment = '#' + ('!' * n) # Create a dict of directives. d = {} for z in g.globalDirectiveList: d[z] = True # Convert all Leonine lines to special comments. i, lines, result = 0, g.splitLines(s0), [] while i < len(lines): progress = i s = lines[i] # Comment out any containing a section reference. j = s.find('<<') k = s.find('>>') if j > -1 else -1 if -1 < j < k: result.append(comment + s) # Generate a properly-indented pass line. j2 = g.skip_ws(s, 0) result.append('%spass\n' % (' ' * j2)) elif s.lstrip().startswith('@'): # Comment out all other Leonine constructs. if starts_doc_part(s): # Comment the entire doc part, until @c or @code. result.append(comment + s) i += 1 while i < len(lines): s = lines[i] result.append(comment + s) i += 1 if ends_doc_part(s): break else: j = g.skip_ws(s, 0) assert s[j] == '@' j += 1 k = g.skip_id(s, j, chars='-') if k > j: word = s[j:k] if word == 'others': # Remember the original @others line. result.append(comment + s) # Generate a properly-indented pass line. result.append('%spass\n' % (' ' * (j - 1))) else: # Comment only Leo directives, not decorators. result.append(comment + s if word in d else s) else: result.append(s) else: # A plain line. result.append(s) if i == progress: i += 1 return comment, ''.join(result)
def split_arg_line(self,s): ''' Split line s into a head and tail. The head is a python id; the tail is everything else. ''' i = g.skip_id(s,0,chars='_') head = s[:i] tail = s[i:].strip() return head,tail
def refreshFromDisk(self, event=None): '''Refresh an @<file> node from disk.''' trace = False and not g.unitTesting c, p, u = self, self.p, self.undoer c.nodeConflictList = [] fn = p.anyAtFileNodeName() shouldDelete = (not g.SQLITE) or (c.sqlite_connection is None) if fn: b = u.beforeChangeTree(p) redraw_flag = True at = c.atFileCommands c.recreateGnxDict() # Fix bug 1090950 refresh from disk: cut node ressurection. i = g.skip_id(p.h, 0, chars='@') word = p.h[0:i] if word == '@auto': # This includes @auto-* if shouldDelete: p.deleteAllChildren() # Fix #451: refresh-from-disk selects wrong node. p = at.readOneAtAutoNode(fn, p) elif word in ('@thin', '@file'): if shouldDelete: p.deleteAllChildren() at.read(p, force=True) elif word in ('@clean', ): # Wishlist 148: use @auto parser if the node is empty. if p.b.strip() or p.hasChildren(): at.readOneAtCleanNode(p) else: # Fix #451: refresh-from-disk selects wrong node. p = at.readOneAtAutoNode(fn, p) elif word == '@shadow': if shouldDelete: p.deleteAllChildren() at.read(p, force=True, atShadow=True) elif word == '@edit': if shouldDelete: p.deleteAllChildren() at.readOneAtEditNode(fn, p) else: g.es_print('can not refresh from disk\n%r' % p.h) redraw_flag = False else: g.warning('not an @<file> node:\n%r' % (p.h)) redraw_flag = False if redraw_flag: # Fix #451: refresh-from-disk selects wrong node. c.selectPosition(p) u.afterChangeTree(p, command='refresh-from-disk', bunch=b) # Create the 'Recovered Nodes' tree. c.fileCommands.handleNodeConflicts() t1 = time.clock() c.redraw() t2 = time.clock() if trace: n = sum([1 for z in p.self_and_subtree()]) h = sum([hash(z.h) for z in p.self_and_subtree()]) g.trace('%s nodes, hash: %s in %5.2f sec. %r' % (n, h, (t2 - t1), p.h))
def refreshFromDisk(self, event=None): """Refresh an @<file> node from disk.""" c, p, u = self, self.p, self.undoer c.nodeConflictList = [] fn = p.anyAtFileNodeName() shouldDelete = c.sqlite_connection is None if not fn: g.warning(f"not an @<file> node: {p.h!r}") return # #1603. if os.path.isdir(fn): g.warning(f"not a file: {fn!r}") return b = u.beforeChangeTree(p) redraw_flag = True at = c.atFileCommands c.recreateGnxDict() # Fix bug 1090950 refresh from disk: cut node ressurection. i = g.skip_id(p.h, 0, chars='@') word = p.h[0:i] if word == '@auto': # This includes @auto-* if shouldDelete: p.v._deleteAllChildren() # Fix #451: refresh-from-disk selects wrong node. p = at.readOneAtAutoNode(p) elif word in ('@thin', '@file'): if shouldDelete: p.v._deleteAllChildren() at.read(p) elif word == '@clean': # Wishlist 148: use @auto parser if the node is empty. if p.b.strip() or p.hasChildren(): at.readOneAtCleanNode(p) else: # Fix #451: refresh-from-disk selects wrong node. p = at.readOneAtAutoNode(p) elif word == '@shadow': if shouldDelete: p.v._deleteAllChildren() at.read(p) elif word == '@edit': at.readOneAtEditNode(fn, p) # Always deletes children. elif word == '@asis': # Fix #1067. at.readOneAtAsisNode(fn, p) # Always deletes children. else: g.es_print(f"can not refresh from disk\n{p.h!r}") redraw_flag = False if redraw_flag: # Fix #451: refresh-from-disk selects wrong node. c.selectPosition(p) u.afterChangeTree(p, command='refresh-from-disk', bunch=b) # Create the 'Recovered Nodes' tree. c.fileCommands.handleNodeConflicts() c.redraw()
def get_kind(self, p): '''Return the proper rendering kind for node p.''' pc = self; h = p.h if h.startswith('@'): i = g.skip_id(h, 1, chars='-') word = h[1: i].lower().strip() if word in pc.dispatch_dict: return word # To do: look at ancestors, or uA's. return pc.default_kind # The default.
def refreshFromDisk(self, event=None): '''Refresh an @<file> node from disk.''' trace = False and not g.unitTesting c, p, u = self, self.p, self.undoer c.nodeConflictList = [] fn = p.anyAtFileNodeName() shouldDelete = (not g.SQLITE) or (c.sqlite_connection is None) if fn: b = u.beforeChangeTree(p) redraw_flag = True at = c.atFileCommands c.recreateGnxDict() # Fix bug 1090950 refresh from disk: cut node ressurection. i = g.skip_id(p.h, 0, chars='@') word = p.h[0: i] if word == '@auto': # This includes @auto-* if shouldDelete: p.deleteAllChildren() # Fix #451: refresh-from-disk selects wrong node. p = at.readOneAtAutoNode(fn, p) elif word in ('@thin', '@file'): if shouldDelete: p.deleteAllChildren() at.read(p, force=True) elif word in ('@clean',): # Wishlist 148: use @auto parser if the node is empty. if p.b.strip() or p.hasChildren(): at.readOneAtCleanNode(p) else: # Fix #451: refresh-from-disk selects wrong node. p = at.readOneAtAutoNode(fn, p) elif word == '@shadow': if shouldDelete: p.deleteAllChildren() at.read(p, force=True, atShadow=True) elif word == '@edit': if shouldDelete: p.deleteAllChildren() at.readOneAtEditNode(fn, p) else: g.es_print('can not refresh from disk\n%r' % p.h) redraw_flag = False else: g.warning('not an @<file> node:\n%r' % (p.h)) redraw_flag = False if redraw_flag: # Fix #451: refresh-from-disk selects wrong node. c.selectPosition(p) u.afterChangeTree(p, command='refresh-from-disk', bunch=b) # Create the 'Recovered Nodes' tree. c.fileCommands.handleNodeConflicts() t1 = time.clock() c.redraw() t2 = time.clock() if trace: n = sum([1 for z in p.self_and_subtree()]) h = sum([hash(z.h) for z in p.self_and_subtree()]) g.trace('%s nodes, hash: %s in %5.2f sec. %r' % (n, h, (t2-t1), p.h))
def remove_directives(self, s): lines = g.splitLines(s) result = [] for s in lines: if s.startswith('@'): i = g.skip_id(s, 1) word = s[1: i] if word in g.globalDirectiveList: continue result.append(s) return ''.join(result)
def refreshFromDisk(self, event=None): '''Refresh an @<file> node from disk.''' c, p, u = self, self.p, self.undoer c.nodeConflictList = [] fn = p.anyAtFileNodeName() shouldDelete = (not g.SQLITE) or (c.sqlite_connection is None) if not fn: g.warning('not an @<file> node:\n%r' % (p.h)) return b = u.beforeChangeTree(p) redraw_flag = True at = c.atFileCommands c.recreateGnxDict() # Fix bug 1090950 refresh from disk: cut node ressurection. i = g.skip_id(p.h, 0, chars='@') word = p.h[0: i] if word == '@auto': # This includes @auto-* if shouldDelete: p.v._deleteAllChildren() # Fix #451: refresh-from-disk selects wrong node. p = at.readOneAtAutoNode(fn, p) elif word in ('@thin', '@file'): if shouldDelete: p.v._deleteAllChildren() at.read(p, force=True) elif word == '@clean': # Wishlist 148: use @auto parser if the node is empty. if p.b.strip() or p.hasChildren(): at.readOneAtCleanNode(p) else: # Fix #451: refresh-from-disk selects wrong node. p = at.readOneAtAutoNode(fn, p) elif word == '@shadow': if shouldDelete: p.v._deleteAllChildren() at.read(p, force=True, atShadow=True) elif word == '@edit': at.readOneAtEditNode(fn, p) # Always deletes children. elif word == '@asis': # Fix #1067. at.readOneAtAsisNode(fn, p) # Always deletes children. else: g.es_print('can not refresh from disk\n%r' % p.h) redraw_flag = False if redraw_flag: # Fix #451: refresh-from-disk selects wrong node. c.selectPosition(p) u.afterChangeTree(p, command='refresh-from-disk', bunch=b) # Create the 'Recovered Nodes' tree. c.fileCommands.handleNodeConflicts() c.redraw()
def refresh_rclick_cb(): # Try to fix bug 1090950 refresh from disk: cut node ressurection. if 0: # This doesn't work--seems safer than previous code. def delete_children(p): # c.fileCommands.gnxDict = {} # Essential to fix the bug, but breaks clone links! while p.hasChildren(): child = p.firstChild() child.doDelete() at = c.atFileCommands p = c.p fn = p.anyAtFileNodeName() if not fn: return i = g.skip_id(p.h, 0, chars='@') word = p.h[0:i] if word == '@auto': delete_children(p) at.readOneAtAutoNode(fn, p) elif word in ('@thin', '@file'): delete_children(p) at.read(p, force=True) elif word == '@shadow ': delete_children(p) at.read(p, force=True, atShadow=True) elif word == '@edit': delete_children(p) at.readOneAtEditNode(fn, p) else: g.trace('unknown:', word) c.redraw() else: # Old code. vnodes = [i.v for i in c.getSelectedPositions()] for v in vnodes: p = c.vnode2position(v) assert (c.positionExists(p)) c.selectPosition(p) if typ.startswith('@auto'): c.readAtAutoNodes() elif typ == '@thin' or typ == '@file': c.readAtFileNodes() elif typ == '@shadow': c.readAtShadowNodes() else: c.readAtFileNodes()
def refresh_rclick_cb(): # Try to fix bug 1090950 refresh from disk: cut node ressurection. if 0: # This doesn't work--seems safer than previous code. def delete_children(p): # c.fileCommands.gnxDict = {} # Essential to fix the bug, but breaks clone links! while p.hasChildren(): child = p.firstChild() child.doDelete() at = c.atFileCommands p = c.p fn = p.anyAtFileNodeName() if not fn: return i = g.skip_id(p.h,0,chars='@') word=p.h[0:i] if word == '@auto': delete_children(p) at.readOneAtAutoNode(fn,p) elif word in ('@thin','@file'): delete_children(p) at.read(p,force=True) elif word == '@shadow ': delete_children(p) at.read(p,force=True,atShadow=True) elif word == '@edit': delete_children(p) at.readOneAtEditNode(fn,p) else: g.trace('unknown:',word) c.redraw() else: # Old code. vnodes = [i.v for i in c.getSelectedPositions()] for v in vnodes: p = c.vnode2position(v) assert(c.positionExists(p)) c.selectPosition(p) if typ.startswith('@auto'): c.readAtAutoNodes() elif typ =='@thin' or typ == '@file': c.readAtFileNodes() elif typ =='@shadow': c.readAtShadowNodes() else: c.readAtFileNodes()
def parseOptionLine(self, s): '''Parse a line containing name=val and return (name,value) or None. If no value is found, default to True.''' s = s.strip() if s.endswith(','): s = s[:-1] # Get name. Names may contain '-' and '_'. i = g.skip_id(s, 0, chars='-_') name = s[:i] if not name: return None j = g.skip_ws(s, i) if g.match(s, j, '='): val = s[j + 1:].strip() # g.trace(val) return name, val else: # g.trace('*True') return name, 'True'
def parseOptionLine (self,s): '''Parse a line containing name=val and return (name,value) or None. If no value is found, default to True.''' s = s.strip() if s.endswith(','): s = s[:-1] # Get name. Names may contain '-' and '_'. i = g.skip_id(s,0,chars='-_') name = s [:i] if not name: return None j = g.skip_ws(s,i) if g.match(s,j,'='): val = s [j+1:].strip() # g.trace(val) return name,val else: # g.trace('*True') return name,'True'
def get_kind(self, p): '''Return the proper rendering kind for node p.''' c, h, pc = self.c, p.h, self if h.startswith('@'): i = g.skip_id(h, 1, chars='-') word = h[1: i].lower().strip() if word in pc.dispatch_dict: return word # 2016/03/25: Honor @language colorizer = c.frame.body.colorizer language = colorizer.scanColorDirectives(p) if got_markdown and language in ('md', 'markdown'): return language elif got_docutils and language in ('rest', 'rst'): return language elif language == 'html': return 'html' else: # To do: look at ancestors, or uA's. return pc.default_kind # The default.
def get_kind(self, p): '''Return the proper rendering kind for node p.''' c, h, pc = self.c, p.h, self if h.startswith('@'): i = g.skip_id(h, 1, chars='-') word = h[1:i].lower().strip() if word in pc.dispatch_dict: return word # 2016/03/25: Honor @language colorizer = c.frame.body.colorizer language = colorizer.scanLanguageDirectives(p) if got_markdown and language in ('md', 'markdown'): return language elif got_docutils and language in ('rest', 'rst'): return language elif language == 'html': return 'html' else: # To do: look at ancestors, or uA's. return pc.default_kind # The default.
def writeHeadlineHelper(self, p): h = p.h.strip() # Remove any headline command before writing the headline. i = g.skip_ws(h, 0) i = g.skip_id(h, 0, chars='@-') word = h[:i].strip() if word: # Never generate a section for @rst-option or @rst-options or @rst-no-head. if word in ('@rst-option', '@rst-options', '@rst-no-head', '@rst-no-leadlines'): return # Remove all other headline commands from the headline. # self.getOption('ignore_node_prefix'), # self.getOption('ignore_tree_prefix'), # self.getOption('show_headline_prefix'), ### for prefix in self.headlineCommands: for prefix in ('@rst-ignore-node', '@rst-ignore-tree', '@rst-ignore'): if word == prefix: h = h[len(word):].strip() break # New in Leo 4.4.4. # if word.startswith('@'): # if self.getOption('strip_at_file_prefixes'): # for s in ('@auto','@file','@nosent','@thin',): # if g.match_word(word,0,s): # h = h [len(s):].strip() if not h.strip(): return if self.getOption('show_sections'): self.write(self.underline(h, p)) else: self.write('\n**%s**\n\n' % h.replace('*', ''))
def get_kind(self, p): '''Return the proper rendering kind for node p.''' trace = False and not g.unitTesting c, h, pc = self.c, p.h, self if h.startswith('@'): i = g.skip_id(h, 1, chars='-') word = h[1:i].lower().strip() if word in pc.dispatch_dict: return word # 2016/03/25: Honor @language colorizer = c.frame.body.colorizer language = colorizer.scanLanguageDirectives(p, use_default=False) # Fix #344: don't use c.target_language as a default. if trace: g.trace(repr(language)) if got_markdown and language in ('md', 'markdown'): return language elif got_docutils and language in ('rest', 'rst'): return language elif language and language in pc.dispatch_dict: return language else: # To do: look at ancestors, or uA's. return pc.default_kind # The default.
def writeHeadlineHelper (self,p): h = p.h.strip() # Remove any headline command before writing the headline. i = g.skip_ws(h,0) i = g.skip_id(h,0,chars='@-') word = h [:i].strip() if word: # Never generate a section for @rst-option or @rst-options or @rst-no-head. if word in ('@rst-option','@rst-options','@rst-no-head','@rst-no-leadlines'): return # Remove all other headline commands from the headline. # self.getOption('ignore_node_prefix'), # self.getOption('ignore_tree_prefix'), # self.getOption('show_headline_prefix'), ### for prefix in self.headlineCommands: for prefix in ('@rst-ignore-node','@rst-ignore-tree','@rst-ignore'): if word == prefix: h = h [len(word):].strip() break # New in Leo 4.4.4. # if word.startswith('@'): # if self.getOption('strip_at_file_prefixes'): # for s in ('@auto','@file','@nosent','@thin',): # if g.match_word(word,0,s): # h = h [len(s):].strip() if not h.strip(): return if self.getOption('show_sections'): self.write(self.underline(h,p)) else: self.write('\n**%s**\n\n' % h.replace('*',''))