#@+leo-ver=5-thin
#@+node:ekr.20101110091234.5700: * @file leo_interface.py
#@+<< docstring >>
#@+node:ekr.20101112180523.5422: ** << docstring >>
""" Allows the user to browse XML documents in Leo.
This plugin implements an interface to XML generation,
so that the resulting file can be processed by leo.
class leo_file represents the whole leo file.
class leo_node has a headline and body text.
See the end of this file for a minimal example on
how to use these classes.
If you encounter the first of a set of clones, create a leo_node. If you
encounter the same set of clones later, create a leo_clone node and refer back
to the first element.
"""
#@-<< docstring >>
debug = False
# Define globals
vnode_count = 0
if debug:
allvnodes = {
# leo_file:None, # Fixed a valid pylint complaint. file is not defined.
}
vnode_count = 0
vnode_stack = []
#@@language python
#@@tabwidth -4
#@+others
#@+node:ekr.20101110092416.5699: ** escape
[docs]def escape(s):
s = s.replace('&', "&")
s = s.replace('<', "<")
s = s.replace('>', ">")
return s
#@+node:ekr.20101112045055.60165: ** init
[docs]def init():
'''Return True if the plugin has loaded successfully.'''
return True
#@+node:ekr.20101110092416.5700: ** class node_with_parent
[docs]class node_with_parent(object):
#@+others
#@+node:ekr.20101110092416.5702: *3* set_parent
[docs] def set_parent(self, node):
self.mparent = node
#@+node:ekr.20101110092416.5704: *3* parent
[docs] def parent(self):
return self.mparent
#@-others
#@+node:ekr.20101110092416.5705: ** class LeoNode
error_count = 0
[docs]class LeoNode(object):
"""
Abstrace class for generating xml.
"""
#@+others
#@+node:ekr.20101110092416.5707: *3* __init__
def __init__(self):
self.children = []
#@+node:ekr.20101110092416.5709: *3* add_child
[docs] def add_child(self, child):
self.children.append(child)
child.set_parent(self)
#@+node:ekr.20101110092416.5711: *3* gen
[docs] def gen(self, file):
pass
#@+node:ekr.20101110092416.5713: *3* gen_children
[docs] def gen_children(self, file):
for child in self.children:
child.gen(file)
#@+node:ekr.20101110092416.5715: *3* mark
[docs] def mark(self, file, marker, func, newline=True):
file.write("<%s>" % marker)
if newline:
file.write("\n")
func(file)
file.write("</%s>\n" % marker)
#@+node:ekr.20101110092416.5717: *3* mark_with_attributes
[docs] def mark_with_attributes(self, file, marker, attribute_list, func, newline=True):
write = file.write
write("<")
write(marker)
write(" ")
for name, value in attribute_list:
write('%s="%s" ' % (name, value))
write(">")
if newline:
write("\n")
func(file)
write("</%s>" % marker)
if newline:
write("\n")
#@+node:ekr.20101110092416.5719: *3* mark_with_attributes_short
[docs] def mark_with_attributes_short(self, file, marker, attribute_list):
write = file.write
write("<")
write(marker)
write(" ")
for name, value in attribute_list:
write('%s="%s" ' % (name, value))
write("/>\n")
#@+node:ekr.20101110092416.5721: *3* nthChild
[docs] def nthChild (self, n):
return self.children[n]
#@-others
#@+node:ekr.20101110092416.5722: ** class leo_file
[docs]class leo_file(LeoNode):
"""Leo specific class representing a file."""
#@+others
#@+node:ekr.20101110092416.5724: *3* headString
[docs] def headString(self):
return "[[This is the file root]]"
#@+node:ekr.20101110092416.5726: *3* parent
[docs] def parent(self):
return None
#@+node:ekr.20101110092416.5728: *3* empty
[docs] def empty(self, file):
pass
#@+node:ekr.20101110092416.5730: *3* find_panel_settings
[docs] def find_panel_settings(self, file):
self.mark(file, "find_string", self.empty, newline=False)
self.mark(file, "change_string", self.empty, newline=False)
#@+node:ekr.20101110092416.5732: *3* gen
[docs] def gen(self, file):
global error_count
error_count = 0
file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
self.mark(file, "leo_file", self.gen1)
#@+node:ekr.20101110092416.5734: *3* gen1
[docs] def gen1(self, file):
self.header(file)
# This is a shortcut.
file.write("""<globals body_outline_ratio="0.5">
<global_window_position top="0" left="2" height="400" width="700"/>
<global_log_window_position top="0" left="0" height="0" width="0"/>
</globals>
""")
self.mark(file, "preferences", self.preferences)
self.mark(file, "find_panel_settings", self.find_panel_settings)
if debug:
global vnode_count
vnode_count = 0
self.mark(file, "vnodes", self.gen_vnodes)
self.mark(file, "tnodes", self.gen_tnodes)
#@+node:ekr.20101110092416.5736: *3* gen_tnodes
[docs] def gen_tnodes(self, file):
for child in self.children:
child.gen_tnodes(file)
#@+node:ekr.20101110092416.5738: *3* gen_vnodes
[docs] def gen_vnodes(self, file):
if debug:
global allvnodes, vnode_stack
allvnodes = {file:None}
vnode_stack = []
for child in self.children:
child.gen_vnodes(file)
#@+node:ekr.20101110092416.5740: *3* header
#@+node:ekr.20101110092416.5742: *3* max_tnode_index
[docs] def max_tnode_index(self):
return leo_node.count
#@+node:ekr.20101110092416.5744: *3* nr_tnodes
[docs] def nr_tnodes(self):
return leo_node.count
#@+node:ekr.20101110092416.5746: *3* preferences
[docs] def preferences(self, file):
pass
#@+node:ekr.20101110092416.5748: *3* sss
[docs] def sss(self, file):
file.write("sss")
#@-others
#@+node:ekr.20101110092416.5749: ** class leo_node
[docs]class leo_node(LeoNode, node_with_parent):
"""
Leo specific class representing a node.
These nodes correspond to tnodes in LEO.
They have a headline and a body.
They also represent the (only) vnode in an outline without clones.
"""
__super_leo_node = LeoNode
count = 0
#@+others
#@+node:ekr.20101110092416.5751: *3* __init__
def __init__(self, headline='', body=''):
self.__super_leo_node.__init__(self)
leo_node.count += 1
self.nr = leo_node.count
self.headline = headline
self.body = body
#@+node:ekr.20101110092416.5753: *3* bodyString
[docs] def bodyString(self, body):
return self.body
#@+node:ekr.20101110092416.5755: *3* gen_tnodes
[docs] def gen_tnodes(self, file):
self.mark_with_attributes(file, "t", (
("tx", "T" + repr(self.nr)),
), self.gen_tnodes1, newline=False)
for child in self.children:
child.gen_tnodes(file)
#@+node:ekr.20101110092416.5757: *3* gen_tnodes1
[docs] def gen_tnodes1(self, file):
self.write_body_escaped(file)
#@+node:ekr.20101110092416.5759: *3* gen_vnodes
[docs] def gen_vnodes(self, file):
attributes = [("t", "T" + repr(self.nr))]
if debug:
# For debugging, make sure that we are not getting
# cyclic references.
# Also number all nodes for easier error hunting.
vnode_stack.append(self)
if self in allvnodes:
print("Fix this; This is an endless recursive call in leo_interface.leo_node.gen_vnodes")
x = vnode_stack[:]
x.reverse()
for i in x:
print(i.headline)
import pdb; pdb.set_trace()
return
global vnode_count
attributes.append(('model_node_number', repr(vnode_count)))
vnode_count += 1
allvnodes[self]=None
self.mark_with_attributes(file, "v", attributes, self.gen_vnodes1)
if debug:
del allvnodes[self]
vnode_stack.pop()
#@+node:ekr.20101110092416.5761: *3* gen_vnodes1
[docs] def gen_vnodes1(self, file):
self.mark(file, "vh", self.write_headline_escaped, newline=False)
for child in self.children:
child.gen_vnodes(file)
#@+node:ekr.20101110092416.5763: *3* headString
[docs] def headString(self):
return self.headline
#@+node:ekr.20101110092416.5765: *3* set_body
[docs] def set_body(self, body):
self.body = body
#@+node:ekr.20101110092416.5767: *3* set_headline
[docs] def set_headline(self, headline):
self.headline = headline
#@+node:ekr.20101110092416.5769: *3* write_body_escaped
[docs] def write_body_escaped(self, file):
file.write(escape(self.body.encode("UTF-8")))
#@+node:ekr.20101110092416.5771: *3* write_headline
[docs] def write_headline(self, file):
file.write(self.headline)
#@+node:ekr.20101110092416.5773: *3* write_headline_escaped
[docs] def write_headline_escaped(self, file):
file.write(escape(self.headline.encode("UTF-8")))
#@-others
#@+node:ekr.20101110092416.5774: ** class leo_clone
[docs]class leo_clone(node_with_parent):
"""
Class representing a clone.
The (only) data of a clone is the reference to a leo_node.
When you encounter the first clone of a set of clones, generate
a leo_node. The second clone should then reference this leo_node,
and contain no other data.
Since clones are indistinguishable, there is really not much to do in
this class.
"""
#@+others
#@+node:ekr.20101110092416.5776: *3* __init__
def __init__(self, orig):
self.orig = orig
self.mparent = None
#@+node:ekr.20101110092416.5778: *3* gen_vnodes
[docs] def gen_vnodes(self, file):
self.orig.gen_vnodes(file)
# There is nothing new to do here;
# just repeat what we did when we encountered
# the first clone.
#@+node:ekr.20101110092416.5780: *3* gen_tnodes
[docs] def gen_tnodes(self, file):
pass
# the tnodes are generated by the Leo_node
#@-others
#@+node:ekr.20101110092416.5782: ** leotree
[docs]def leotree():
f = leo_file()
return f
#@-others
if __name__ == "__main__":
import sys
f = leotree()
r = leo_node("Some headline", "some Body")
f.add_child(r)
f.gen(sys.stdout)
#@-leo