##// END OF EJS Templates
ipy_leo: do not crash if _p has been deleted in push
Ville M. Vainio -
Show More
@@ -1,575 +1,575 b''
1 """ ILeo - Leo plugin for IPython
1 """ ILeo - Leo plugin for IPython
2
2
3
3
4 """
4 """
5 import IPython.ipapi
5 import IPython.ipapi
6 import IPython.genutils
6 import IPython.genutils
7 import IPython.generics
7 import IPython.generics
8 from IPython.hooks import CommandChainDispatcher
8 from IPython.hooks import CommandChainDispatcher
9 import re
9 import re
10 import UserDict
10 import UserDict
11 from IPython.ipapi import TryNext
11 from IPython.ipapi import TryNext
12 import IPython.macro
12 import IPython.macro
13
13
14 def init_ipython(ipy):
14 def init_ipython(ipy):
15 """ This will be run by _ip.load('ipy_leo')
15 """ This will be run by _ip.load('ipy_leo')
16
16
17 Leo still needs to run update_commander() after this.
17 Leo still needs to run update_commander() after this.
18
18
19 """
19 """
20 global ip
20 global ip
21 ip = ipy
21 ip = ipy
22 ip.set_hook('complete_command', mb_completer, str_key = '%mb')
22 ip.set_hook('complete_command', mb_completer, str_key = '%mb')
23 ip.expose_magic('mb',mb_f)
23 ip.expose_magic('mb',mb_f)
24 ip.expose_magic('lee',lee_f)
24 ip.expose_magic('lee',lee_f)
25 ip.expose_magic('leoref',leoref_f)
25 ip.expose_magic('leoref',leoref_f)
26 expose_ileo_push(push_cl_node,100)
26 expose_ileo_push(push_cl_node,100)
27 # this should be the LAST one that will be executed, and it will never raise TryNext
27 # this should be the LAST one that will be executed, and it will never raise TryNext
28 expose_ileo_push(push_ipython_script, 1000)
28 expose_ileo_push(push_ipython_script, 1000)
29 expose_ileo_push(push_plain_python, 100)
29 expose_ileo_push(push_plain_python, 100)
30 expose_ileo_push(push_ev_node, 100)
30 expose_ileo_push(push_ev_node, 100)
31 global wb
31 global wb
32 wb = LeoWorkbook()
32 wb = LeoWorkbook()
33 ip.user_ns['wb'] = wb
33 ip.user_ns['wb'] = wb
34
34
35 show_welcome()
35 show_welcome()
36
36
37
37
38 def update_commander(new_leox):
38 def update_commander(new_leox):
39 """ Set the Leo commander to use
39 """ Set the Leo commander to use
40
40
41 This will be run every time Leo does ipython-launch; basically,
41 This will be run every time Leo does ipython-launch; basically,
42 when the user switches the document he is focusing on, he should do
42 when the user switches the document he is focusing on, he should do
43 ipython-launch to tell ILeo what document the commands apply to.
43 ipython-launch to tell ILeo what document the commands apply to.
44
44
45 """
45 """
46
46
47 global c,g
47 global c,g
48 c,g = new_leox.c, new_leox.g
48 c,g = new_leox.c, new_leox.g
49 print "Set Leo Commander:",c.frame.getTitle()
49 print "Set Leo Commander:",c.frame.getTitle()
50
50
51 # will probably be overwritten by user, but handy for experimentation early on
51 # will probably be overwritten by user, but handy for experimentation early on
52 ip.user_ns['c'] = c
52 ip.user_ns['c'] = c
53 ip.user_ns['g'] = g
53 ip.user_ns['g'] = g
54 ip.user_ns['_leo'] = new_leox
54 ip.user_ns['_leo'] = new_leox
55
55
56 new_leox.push = push_position_from_leo
56 new_leox.push = push_position_from_leo
57 run_leo_startup_node()
57 run_leo_startup_node()
58
58
59 from IPython.external.simplegeneric import generic
59 from IPython.external.simplegeneric import generic
60 import pprint
60 import pprint
61
61
62 def es(s):
62 def es(s):
63 g.es(s, tabName = 'IPython')
63 g.es(s, tabName = 'IPython')
64 pass
64 pass
65
65
66 @generic
66 @generic
67 def format_for_leo(obj):
67 def format_for_leo(obj):
68 """ Convert obj to string representiation (for editing in Leo)"""
68 """ Convert obj to string representiation (for editing in Leo)"""
69 return pprint.pformat(obj)
69 return pprint.pformat(obj)
70
70
71 @format_for_leo.when_type(list)
71 @format_for_leo.when_type(list)
72 def format_list(obj):
72 def format_list(obj):
73 return "\n".join(str(s) for s in obj)
73 return "\n".join(str(s) for s in obj)
74
74
75
75
76 attribute_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
76 attribute_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
77 def valid_attribute(s):
77 def valid_attribute(s):
78 return attribute_re.match(s)
78 return attribute_re.match(s)
79
79
80 _rootnode = None
80 _rootnode = None
81 def rootnode():
81 def rootnode():
82 """ Get ileo root node (@ipy-root)
82 """ Get ileo root node (@ipy-root)
83
83
84 if node has become invalid or has not been set, return None
84 if node has become invalid or has not been set, return None
85
85
86 Note that the root is the *first* @ipy-root item found
86 Note that the root is the *first* @ipy-root item found
87 """
87 """
88 global _rootnode
88 global _rootnode
89 if _rootnode is None:
89 if _rootnode is None:
90 return None
90 return None
91 if c.positionExists(_rootnode.p):
91 if c.positionExists(_rootnode.p):
92 return _rootnode
92 return _rootnode
93 _rootnode = None
93 _rootnode = None
94 return None
94 return None
95
95
96 def all_cells():
96 def all_cells():
97 global _rootnode
97 global _rootnode
98 d = {}
98 d = {}
99 r = rootnode()
99 r = rootnode()
100 if r is not None:
100 if r is not None:
101 nodes = r.p.children_iter()
101 nodes = r.p.children_iter()
102 else:
102 else:
103 nodes = c.allNodes_iter()
103 nodes = c.allNodes_iter()
104
104
105 for p in nodes:
105 for p in nodes:
106 h = p.headString()
106 h = p.headString()
107 if h.strip() == '@ipy-root':
107 if h.strip() == '@ipy-root':
108 # update root node (found it for the first time)
108 # update root node (found it for the first time)
109 _rootnode = LeoNode(p)
109 _rootnode = LeoNode(p)
110 # the next recursive call will use the children of new root
110 # the next recursive call will use the children of new root
111 return all_cells()
111 return all_cells()
112
112
113 if h.startswith('@a '):
113 if h.startswith('@a '):
114 d[h.lstrip('@a ').strip()] = p.parent().copy()
114 d[h.lstrip('@a ').strip()] = p.parent().copy()
115 elif not valid_attribute(h):
115 elif not valid_attribute(h):
116 continue
116 continue
117 d[h] = p.copy()
117 d[h] = p.copy()
118 return d
118 return d
119
119
120 def eval_node(n):
120 def eval_node(n):
121 body = n.b
121 body = n.b
122 if not body.startswith('@cl'):
122 if not body.startswith('@cl'):
123 # plain python repr node, just eval it
123 # plain python repr node, just eval it
124 return ip.ev(n.b)
124 return ip.ev(n.b)
125 # @cl nodes deserve special treatment - first eval the first line (minus cl), then use it to call the rest of body
125 # @cl nodes deserve special treatment - first eval the first line (minus cl), then use it to call the rest of body
126 first, rest = body.split('\n',1)
126 first, rest = body.split('\n',1)
127 tup = first.split(None, 1)
127 tup = first.split(None, 1)
128 # @cl alone SPECIAL USE-> dump var to user_ns
128 # @cl alone SPECIAL USE-> dump var to user_ns
129 if len(tup) == 1:
129 if len(tup) == 1:
130 val = ip.ev(rest)
130 val = ip.ev(rest)
131 ip.user_ns[n.h] = val
131 ip.user_ns[n.h] = val
132 es("%s = %s" % (n.h, repr(val)[:20] ))
132 es("%s = %s" % (n.h, repr(val)[:20] ))
133 return val
133 return val
134
134
135 cl, hd = tup
135 cl, hd = tup
136
136
137 xformer = ip.ev(hd.strip())
137 xformer = ip.ev(hd.strip())
138 es('Transform w/ %s' % repr(xformer))
138 es('Transform w/ %s' % repr(xformer))
139 return xformer(rest, n)
139 return xformer(rest, n)
140
140
141 class LeoNode(object, UserDict.DictMixin):
141 class LeoNode(object, UserDict.DictMixin):
142 """ Node in Leo outline
142 """ Node in Leo outline
143
143
144 Most important attributes (getters/setters available:
144 Most important attributes (getters/setters available:
145 .v - evaluate node, can also be alligned
145 .v - evaluate node, can also be alligned
146 .b, .h - body string, headline string
146 .b, .h - body string, headline string
147 .l - value as string list
147 .l - value as string list
148
148
149 Also supports iteration,
149 Also supports iteration,
150
150
151 setitem / getitem (indexing):
151 setitem / getitem (indexing):
152 wb.foo['key'] = 12
152 wb.foo['key'] = 12
153 assert wb.foo['key'].v == 12
153 assert wb.foo['key'].v == 12
154
154
155 Note the asymmetry on setitem and getitem! Also other
155 Note the asymmetry on setitem and getitem! Also other
156 dict methods are available.
156 dict methods are available.
157
157
158 .ipush() - run push-to-ipython
158 .ipush() - run push-to-ipython
159
159
160 Minibuffer command access (tab completion works):
160 Minibuffer command access (tab completion works):
161
161
162 mb save-to-file
162 mb save-to-file
163
163
164 """
164 """
165 def __init__(self,p):
165 def __init__(self,p):
166 self.p = p.copy()
166 self.p = p.copy()
167
167
168 def __str__(self):
168 def __str__(self):
169 return "<LeoNode %s>" % str(self.p)
169 return "<LeoNode %s>" % str(self.p)
170
170
171 __repr__ = __str__
171 __repr__ = __str__
172
172
173 def __get_h(self): return self.p.headString()
173 def __get_h(self): return self.p.headString()
174 def __set_h(self,val):
174 def __set_h(self,val):
175 print "set head",val
175 print "set head",val
176 c.beginUpdate()
176 c.beginUpdate()
177 try:
177 try:
178 c.setHeadString(self.p,val)
178 c.setHeadString(self.p,val)
179 finally:
179 finally:
180 c.endUpdate()
180 c.endUpdate()
181
181
182 h = property( __get_h, __set_h, doc = "Node headline string")
182 h = property( __get_h, __set_h, doc = "Node headline string")
183
183
184 def __get_b(self): return self.p.bodyString()
184 def __get_b(self): return self.p.bodyString()
185 def __set_b(self,val):
185 def __set_b(self,val):
186 print "set body",val
186 print "set body",val
187 c.beginUpdate()
187 c.beginUpdate()
188 try:
188 try:
189 c.setBodyString(self.p, val)
189 c.setBodyString(self.p, val)
190 finally:
190 finally:
191 c.endUpdate()
191 c.endUpdate()
192
192
193 b = property(__get_b, __set_b, doc = "Nody body string")
193 b = property(__get_b, __set_b, doc = "Nody body string")
194
194
195 def __set_val(self, val):
195 def __set_val(self, val):
196 self.b = format_for_leo(val)
196 self.b = format_for_leo(val)
197
197
198 v = property(lambda self: eval_node(self), __set_val, doc = "Node evaluated value")
198 v = property(lambda self: eval_node(self), __set_val, doc = "Node evaluated value")
199
199
200 def __set_l(self,val):
200 def __set_l(self,val):
201 self.b = '\n'.join(val )
201 self.b = '\n'.join(val )
202 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
202 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
203 __set_l, doc = "Node value as string list")
203 __set_l, doc = "Node value as string list")
204
204
205 def __iter__(self):
205 def __iter__(self):
206 """ Iterate through nodes direct children """
206 """ Iterate through nodes direct children """
207
207
208 return (LeoNode(p) for p in self.p.children_iter())
208 return (LeoNode(p) for p in self.p.children_iter())
209
209
210 def __children(self):
210 def __children(self):
211 d = {}
211 d = {}
212 for child in self:
212 for child in self:
213 head = child.h
213 head = child.h
214 tup = head.split(None,1)
214 tup = head.split(None,1)
215 if len(tup) > 1 and tup[0] == '@k':
215 if len(tup) > 1 and tup[0] == '@k':
216 d[tup[1]] = child
216 d[tup[1]] = child
217 continue
217 continue
218
218
219 if not valid_attribute(head):
219 if not valid_attribute(head):
220 d[head] = child
220 d[head] = child
221 continue
221 continue
222 return d
222 return d
223 def keys(self):
223 def keys(self):
224 d = self.__children()
224 d = self.__children()
225 return d.keys()
225 return d.keys()
226 def __getitem__(self, key):
226 def __getitem__(self, key):
227 """ wb.foo['Some stuff'] Return a child node with headline 'Some stuff'
227 """ wb.foo['Some stuff'] Return a child node with headline 'Some stuff'
228
228
229 If key is a valid python name (e.g. 'foo'), look for headline '@k foo' as well
229 If key is a valid python name (e.g. 'foo'), look for headline '@k foo' as well
230 """
230 """
231 key = str(key)
231 key = str(key)
232 d = self.__children()
232 d = self.__children()
233 return d[key]
233 return d[key]
234 def __setitem__(self, key, val):
234 def __setitem__(self, key, val):
235 """ You can do wb.foo['My Stuff'] = 12 to create children
235 """ You can do wb.foo['My Stuff'] = 12 to create children
236
236
237 This will create 'My Stuff' as a child of foo (if it does not exist), and
237 This will create 'My Stuff' as a child of foo (if it does not exist), and
238 do .v = 12 assignment.
238 do .v = 12 assignment.
239
239
240 Exception:
240 Exception:
241
241
242 wb.foo['bar'] = 12
242 wb.foo['bar'] = 12
243
243
244 will create a child with headline '@k bar', because bar is a valid python name
244 will create a child with headline '@k bar', because bar is a valid python name
245 and we don't want to crowd the WorkBook namespace with (possibly numerous) entries
245 and we don't want to crowd the WorkBook namespace with (possibly numerous) entries
246 """
246 """
247 key = str(key)
247 key = str(key)
248 d = self.__children()
248 d = self.__children()
249 if key in d:
249 if key in d:
250 d[key].v = val
250 d[key].v = val
251 return
251 return
252
252
253 if not valid_attribute(key):
253 if not valid_attribute(key):
254 head = key
254 head = key
255 else:
255 else:
256 head = '@k ' + key
256 head = '@k ' + key
257 p = c.createLastChildNode(self.p, head, '')
257 p = c.createLastChildNode(self.p, head, '')
258 LeoNode(p).v = val
258 LeoNode(p).v = val
259
259
260 def ipush(self):
260 def ipush(self):
261 """ Does push-to-ipython on the node """
261 """ Does push-to-ipython on the node """
262 push_from_leo(self)
262 push_from_leo(self)
263
263
264 def go(self):
264 def go(self):
265 """ Set node as current node (to quickly see it in Outline) """
265 """ Set node as current node (to quickly see it in Outline) """
266 c.beginUpdate()
266 c.beginUpdate()
267 try:
267 try:
268 c.setCurrentPosition(self.p)
268 c.setCurrentPosition(self.p)
269 finally:
269 finally:
270 c.endUpdate()
270 c.endUpdate()
271
271
272 def script(self):
272 def script(self):
273 """ Method to get the 'tangled' contents of the node
273 """ Method to get the 'tangled' contents of the node
274
274
275 (parse @others, << section >> references etc.)
275 (parse @others, << section >> references etc.)
276 """
276 """
277 return g.getScript(c,self.p,useSelectedText=False,useSentinels=False)
277 return g.getScript(c,self.p,useSelectedText=False,useSentinels=False)
278
278
279 def __get_uA(self):
279 def __get_uA(self):
280 p = self.p
280 p = self.p
281 # Create the uA if necessary.
281 # Create the uA if necessary.
282 if not hasattr(p.v.t,'unknownAttributes'):
282 if not hasattr(p.v.t,'unknownAttributes'):
283 p.v.t.unknownAttributes = {}
283 p.v.t.unknownAttributes = {}
284
284
285 d = p.v.t.unknownAttributes.setdefault('ipython', {})
285 d = p.v.t.unknownAttributes.setdefault('ipython', {})
286 return d
286 return d
287
287
288 uA = property(__get_uA, doc = "Access persistent unknownAttributes of node")
288 uA = property(__get_uA, doc = "Access persistent unknownAttributes of node")
289
289
290
290
291 class LeoWorkbook:
291 class LeoWorkbook:
292 """ class for 'advanced' node access
292 """ class for 'advanced' node access
293
293
294 Has attributes for all "discoverable" nodes. Node is discoverable if it
294 Has attributes for all "discoverable" nodes. Node is discoverable if it
295 either
295 either
296
296
297 - has a valid python name (Foo, bar_12)
297 - has a valid python name (Foo, bar_12)
298 - is a parent of an anchor node (if it has a child '@a foo', it is visible as foo)
298 - is a parent of an anchor node (if it has a child '@a foo', it is visible as foo)
299
299
300 """
300 """
301 def __getattr__(self, key):
301 def __getattr__(self, key):
302 if key.startswith('_') or key == 'trait_names' or not valid_attribute(key):
302 if key.startswith('_') or key == 'trait_names' or not valid_attribute(key):
303 raise AttributeError
303 raise AttributeError
304 cells = all_cells()
304 cells = all_cells()
305 p = cells.get(key, None)
305 p = cells.get(key, None)
306 if p is None:
306 if p is None:
307 return add_var(key)
307 return add_var(key)
308
308
309 return LeoNode(p)
309 return LeoNode(p)
310
310
311 def __str__(self):
311 def __str__(self):
312 return "<LeoWorkbook>"
312 return "<LeoWorkbook>"
313 def __setattr__(self,key, val):
313 def __setattr__(self,key, val):
314 raise AttributeError("Direct assignment to workbook denied, try wb.%s.v = %s" % (key,val))
314 raise AttributeError("Direct assignment to workbook denied, try wb.%s.v = %s" % (key,val))
315
315
316 __repr__ = __str__
316 __repr__ = __str__
317
317
318 def __iter__(self):
318 def __iter__(self):
319 """ Iterate all (even non-exposed) nodes """
319 """ Iterate all (even non-exposed) nodes """
320 cells = all_cells()
320 cells = all_cells()
321 return (LeoNode(p) for p in c.allNodes_iter())
321 return (LeoNode(p) for p in c.allNodes_iter())
322
322
323 current = property(lambda self: LeoNode(c.currentPosition()), doc = "Currently selected node")
323 current = property(lambda self: LeoNode(c.currentPosition()), doc = "Currently selected node")
324
324
325 def match_h(self, regex):
325 def match_h(self, regex):
326 cmp = re.compile(regex)
326 cmp = re.compile(regex)
327 for node in self:
327 for node in self:
328 if re.match(cmp, node.h, re.IGNORECASE):
328 if re.match(cmp, node.h, re.IGNORECASE):
329 yield node
329 yield node
330 return
330 return
331
331
332 @IPython.generics.complete_object.when_type(LeoWorkbook)
332 @IPython.generics.complete_object.when_type(LeoWorkbook)
333 def workbook_complete(obj, prev):
333 def workbook_complete(obj, prev):
334 return all_cells().keys() + [s for s in prev if not s.startswith('_')]
334 return all_cells().keys() + [s for s in prev if not s.startswith('_')]
335
335
336
336
337 def add_var(varname):
337 def add_var(varname):
338 c.beginUpdate()
338 c.beginUpdate()
339 r = rootnode()
339 r = rootnode()
340 try:
340 try:
341 if r is None:
341 if r is None:
342 p2 = g.findNodeAnywhere(c,varname)
342 p2 = g.findNodeAnywhere(c,varname)
343 else:
343 else:
344 p2 = g.findNodeInChildren(c, r.p, varname)
344 p2 = g.findNodeInChildren(c, r.p, varname)
345 if p2:
345 if p2:
346 return LeoNode(p2)
346 return LeoNode(p2)
347
347
348 if r is not None:
348 if r is not None:
349 p2 = r.p.insertAsLastChild()
349 p2 = r.p.insertAsLastChild()
350
350
351 else:
351 else:
352 p2 = c.currentPosition().insertAfter()
352 p2 = c.currentPosition().insertAfter()
353
353
354 c.setHeadString(p2,varname)
354 c.setHeadString(p2,varname)
355 return LeoNode(p2)
355 return LeoNode(p2)
356 finally:
356 finally:
357 c.endUpdate()
357 c.endUpdate()
358
358
359 def add_file(self,fname):
359 def add_file(self,fname):
360 p2 = c.currentPosition().insertAfter()
360 p2 = c.currentPosition().insertAfter()
361
361
362 push_from_leo = CommandChainDispatcher()
362 push_from_leo = CommandChainDispatcher()
363
363
364 def expose_ileo_push(f, prio = 0):
364 def expose_ileo_push(f, prio = 0):
365 push_from_leo.add(f, prio)
365 push_from_leo.add(f, prio)
366
366
367 def push_ipython_script(node):
367 def push_ipython_script(node):
368 """ Execute the node body in IPython, as if it was entered in interactive prompt """
368 """ Execute the node body in IPython, as if it was entered in interactive prompt """
369 c.beginUpdate()
369 c.beginUpdate()
370 try:
370 try:
371 ohist = ip.IP.output_hist
371 ohist = ip.IP.output_hist
372 hstart = len(ip.IP.input_hist)
372 hstart = len(ip.IP.input_hist)
373 script = node.script()
373 script = node.script()
374
374
375 script = g.splitLines(script + '\n')
375 script = g.splitLines(script + '\n')
376 ip.user_ns['_p'] = node
376 ip.user_ns['_p'] = node
377 ip.runlines(script)
377 ip.runlines(script)
378 del ip.user_ns['_p']
378 ip.user_ns.pop('_p',None)
379
379
380 has_output = False
380 has_output = False
381 for idx in range(hstart,len(ip.IP.input_hist)):
381 for idx in range(hstart,len(ip.IP.input_hist)):
382 val = ohist.get(idx,None)
382 val = ohist.get(idx,None)
383 if val is None:
383 if val is None:
384 continue
384 continue
385 has_output = True
385 has_output = True
386 inp = ip.IP.input_hist[idx]
386 inp = ip.IP.input_hist[idx]
387 if inp.strip():
387 if inp.strip():
388 es('In: %s' % (inp[:40], ))
388 es('In: %s' % (inp[:40], ))
389
389
390 es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)))
390 es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)))
391
391
392 if not has_output:
392 if not has_output:
393 es('ipy run: %s (%d LL)' %( node.h,len(script)))
393 es('ipy run: %s (%d LL)' %( node.h,len(script)))
394 finally:
394 finally:
395 c.endUpdate()
395 c.endUpdate()
396
396
397
397
398 def eval_body(body):
398 def eval_body(body):
399 try:
399 try:
400 val = ip.ev(body)
400 val = ip.ev(body)
401 except:
401 except:
402 # just use stringlist if it's not completely legal python expression
402 # just use stringlist if it's not completely legal python expression
403 val = IPython.genutils.SList(body.splitlines())
403 val = IPython.genutils.SList(body.splitlines())
404 return val
404 return val
405
405
406 def push_plain_python(node):
406 def push_plain_python(node):
407 if not node.h.endswith('P'):
407 if not node.h.endswith('P'):
408 raise TryNext
408 raise TryNext
409 script = node.script()
409 script = node.script()
410 lines = script.count('\n')
410 lines = script.count('\n')
411 try:
411 try:
412 exec script in ip.user_ns
412 exec script in ip.user_ns
413 except:
413 except:
414 print " -- Exception in script:\n"+script + "\n --"
414 print " -- Exception in script:\n"+script + "\n --"
415 raise
415 raise
416 es('ipy plain: %s (%d LL)' % (node.h,lines))
416 es('ipy plain: %s (%d LL)' % (node.h,lines))
417
417
418
418
419 def push_cl_node(node):
419 def push_cl_node(node):
420 """ If node starts with @cl, eval it
420 """ If node starts with @cl, eval it
421
421
422 The result is put as last child of @ipy-results node, if it exists
422 The result is put as last child of @ipy-results node, if it exists
423 """
423 """
424 if not node.b.startswith('@cl'):
424 if not node.b.startswith('@cl'):
425 raise TryNext
425 raise TryNext
426
426
427 p2 = g.findNodeAnywhere(c,'@ipy-results')
427 p2 = g.findNodeAnywhere(c,'@ipy-results')
428 val = node.v
428 val = node.v
429 if p2:
429 if p2:
430 es("=> @ipy-results")
430 es("=> @ipy-results")
431 LeoNode(p2).v = val
431 LeoNode(p2).v = val
432 es(val)
432 es(val)
433
433
434 def push_ev_node(node):
434 def push_ev_node(node):
435 """ If headline starts with @ev, eval it and put result in body """
435 """ If headline starts with @ev, eval it and put result in body """
436 if not node.h.startswith('@ev '):
436 if not node.h.startswith('@ev '):
437 raise TryNext
437 raise TryNext
438 expr = node.h.lstrip('@ev ')
438 expr = node.h.lstrip('@ev ')
439 es('ipy eval ' + expr)
439 es('ipy eval ' + expr)
440 res = ip.ev(expr)
440 res = ip.ev(expr)
441 node.v = res
441 node.v = res
442
442
443
443
444 def push_position_from_leo(p):
444 def push_position_from_leo(p):
445 push_from_leo(LeoNode(p))
445 push_from_leo(LeoNode(p))
446
446
447 @generic
447 @generic
448 def edit_object_in_leo(obj, varname):
448 def edit_object_in_leo(obj, varname):
449 """ Make it @cl node so it can be pushed back directly by alt+I """
449 """ Make it @cl node so it can be pushed back directly by alt+I """
450 node = add_var(varname)
450 node = add_var(varname)
451 formatted = format_for_leo(obj)
451 formatted = format_for_leo(obj)
452 if not formatted.startswith('@cl'):
452 if not formatted.startswith('@cl'):
453 formatted = '@cl\n' + formatted
453 formatted = '@cl\n' + formatted
454 node.b = formatted
454 node.b = formatted
455 node.go()
455 node.go()
456
456
457 @edit_object_in_leo.when_type(IPython.macro.Macro)
457 @edit_object_in_leo.when_type(IPython.macro.Macro)
458 def edit_macro(obj,varname):
458 def edit_macro(obj,varname):
459 bod = '_ip.defmacro("""\\\n' + obj.value + '""")'
459 bod = '_ip.defmacro("""\\\n' + obj.value + '""")'
460 node = add_var('Macro_' + varname)
460 node = add_var('Macro_' + varname)
461 node.b = bod
461 node.b = bod
462 node.go()
462 node.go()
463
463
464 def get_history(hstart = 0):
464 def get_history(hstart = 0):
465 res = []
465 res = []
466 ohist = ip.IP.output_hist
466 ohist = ip.IP.output_hist
467
467
468 for idx in range(hstart, len(ip.IP.input_hist)):
468 for idx in range(hstart, len(ip.IP.input_hist)):
469 val = ohist.get(idx,None)
469 val = ohist.get(idx,None)
470 has_output = True
470 has_output = True
471 inp = ip.IP.input_hist_raw[idx]
471 inp = ip.IP.input_hist_raw[idx]
472 if inp.strip():
472 if inp.strip():
473 res.append('In [%d]: %s' % (idx, inp))
473 res.append('In [%d]: %s' % (idx, inp))
474 if val:
474 if val:
475 res.append(pprint.pformat(val))
475 res.append(pprint.pformat(val))
476 res.append('\n')
476 res.append('\n')
477 return ''.join(res)
477 return ''.join(res)
478
478
479
479
480 def lee_f(self,s):
480 def lee_f(self,s):
481 """ Open file(s)/objects in Leo
481 """ Open file(s)/objects in Leo
482
482
483 - %lee hist -> open full session history in leo
483 - %lee hist -> open full session history in leo
484 - Takes an object
484 - Takes an object
485 - Takes an mglob pattern, e.g. '%lee *.cpp' or %leo 'rec:*.cpp'
485 - Takes an mglob pattern, e.g. '%lee *.cpp' or %leo 'rec:*.cpp'
486 """
486 """
487 import os
487 import os
488
488
489 c.beginUpdate()
489 c.beginUpdate()
490 try:
490 try:
491 if s == 'hist':
491 if s == 'hist':
492 wb.ipython_history.b = get_history()
492 wb.ipython_history.b = get_history()
493 wb.ipython_history.go()
493 wb.ipython_history.go()
494 return
494 return
495
495
496
496
497
497
498 # try editing the object directly
498 # try editing the object directly
499 obj = ip.user_ns.get(s, None)
499 obj = ip.user_ns.get(s, None)
500 if obj is not None:
500 if obj is not None:
501 edit_object_in_leo(obj,s)
501 edit_object_in_leo(obj,s)
502 return
502 return
503
503
504 # if it's not object, it's a file name / mglob pattern
504 # if it's not object, it's a file name / mglob pattern
505 from IPython.external import mglob
505 from IPython.external import mglob
506
506
507 files = (os.path.abspath(f) for f in mglob.expand(s))
507 files = (os.path.abspath(f) for f in mglob.expand(s))
508 for fname in files:
508 for fname in files:
509 p = g.findNodeAnywhere(c,'@auto ' + fname)
509 p = g.findNodeAnywhere(c,'@auto ' + fname)
510 if not p:
510 if not p:
511 p = c.currentPosition().insertAfter()
511 p = c.currentPosition().insertAfter()
512
512
513 p.setHeadString('@auto ' + fname)
513 p.setHeadString('@auto ' + fname)
514 if os.path.isfile(fname):
514 if os.path.isfile(fname):
515 c.setBodyString(p,open(fname).read())
515 c.setBodyString(p,open(fname).read())
516 c.selectPosition(p)
516 c.selectPosition(p)
517 print "Editing file(s), press ctrl+shift+w in Leo to write @auto nodes"
517 print "Editing file(s), press ctrl+shift+w in Leo to write @auto nodes"
518 finally:
518 finally:
519 c.endUpdate()
519 c.endUpdate()
520
520
521
521
522
522
523 def leoref_f(self,s):
523 def leoref_f(self,s):
524 """ Quick reference for ILeo """
524 """ Quick reference for ILeo """
525 import textwrap
525 import textwrap
526 print textwrap.dedent("""\
526 print textwrap.dedent("""\
527 %leoe file/object - open file / object in leo
527 %leoe file/object - open file / object in leo
528 wb.foo.v - eval node foo (i.e. headstring is 'foo' or '@ipy foo')
528 wb.foo.v - eval node foo (i.e. headstring is 'foo' or '@ipy foo')
529 wb.foo.v = 12 - assign to body of node foo
529 wb.foo.v = 12 - assign to body of node foo
530 wb.foo.b - read or write the body of node foo
530 wb.foo.b - read or write the body of node foo
531 wb.foo.l - body of node foo as string list
531 wb.foo.l - body of node foo as string list
532
532
533 for el in wb.foo:
533 for el in wb.foo:
534 print el.v
534 print el.v
535
535
536 """
536 """
537 )
537 )
538
538
539
539
540
540
541 def mb_f(self, arg):
541 def mb_f(self, arg):
542 """ Execute leo minibuffer commands
542 """ Execute leo minibuffer commands
543
543
544 Example:
544 Example:
545 mb save-to-file
545 mb save-to-file
546 """
546 """
547 c.executeMinibufferCommand(arg)
547 c.executeMinibufferCommand(arg)
548
548
549 def mb_completer(self,event):
549 def mb_completer(self,event):
550 """ Custom completer for minibuffer """
550 """ Custom completer for minibuffer """
551 cmd_param = event.line.split()
551 cmd_param = event.line.split()
552 if event.line.endswith(' '):
552 if event.line.endswith(' '):
553 cmd_param.append('')
553 cmd_param.append('')
554 if len(cmd_param) > 2:
554 if len(cmd_param) > 2:
555 return ip.IP.Completer.file_matches(event.symbol)
555 return ip.IP.Completer.file_matches(event.symbol)
556 cmds = c.commandsDict.keys()
556 cmds = c.commandsDict.keys()
557 cmds.sort()
557 cmds.sort()
558 return cmds
558 return cmds
559
559
560 def show_welcome():
560 def show_welcome():
561 print "------------------"
561 print "------------------"
562 print "Welcome to Leo-enabled IPython session!"
562 print "Welcome to Leo-enabled IPython session!"
563 print "Try %leoref for quick reference."
563 print "Try %leoref for quick reference."
564 import IPython.platutils
564 import IPython.platutils
565 IPython.platutils.set_term_title('ILeo')
565 IPython.platutils.set_term_title('ILeo')
566 IPython.platutils.freeze_term_title()
566 IPython.platutils.freeze_term_title()
567
567
568 def run_leo_startup_node():
568 def run_leo_startup_node():
569 p = g.findNodeAnywhere(c,'@ipy-startup')
569 p = g.findNodeAnywhere(c,'@ipy-startup')
570 if p:
570 if p:
571 print "Running @ipy-startup nodes"
571 print "Running @ipy-startup nodes"
572 for n in LeoNode(p):
572 for n in LeoNode(p):
573 push_from_leo(n)
573 push_from_leo(n)
574
574
575
575
General Comments 0
You need to be logged in to leave comments. Login now