Coverage for C:\leo.repo\leo-editor\leo\plugins\importers\org.py: 86%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x 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.20140723122936.18146: * @file ../plugins/importers/org.py
3"""The @auto importer for the org language."""
4import re
5from leo.core import leoGlobals as g
6from leo.plugins.importers import linescanner
7Importer = linescanner.Importer
8#@+others
9#@+node:ekr.20140723122936.18072: ** class Org_Importer
10class Org_Importer(Importer):
11 """The importer for the org lanuage."""
13 def __init__(self, importCommands, **kwargs):
14 """Org_Importer.__init__"""
15 super().__init__(
16 importCommands,
17 language='plain', # A reasonable @language
18 state_class=None,
19 strict=False,
20 )
21 self.tc = self.load_nodetags()
23 #@+others
24 #@+node:ekr.20171120084611.2: *3* org_i.clean_headline
25 # Recognize :tag: syntax only at the end of headlines.
26 # Use :tag1:tag2: to specify two tags, not :tag1: :tag2:
27 tag_pattern = re.compile(r':([\w_@]+:)+\s*$')
29 def clean_headline(self, s, p=None):
30 """
31 Return a cleaned up headline for p.
32 Also parses org-mode tags.
33 """
34 if p and self.tc:
35 # Support for #578: org-mode tags.
36 m = self.tag_pattern.search(s)
37 if m:
38 i = m.start()
39 # head = s[:i].strip()
40 tail = s[i + 1 : -1].strip()
41 tags = tail.split(':')
42 for tag in tags:
43 self.tc.add_tag(p, tag)
44 return s
46 #@+node:ekr.20161123194634.1: *3* org_i.gen_lines & helper
47 # #1037: eat only one space.
48 org_pattern = re.compile(r'^(\*+)\s(.*)$')
50 def gen_lines(self, lines, parent):
51 """Node generator for org mode."""
52 self.vnode_info = {
53 # Keys are vnodes, values are inner dicts.
54 parent.v: {
55 'lines': [],
56 }
57 }
58 self.parents = [parent]
59 for line in lines:
60 m = self.org_pattern.match(line)
61 if m:
62 # Cut back the stack, then allocate a new node.
63 level = len(m.group(1))
64 self.parents = self.parents[:level]
65 self.find_parent(
66 level=level,
67 h=m.group(2))
68 else:
69 p = self.parents[-1]
70 self.add_line(p, line)
71 #@+node:ekr.20161123194732.2: *4* org_i.find_parent
72 def find_parent(self, level, h):
73 """
74 Return the parent at the indicated level, allocating
75 place-holder nodes as necessary.
76 """
77 assert level >= 0
78 n = level - len(self.parents)
79 while level >= len(self.parents):
80 headline = h if n == 0 else 'placeholder'
81 # This works, but there is no way perfect import will pass the result.
82 n -= 1
83 child = self.create_child_node(
84 parent=self.parents[-1],
85 line=None,
86 headline=headline,
87 )
88 self.parents.append(child)
89 return self.parents[level]
90 #@+node:ekr.20190210091845.1: *4* org_i.create_child_node
91 def create_child_node(self, parent, line, headline):
92 """Create a child node of parent."""
93 child = parent.insertAsLastChild()
94 self.vnode_info[child.v] = {
95 'lines': [],
96 }
97 if line:
98 self.add_line(child, line)
99 assert isinstance(headline, str), repr(headline)
100 # #1037: do rstrip, not strip.
101 # #1087: do not strip at all!
102 child.h = headline
103 return child
104 #@+node:ekr.20171120084611.5: *3* org_i.load_nodetags
105 def load_nodetags(self):
106 """
107 Load the nodetags.py plugin if necessary.
108 Return c.theTagController.
109 """
110 c = self.c
111 if not getattr(c, 'theTagController', None):
112 g.app.pluginsController.loadOnePlugin('nodetags.py', verbose=False)
113 return getattr(c, 'theTagController', None)
114 #@+node:ekr.20161126074103.1: *3* org_i.post_pass
115 def post_pass(self, parent):
116 """
117 Optional Stage 2 of the importer pipeline, consisting of zero or more
118 substages. Each substage alters nodes in various ways.
120 Subclasses may freely override this method, **provided** that all
121 substages use the API for setting body text. Changing p.b directly will
122 cause asserts to fail later in i.finish().
123 """
124 self.clean_all_headlines(parent)
125 #@-others
126#@-others
127importer_dict = {
128 '@auto': ['@auto-org', '@auto-org-mode',],
129 'func': Org_Importer.do_import(),
130 'extensions': ['.org'],
131}
132#@@language python
133#@@tabwidth -4
134#@-leo