##// END OF EJS Templates
ileo: %lee also takes input slices
Ville M. Vainio -
Show More
@@ -1,577 +1,586 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 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
177 print "set head",val
178 c.beginUpdate()
178 c.beginUpdate()
179 try:
179 try:
180 c.setHeadString(self.p,val)
180 c.setHeadString(self.p,val)
181 finally:
181 finally:
182 c.endUpdate()
182 c.endUpdate()
183
183
184 h = property( __get_h, __set_h, doc = "Node headline string")
184 h = property( __get_h, __set_h, doc = "Node headline string")
185
185
186 def __get_b(self): return self.p.bodyString()
186 def __get_b(self): return self.p.bodyString()
187 def __set_b(self,val):
187 def __set_b(self,val):
188 print "set body",val
188 print "set body",val
189 c.beginUpdate()
189 c.beginUpdate()
190 try:
190 try:
191 c.setBodyString(self.p, val)
191 c.setBodyString(self.p, val)
192 finally:
192 finally:
193 c.endUpdate()
193 c.endUpdate()
194
194
195 b = property(__get_b, __set_b, doc = "Nody body string")
195 b = property(__get_b, __set_b, doc = "Nody body string")
196
196
197 def __set_val(self, val):
197 def __set_val(self, val):
198 self.b = format_for_leo(val)
198 self.b = format_for_leo(val)
199
199
200 v = property(lambda self: eval_node(self), __set_val, doc = "Node evaluated value")
200 v = property(lambda self: eval_node(self), __set_val, doc = "Node evaluated value")
201
201
202 def __set_l(self,val):
202 def __set_l(self,val):
203 self.b = '\n'.join(val )
203 self.b = '\n'.join(val )
204 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
204 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
205 __set_l, doc = "Node value as string list")
205 __set_l, doc = "Node value as string list")
206
206
207 def __iter__(self):
207 def __iter__(self):
208 """ Iterate through nodes direct children """
208 """ Iterate through nodes direct children """
209
209
210 return (LeoNode(p) for p in self.p.children_iter())
210 return (LeoNode(p) for p in self.p.children_iter())
211
211
212 def __children(self):
212 def __children(self):
213 d = {}
213 d = {}
214 for child in self:
214 for child in self:
215 head = child.h
215 head = child.h
216 tup = head.split(None,1)
216 tup = head.split(None,1)
217 if len(tup) > 1 and tup[0] == '@k':
217 if len(tup) > 1 and tup[0] == '@k':
218 d[tup[1]] = child
218 d[tup[1]] = child
219 continue
219 continue
220
220
221 if not valid_attribute(head):
221 if not valid_attribute(head):
222 d[head] = child
222 d[head] = child
223 continue
223 continue
224 return d
224 return d
225 def keys(self):
225 def keys(self):
226 d = self.__children()
226 d = self.__children()
227 return d.keys()
227 return d.keys()
228 def __getitem__(self, key):
228 def __getitem__(self, key):
229 """ wb.foo['Some stuff'] Return a child node with headline 'Some stuff'
229 """ wb.foo['Some stuff'] Return a child node with headline 'Some stuff'
230
230
231 If key is a valid python name (e.g. 'foo'), look for headline '@k foo' as well
231 If key is a valid python name (e.g. 'foo'), look for headline '@k foo' as well
232 """
232 """
233 key = str(key)
233 key = str(key)
234 d = self.__children()
234 d = self.__children()
235 return d[key]
235 return d[key]
236 def __setitem__(self, key, val):
236 def __setitem__(self, key, val):
237 """ You can do wb.foo['My Stuff'] = 12 to create children
237 """ You can do wb.foo['My Stuff'] = 12 to create children
238
238
239 This will create 'My Stuff' as a child of foo (if it does not exist), and
239 This will create 'My Stuff' as a child of foo (if it does not exist), and
240 do .v = 12 assignment.
240 do .v = 12 assignment.
241
241
242 Exception:
242 Exception:
243
243
244 wb.foo['bar'] = 12
244 wb.foo['bar'] = 12
245
245
246 will create a child with headline '@k bar', because bar is a valid python name
246 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
247 and we don't want to crowd the WorkBook namespace with (possibly numerous) entries
248 """
248 """
249 key = str(key)
249 key = str(key)
250 d = self.__children()
250 d = self.__children()
251 if key in d:
251 if key in d:
252 d[key].v = val
252 d[key].v = val
253 return
253 return
254
254
255 if not valid_attribute(key):
255 if not valid_attribute(key):
256 head = key
256 head = key
257 else:
257 else:
258 head = '@k ' + key
258 head = '@k ' + key
259 p = c.createLastChildNode(self.p, head, '')
259 p = c.createLastChildNode(self.p, head, '')
260 LeoNode(p).v = val
260 LeoNode(p).v = val
261
261
262 def ipush(self):
262 def ipush(self):
263 """ Does push-to-ipython on the node """
263 """ Does push-to-ipython on the node """
264 push_from_leo(self)
264 push_from_leo(self)
265
265
266 def go(self):
266 def go(self):
267 """ Set node as current node (to quickly see it in Outline) """
267 """ Set node as current node (to quickly see it in Outline) """
268 c.beginUpdate()
268 c.beginUpdate()
269 try:
269 try:
270 c.setCurrentPosition(self.p)
270 c.setCurrentPosition(self.p)
271 finally:
271 finally:
272 c.endUpdate()
272 c.endUpdate()
273
273
274 def script(self):
274 def script(self):
275 """ Method to get the 'tangled' contents of the node
275 """ Method to get the 'tangled' contents of the node
276
276
277 (parse @others, << section >> references etc.)
277 (parse @others, << section >> references etc.)
278 """
278 """
279 return g.getScript(c,self.p,useSelectedText=False,useSentinels=False)
279 return g.getScript(c,self.p,useSelectedText=False,useSentinels=False)
280
280
281 def __get_uA(self):
281 def __get_uA(self):
282 p = self.p
282 p = self.p
283 # Create the uA if necessary.
283 # Create the uA if necessary.
284 if not hasattr(p.v.t,'unknownAttributes'):
284 if not hasattr(p.v.t,'unknownAttributes'):
285 p.v.t.unknownAttributes = {}
285 p.v.t.unknownAttributes = {}
286
286
287 d = p.v.t.unknownAttributes.setdefault('ipython', {})
287 d = p.v.t.unknownAttributes.setdefault('ipython', {})
288 return d
288 return d
289
289
290 uA = property(__get_uA, doc = "Access persistent unknownAttributes of node")
290 uA = property(__get_uA, doc = "Access persistent unknownAttributes of node")
291
291
292
292
293 class LeoWorkbook:
293 class LeoWorkbook:
294 """ class for 'advanced' node access
294 """ class for 'advanced' node access
295
295
296 Has attributes for all "discoverable" nodes. Node is discoverable if it
296 Has attributes for all "discoverable" nodes. Node is discoverable if it
297 either
297 either
298
298
299 - has a valid python name (Foo, bar_12)
299 - 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)
300 - is a parent of an anchor node (if it has a child '@a foo', it is visible as foo)
301
301
302 """
302 """
303 def __getattr__(self, key):
303 def __getattr__(self, key):
304 if key.startswith('_') or key == 'trait_names' or not valid_attribute(key):
304 if key.startswith('_') or key == 'trait_names' or not valid_attribute(key):
305 raise AttributeError
305 raise AttributeError
306 cells = all_cells()
306 cells = all_cells()
307 p = cells.get(key, None)
307 p = cells.get(key, None)
308 if p is None:
308 if p is None:
309 return add_var(key)
309 return add_var(key)
310
310
311 return LeoNode(p)
311 return LeoNode(p)
312
312
313 def __str__(self):
313 def __str__(self):
314 return "<LeoWorkbook>"
314 return "<LeoWorkbook>"
315 def __setattr__(self,key, val):
315 def __setattr__(self,key, val):
316 raise AttributeError("Direct assignment to workbook denied, try wb.%s.v = %s" % (key,val))
316 raise AttributeError("Direct assignment to workbook denied, try wb.%s.v = %s" % (key,val))
317
317
318 __repr__ = __str__
318 __repr__ = __str__
319
319
320 def __iter__(self):
320 def __iter__(self):
321 """ Iterate all (even non-exposed) nodes """
321 """ Iterate all (even non-exposed) nodes """
322 cells = all_cells()
322 cells = all_cells()
323 return (LeoNode(p) for p in c.allNodes_iter())
323 return (LeoNode(p) for p in c.allNodes_iter())
324
324
325 current = property(lambda self: LeoNode(c.currentPosition()), doc = "Currently selected node")
325 current = property(lambda self: LeoNode(c.currentPosition()), doc = "Currently selected node")
326
326
327 def match_h(self, regex):
327 def match_h(self, regex):
328 cmp = re.compile(regex)
328 cmp = re.compile(regex)
329 for node in self:
329 for node in self:
330 if re.match(cmp, node.h, re.IGNORECASE):
330 if re.match(cmp, node.h, re.IGNORECASE):
331 yield node
331 yield node
332 return
332 return
333
333
334 @IPython.generics.complete_object.when_type(LeoWorkbook)
334 @IPython.generics.complete_object.when_type(LeoWorkbook)
335 def workbook_complete(obj, prev):
335 def workbook_complete(obj, prev):
336 return all_cells().keys() + [s for s in prev if not s.startswith('_')]
336 return all_cells().keys() + [s for s in prev if not s.startswith('_')]
337
337
338
338
339 def add_var(varname):
339 def add_var(varname):
340 c.beginUpdate()
340 c.beginUpdate()
341 r = rootnode()
341 r = rootnode()
342 try:
342 try:
343 if r is None:
343 if r is None:
344 p2 = g.findNodeAnywhere(c,varname)
344 p2 = g.findNodeAnywhere(c,varname)
345 else:
345 else:
346 p2 = g.findNodeInChildren(c, r.p, varname)
346 p2 = g.findNodeInChildren(c, r.p, varname)
347 if p2:
347 if p2:
348 return LeoNode(p2)
348 return LeoNode(p2)
349
349
350 if r is not None:
350 if r is not None:
351 p2 = r.p.insertAsLastChild()
351 p2 = r.p.insertAsLastChild()
352
352
353 else:
353 else:
354 p2 = c.currentPosition().insertAfter()
354 p2 = c.currentPosition().insertAfter()
355
355
356 c.setHeadString(p2,varname)
356 c.setHeadString(p2,varname)
357 return LeoNode(p2)
357 return LeoNode(p2)
358 finally:
358 finally:
359 c.endUpdate()
359 c.endUpdate()
360
360
361 def add_file(self,fname):
361 def add_file(self,fname):
362 p2 = c.currentPosition().insertAfter()
362 p2 = c.currentPosition().insertAfter()
363
363
364 push_from_leo = CommandChainDispatcher()
364 push_from_leo = CommandChainDispatcher()
365
365
366 def expose_ileo_push(f, prio = 0):
366 def expose_ileo_push(f, prio = 0):
367 push_from_leo.add(f, prio)
367 push_from_leo.add(f, prio)
368
368
369 def push_ipython_script(node):
369 def push_ipython_script(node):
370 """ Execute the node body in IPython, as if it was entered in interactive prompt """
370 """ Execute the node body in IPython, as if it was entered in interactive prompt """
371 c.beginUpdate()
371 c.beginUpdate()
372 try:
372 try:
373 ohist = ip.IP.output_hist
373 ohist = ip.IP.output_hist
374 hstart = len(ip.IP.input_hist)
374 hstart = len(ip.IP.input_hist)
375 script = node.script()
375 script = node.script()
376
376
377 script = g.splitLines(script + '\n')
377 script = g.splitLines(script + '\n')
378 ip.user_ns['_p'] = node
378 ip.user_ns['_p'] = node
379 ip.runlines(script)
379 ip.runlines(script)
380 ip.user_ns.pop('_p',None)
380 ip.user_ns.pop('_p',None)
381
381
382 has_output = False
382 has_output = False
383 for idx in range(hstart,len(ip.IP.input_hist)):
383 for idx in range(hstart,len(ip.IP.input_hist)):
384 val = ohist.get(idx,None)
384 val = ohist.get(idx,None)
385 if val is None:
385 if val is None:
386 continue
386 continue
387 has_output = True
387 has_output = True
388 inp = ip.IP.input_hist[idx]
388 inp = ip.IP.input_hist[idx]
389 if inp.strip():
389 if inp.strip():
390 es('In: %s' % (inp[:40], ))
390 es('In: %s' % (inp[:40], ))
391
391
392 es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)))
392 es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)))
393
393
394 if not has_output:
394 if not has_output:
395 es('ipy run: %s (%d LL)' %( node.h,len(script)))
395 es('ipy run: %s (%d LL)' %( node.h,len(script)))
396 finally:
396 finally:
397 c.endUpdate()
397 c.endUpdate()
398
398
399
399
400 def eval_body(body):
400 def eval_body(body):
401 try:
401 try:
402 val = ip.ev(body)
402 val = ip.ev(body)
403 except:
403 except:
404 # just use stringlist if it's not completely legal python expression
404 # just use stringlist if it's not completely legal python expression
405 val = IPython.genutils.SList(body.splitlines())
405 val = IPython.genutils.SList(body.splitlines())
406 return val
406 return val
407
407
408 def push_plain_python(node):
408 def push_plain_python(node):
409 if not node.h.endswith('P'):
409 if not node.h.endswith('P'):
410 raise TryNext
410 raise TryNext
411 script = node.script()
411 script = node.script()
412 lines = script.count('\n')
412 lines = script.count('\n')
413 try:
413 try:
414 exec script in ip.user_ns
414 exec script in ip.user_ns
415 except:
415 except:
416 print " -- Exception in script:\n"+script + "\n --"
416 print " -- Exception in script:\n"+script + "\n --"
417 raise
417 raise
418 es('ipy plain: %s (%d LL)' % (node.h,lines))
418 es('ipy plain: %s (%d LL)' % (node.h,lines))
419
419
420
420
421 def push_cl_node(node):
421 def push_cl_node(node):
422 """ If node starts with @cl, eval it
422 """ If node starts with @cl, eval it
423
423
424 The result is put as last child of @ipy-results node, if it exists
424 The result is put as last child of @ipy-results node, if it exists
425 """
425 """
426 if not node.b.startswith('@cl'):
426 if not node.b.startswith('@cl'):
427 raise TryNext
427 raise TryNext
428
428
429 p2 = g.findNodeAnywhere(c,'@ipy-results')
429 p2 = g.findNodeAnywhere(c,'@ipy-results')
430 val = node.v
430 val = node.v
431 if p2:
431 if p2:
432 es("=> @ipy-results")
432 es("=> @ipy-results")
433 LeoNode(p2).v = val
433 LeoNode(p2).v = val
434 es(val)
434 es(val)
435
435
436 def push_ev_node(node):
436 def push_ev_node(node):
437 """ If headline starts with @ev, eval it and put result in body """
437 """ If headline starts with @ev, eval it and put result in body """
438 if not node.h.startswith('@ev '):
438 if not node.h.startswith('@ev '):
439 raise TryNext
439 raise TryNext
440 expr = node.h.lstrip('@ev ')
440 expr = node.h.lstrip('@ev ')
441 es('ipy eval ' + expr)
441 es('ipy eval ' + expr)
442 res = ip.ev(expr)
442 res = ip.ev(expr)
443 node.v = res
443 node.v = res
444
444
445
445
446 def push_position_from_leo(p):
446 def push_position_from_leo(p):
447 push_from_leo(LeoNode(p))
447 push_from_leo(LeoNode(p))
448
448
449 @generic
449 @generic
450 def edit_object_in_leo(obj, varname):
450 def edit_object_in_leo(obj, varname):
451 """ Make it @cl node so it can be pushed back directly by alt+I """
451 """ Make it @cl node so it can be pushed back directly by alt+I """
452 node = add_var(varname)
452 node = add_var(varname)
453 formatted = format_for_leo(obj)
453 formatted = format_for_leo(obj)
454 if not formatted.startswith('@cl'):
454 if not formatted.startswith('@cl'):
455 formatted = '@cl\n' + formatted
455 formatted = '@cl\n' + formatted
456 node.b = formatted
456 node.b = formatted
457 node.go()
457 node.go()
458
458
459 @edit_object_in_leo.when_type(IPython.macro.Macro)
459 @edit_object_in_leo.when_type(IPython.macro.Macro)
460 def edit_macro(obj,varname):
460 def edit_macro(obj,varname):
461 bod = '_ip.defmacro("""\\\n' + obj.value + '""")'
461 bod = '_ip.defmacro("""\\\n' + obj.value + '""")'
462 node = add_var('Macro_' + varname)
462 node = add_var('Macro_' + varname)
463 node.b = bod
463 node.b = bod
464 node.go()
464 node.go()
465
465
466 def get_history(hstart = 0):
466 def get_history(hstart = 0):
467 res = []
467 res = []
468 ohist = ip.IP.output_hist
468 ohist = ip.IP.output_hist
469
469
470 for idx in range(hstart, len(ip.IP.input_hist)):
470 for idx in range(hstart, len(ip.IP.input_hist)):
471 val = ohist.get(idx,None)
471 val = ohist.get(idx,None)
472 has_output = True
472 has_output = True
473 inp = ip.IP.input_hist_raw[idx]
473 inp = ip.IP.input_hist_raw[idx]
474 if inp.strip():
474 if inp.strip():
475 res.append('In [%d]: %s' % (idx, inp))
475 res.append('In [%d]: %s' % (idx, inp))
476 if val:
476 if val:
477 res.append(pprint.pformat(val))
477 res.append(pprint.pformat(val))
478 res.append('\n')
478 res.append('\n')
479 return ''.join(res)
479 return ''.join(res)
480
480
481
481
482 def lee_f(self,s):
482 def lee_f(self,s):
483 """ Open file(s)/objects in Leo
483 """ Open file(s)/objects in Leo
484
484
485 - %lee hist -> open full session history in leo
485 - %lee hist -> open full session history in leo
486 - Takes an object
486 - Takes an object. l = [1,2,"hello"]; %lee l. Alt+I in leo pushes the object back
487 - Takes an mglob pattern, e.g. '%lee *.cpp' or %leo 'rec:*.cpp'
487 - Takes an mglob pattern, e.g. '%lee *.cpp' or %lee 'rec:*.cpp'
488 - Takes input history indices: %lee 4 6-8 10 12-47
488 """
489 """
489 import os
490 import os
490
491
491 c.beginUpdate()
492 c.beginUpdate()
492 try:
493 try:
493 if s == 'hist':
494 if s == 'hist':
494 wb.ipython_history.b = get_history()
495 wb.ipython_history.b = get_history()
495 wb.ipython_history.go()
496 wb.ipython_history.go()
496 return
497 return
497
498
498
499
500 if s and s[0].isdigit():
501 # numbers; push input slices to leo
502 lines = self.extract_input_slices(s.strip().split(), True)
503 v = add_var('stored_ipython_input')
504 v.b = '\n'.join(lines)
505 return
506
499
507
500 # try editing the object directly
508 # try editing the object directly
501 obj = ip.user_ns.get(s, None)
509 obj = ip.user_ns.get(s, None)
502 if obj is not None:
510 if obj is not None:
503 edit_object_in_leo(obj,s)
511 edit_object_in_leo(obj,s)
504 return
512 return
505
513
514
506 # if it's not object, it's a file name / mglob pattern
515 # if it's not object, it's a file name / mglob pattern
507 from IPython.external import mglob
516 from IPython.external import mglob
508
517
509 files = (os.path.abspath(f) for f in mglob.expand(s))
518 files = (os.path.abspath(f) for f in mglob.expand(s))
510 for fname in files:
519 for fname in files:
511 p = g.findNodeAnywhere(c,'@auto ' + fname)
520 p = g.findNodeAnywhere(c,'@auto ' + fname)
512 if not p:
521 if not p:
513 p = c.currentPosition().insertAfter()
522 p = c.currentPosition().insertAfter()
514
523
515 p.setHeadString('@auto ' + fname)
524 p.setHeadString('@auto ' + fname)
516 if os.path.isfile(fname):
525 if os.path.isfile(fname):
517 c.setBodyString(p,open(fname).read())
526 c.setBodyString(p,open(fname).read())
518 c.selectPosition(p)
527 c.selectPosition(p)
519 print "Editing file(s), press ctrl+shift+w in Leo to write @auto nodes"
528 print "Editing file(s), press ctrl+shift+w in Leo to write @auto nodes"
520 finally:
529 finally:
521 c.endUpdate()
530 c.endUpdate()
522
531
523
532
524
533
525 def leoref_f(self,s):
534 def leoref_f(self,s):
526 """ Quick reference for ILeo """
535 """ Quick reference for ILeo """
527 import textwrap
536 import textwrap
528 print textwrap.dedent("""\
537 print textwrap.dedent("""\
529 %leoe file/object - open file / object in leo
538 %leoe file/object - open file / object in leo
530 wb.foo.v - eval node foo (i.e. headstring is 'foo' or '@ipy foo')
539 wb.foo.v - eval node foo (i.e. headstring is 'foo' or '@ipy foo')
531 wb.foo.v = 12 - assign to body of node foo
540 wb.foo.v = 12 - assign to body of node foo
532 wb.foo.b - read or write the body of node foo
541 wb.foo.b - read or write the body of node foo
533 wb.foo.l - body of node foo as string list
542 wb.foo.l - body of node foo as string list
534
543
535 for el in wb.foo:
544 for el in wb.foo:
536 print el.v
545 print el.v
537
546
538 """
547 """
539 )
548 )
540
549
541
550
542
551
543 def mb_f(self, arg):
552 def mb_f(self, arg):
544 """ Execute leo minibuffer commands
553 """ Execute leo minibuffer commands
545
554
546 Example:
555 Example:
547 mb save-to-file
556 mb save-to-file
548 """
557 """
549 c.executeMinibufferCommand(arg)
558 c.executeMinibufferCommand(arg)
550
559
551 def mb_completer(self,event):
560 def mb_completer(self,event):
552 """ Custom completer for minibuffer """
561 """ Custom completer for minibuffer """
553 cmd_param = event.line.split()
562 cmd_param = event.line.split()
554 if event.line.endswith(' '):
563 if event.line.endswith(' '):
555 cmd_param.append('')
564 cmd_param.append('')
556 if len(cmd_param) > 2:
565 if len(cmd_param) > 2:
557 return ip.IP.Completer.file_matches(event.symbol)
566 return ip.IP.Completer.file_matches(event.symbol)
558 cmds = c.commandsDict.keys()
567 cmds = c.commandsDict.keys()
559 cmds.sort()
568 cmds.sort()
560 return cmds
569 return cmds
561
570
562 def show_welcome():
571 def show_welcome():
563 print "------------------"
572 print "------------------"
564 print "Welcome to Leo-enabled IPython session!"
573 print "Welcome to Leo-enabled IPython session!"
565 print "Try %leoref for quick reference."
574 print "Try %leoref for quick reference."
566 import IPython.platutils
575 import IPython.platutils
567 IPython.platutils.set_term_title('ILeo')
576 IPython.platutils.set_term_title('ILeo')
568 IPython.platutils.freeze_term_title()
577 IPython.platutils.freeze_term_title()
569
578
570 def run_leo_startup_node():
579 def run_leo_startup_node():
571 p = g.findNodeAnywhere(c,'@ipy-startup')
580 p = g.findNodeAnywhere(c,'@ipy-startup')
572 if p:
581 if p:
573 print "Running @ipy-startup nodes"
582 print "Running @ipy-startup nodes"
574 for n in LeoNode(p):
583 for n in LeoNode(p):
575 push_from_leo(n)
584 push_from_leo(n)
576
585
577
586
General Comments 0
You need to be logged in to leave comments. Login now