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