##// END OF EJS Templates
cd -foo jumps to dir matching 'foo' in directory history
Ville M. Vainio -
Show More

The requested changes are too big and content was truncated. Show full diff

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