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