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