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