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