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