Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#@+leo-ver=5-thin 

2#@+node:ekr.20140725190808.18066: * @file ../plugins/importers/markdown.py 

3"""The @auto importer for the markdown language.""" 

4import re 

5from leo.core import leoGlobals as g 

6from leo.plugins.importers import linescanner 

7Importer = linescanner.Importer 

8#@+others 

9#@+node:ekr.20161124192050.2: ** class Markdown_Importer 

10class Markdown_Importer(Importer): 

11 """The importer for the markdown lanuage.""" 

12 

13 def __init__(self, importCommands, **kwargs): 

14 """Markdown_Importer.__init__""" 

15 super().__init__(importCommands, 

16 language='md', 

17 state_class=None, 

18 strict=False, 

19 ) 

20 self.underline_dict = {} 

21 

22 #@+others 

23 #@+node:ekr.20161124193148.1: *3* md_i.gen_lines & helpers 

24 def gen_lines(self, lines, parent): 

25 """Node generator for markdown importer.""" 

26 if all(s.isspace() for s in lines): 

27 return 

28 self.vnode_info = { 

29 # Keys are vnodes, values are inner dicts. 

30 parent.v: { 

31 'lines': [], 

32 } 

33 } 

34 # We may as well do this first. See warning below. 

35 self.stack = [parent] 

36 in_code = False 

37 

38 skip = 0 

39 for i, line in enumerate(lines): 

40 top = self.stack[-1] 

41 level, name = self.is_hash(line) 

42 if skip > 0: 

43 skip -= 1 

44 elif not in_code and self.lookahead_underline(i, lines): 

45 level = 1 if lines[i + 1].startswith('=') else 2 

46 self.make_node(level, line) 

47 skip = 1 

48 elif not in_code and name: 

49 self.make_node(level, name) 

50 elif i == 0: 

51 self.make_decls_node(line) 

52 elif in_code: 

53 if line.startswith("```"): 

54 in_code = False 

55 self.add_line(top, line) 

56 elif line.startswith("```"): 

57 in_code = True 

58 self.add_line(top, line) 

59 else: 

60 self.add_line(top, line) 

61 #@+node:ekr.20161124193148.2: *4* md_i.find_parent 

62 def find_parent(self, level, h): 

63 """ 

64 Return the parent at the indicated level, allocating 

65 place-holder nodes as necessary. 

66 """ 

67 assert level >= 0 

68 while level < len(self.stack): 

69 self.stack.pop() 

70 top = self.stack[-1] 

71 if 1: # Experimental fix for #877. 

72 if level > len(self.stack): 

73 print('') 

74 g.trace('Unexpected markdown level for: %s' % h) 

75 print('') 

76 while level > len(self.stack): 

77 child = self.create_child_node( 

78 parent=top, 

79 line=None, 

80 headline='INSERTED NODE' 

81 ) 

82 self.stack.append(child) 

83 assert level == len(self.stack), (level, len(self.stack)) 

84 child = self.create_child_node( 

85 parent=top, 

86 line=None, 

87 headline=h, # Leave the headline alone 

88 ) 

89 self.stack.append(child) 

90 assert self.stack 

91 assert 0 <= level < len(self.stack), (level, len(self.stack)) 

92 return self.stack[level] 

93 #@+node:ekr.20161202090722.1: *4* md_i.is_hash 

94 # Allow any non-blank after the hashes. 

95 md_hash_pattern = re.compile(r'^(#+)\s*(.+)\s*\n') 

96 

97 def is_hash(self, line): 

98 """ 

99 Return level, name if line is a hash section line. 

100 else return None, None. 

101 """ 

102 m = self.md_hash_pattern.match(line) 

103 if m: 

104 level = len(m.group(1)) 

105 # name = m.group(2) + m.group(3) 

106 name = m.group(2).strip() 

107 if name: 

108 return level, name 

109 return None, None 

110 #@+node:ekr.20161202085119.1: *4* md_i.is_underline 

111 md_pattern_table = ( 

112 re.compile(r'^(=+)\n'), 

113 re.compile(r'^(-+)\n'), 

114 ) 

115 

116 def is_underline(self, line): 

117 """True if line is all '-' or '=' characters.""" 

118 

119 for pattern in self.md_pattern_table: 

120 m = pattern.match(line) 

121 if m and len(m.group(1)) >= 4: 

122 return True 

123 return False 

124 #@+node:ekr.20161202085032.1: *4* md_i.lookahead_underline 

125 def lookahead_underline(self, i, lines): 

126 """True if lines[i:i+1] form an underlined line.""" 

127 if i + 1 < len(lines): 

128 line0 = lines[i] 

129 line1 = lines[i + 1] 

130 ch0 = self.is_underline(line0) 

131 ch1 = self.is_underline(line1) 

132 return not ch0 and not line0.isspace() and ch1 and len(line1) >= 4 

133 return False 

134 #@+node:ekr.20161125113240.1: *4* md_i.make_decls_node 

135 def make_decls_node(self, line): 

136 """Make a decls node.""" 

137 parent = self.stack[-1] 

138 assert parent == self.root, repr(parent) 

139 child = self.create_child_node( 

140 parent=self.stack[-1], 

141 line=line, 

142 headline='!Declarations', 

143 ) 

144 self.stack.append(child) 

145 #@+node:ekr.20161125095217.1: *4* md_i.make_node 

146 def make_node(self, level, name): 

147 """Create a new node.""" 

148 self.find_parent(level=level, h=name) 

149 #@+node:ekr.20161125225349.1: *3* md_i.post_pass 

150 def post_pass(self, parent): 

151 """A do-nothing post-pass for markdown.""" 

152 #@+node:ekr.20161202074507.1: *3* md_i.check 

153 def check(self, unused_s, parent): 

154 """ 

155 A do-nothing perfect-import check for markdown. 

156 We don't want to prevent writer.markdown from converting 

157 all headlines to hashed sections. 

158 """ 

159 return True 

160 #@-others 

161#@-others 

162importer_dict = { 

163 '@auto': ['@auto-md', '@auto-markdown',], 

164 'func': Markdown_Importer.do_import(), 

165 'extensions': ['.md', '.rmd', '.Rmd',], 

166} 

167#@@language python 

168#@@tabwidth -4 

169#@-leo