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