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