├── CodeManipulator.py ├── Default (Linux).sublime-keymap ├── Default (OSX).sublime-keymap ├── Default (Windows).sublime-keymap ├── Default.sublime-commands ├── FoldPython.sublime-settings ├── Main.sublime-menu ├── README.md └── SublimeFold.py /CodeManipulator.py: -------------------------------------------------------------------------------- 1 | import sublime, sublime_plugin 2 | VERBOSE = 5 3 | 4 | def log(message,verbose=1): 5 | '''print a message with verbose limit 6 | ''' 7 | if verbose <= VERBOSE: 8 | print('%s:%s' % (verbose, message) ) 9 | 10 | class FLine(object): 11 | '''line in sublime 12 | ''' 13 | def __init__(self, view=None, region=None, edit=None): 14 | '''initiates the line extracter 15 | ''' 16 | self._tabString = None 17 | self._view = view 18 | self._region = region 19 | self._edit = edit 20 | 21 | if view: 22 | tabSize = view.settings().get("tab_size") 23 | tabsToSpaces = view.settings().get("translate_tabs_to_spaces") 24 | 25 | if tabsToSpaces: 26 | self._tabString = ' ' * tabSize 27 | else: 28 | self._tabString = '\t' 29 | 30 | #attributes 31 | def data(self): 32 | '''get data 33 | ''' 34 | dataDict = {} 35 | dataDict["view"] = self.view() 36 | dataDict["region"] = self.region() 37 | dataDict["tabString"] = self.tabString() 38 | dataDict["edit"] = self.edit() 39 | return dataDict 40 | 41 | def setData(self, dataDict): 42 | '''set data 43 | ''' 44 | self.setView( dataDict["view"] ) 45 | self.setRegion( dataDict["region"] ) 46 | self.setTabString( dataDict["tabString"] ) 47 | self.setEdit( dataDict["edit"] ) 48 | 49 | def edit(self): 50 | '''get edit 51 | ''' 52 | return self._edit 53 | 54 | def setEdit(self, value): 55 | '''set edit 56 | ''' 57 | self._edit = value 58 | 59 | def tabString(self): 60 | '''return the tabString 61 | ''' 62 | return self._tabString 63 | 64 | def setTabString(self, value): 65 | self._tabString = value 66 | 67 | def region(self): 68 | '''get region 69 | ''' 70 | return self._region 71 | 72 | def setRegion(self, value): 73 | '''set region 74 | ''' 75 | self._region = value 76 | 77 | def view(self): 78 | '''get view 79 | ''' 80 | return self._view 81 | 82 | def setView(self, value): 83 | '''set view 84 | ''' 85 | self._view = value 86 | 87 | # methods 88 | def isEmpty(self): 89 | '''check if it is empty line 90 | ''' 91 | if self.lineString().strip() == '': 92 | return True 93 | else: 94 | return False 95 | 96 | def spaceDepth(self): 97 | '''return the depth of the selected line 98 | ''' 99 | view = self.view() 100 | region = self.region() 101 | lineRegion = view.line(region) 102 | lineString = view.substr( lineRegion ) 103 | log('lineString=%s' % lineString, 6) 104 | 105 | counter = 0 106 | for i in lineString.split(' '): 107 | if i == '': 108 | counter += 1 109 | else: 110 | break 111 | return counter 112 | 113 | def tabDepth(self): 114 | '''return the dpeth of the selected line in tabs 115 | ''' 116 | view = self.view() 117 | region = self.region() 118 | lineRegion = view.line(region) 119 | lineString = view.substr( lineRegion ) 120 | counter = 0 121 | 122 | log('lineString=%s' % lineString, 6) 123 | 124 | for i in lineString.split('\t'): 125 | if i == '': 126 | counter += 1 127 | else: 128 | break 129 | return counter 130 | 131 | def depth(self): 132 | '''return the depth of the region 133 | ''' 134 | view = self.view() 135 | tabSize = view.settings().get("tab_size") 136 | tabsToSpaces = view.settings().get("translate_tabs_to_spaces") 137 | 138 | if tabsToSpaces: 139 | return int(self.spaceDepth() / 4) 140 | else: 141 | return int(self.tabDepth() ) 142 | 143 | def lineString(self): 144 | '''return the line as string 145 | ''' 146 | view = self.view() 147 | region = self.region() 148 | lineRegion = view.line(region) 149 | log('lineRegion=%s' % lineRegion, 6) 150 | return view.substr ( lineRegion ) 151 | 152 | def goToRegion(self): 153 | '''return the region of the beginning of the line 154 | ''' 155 | view = self.view() 156 | region = self.region() 157 | 158 | lineRegion = view.line(region) 159 | lineString = view.substr ( lineRegion ) 160 | strippedLineString = lineString.strip() 161 | startOffset = lineString.find(strippedLineString) 162 | startRegion = sublime.Region( lineRegion.a + startOffset, lineRegion.a + startOffset) 163 | return startRegion 164 | 165 | def lineDown(self): 166 | '''get the one line up 167 | ''' 168 | view = self.view() 169 | edit = self.edit() 170 | region = self.region() 171 | lineRegion = view.line(region) 172 | endLineBefore = lineRegion.b + 1 173 | 174 | maxRange = view.size() 175 | if endLineBefore >= maxRange: 176 | return None 177 | 178 | lineDownRegion = view.line( sublime.Region( endLineBefore, endLineBefore) ) 179 | 180 | return FLine(view, lineDownRegion, edit ) 181 | 182 | def lineUp(self): 183 | '''get the one line up 184 | ''' 185 | view = self.view() 186 | region = self.region() 187 | lineRegion = view.line(region) 188 | endLineBefore = lineRegion.a -1 189 | edit = self.edit() 190 | 191 | if endLineBefore < 0: 192 | return None 193 | 194 | lineBeforeRegion = view.line( sublime.Region( endLineBefore, endLineBefore) ) 195 | 196 | return FLine(view, lineBeforeRegion, edit) 197 | 198 | def grandChildren(self): 199 | '''return the grand child 200 | ''' 201 | depth = self.depth() 202 | linedownDepth = None 203 | lineDown = self 204 | loop = True 205 | children = [] 206 | 207 | while loop: 208 | lineDown = lineDown.lineDown() 209 | if lineDown == None: 210 | loop = False 211 | continue 212 | 213 | if lineDown.isEmpty(): 214 | continue 215 | 216 | linedownDepth = lineDown.depth() 217 | if linedownDepth > depth : 218 | children.append(lineDown) 219 | 220 | if linedownDepth == depth: 221 | break 222 | 223 | if linedownDepth < depth: 224 | break 225 | 226 | return children 227 | 228 | def hasChildren(self): 229 | '''return if has children 230 | ''' 231 | depth = self.depth() 232 | linedownDepth = None 233 | lineDown = self 234 | loop = True 235 | children = [] 236 | 237 | while loop: 238 | lineDown = lineDown.lineDown() 239 | if lineDown == None: 240 | loop = False 241 | continue 242 | 243 | if lineDown.isEmpty(): 244 | continue 245 | 246 | linedownDepth = lineDown.depth() 247 | if linedownDepth == depth + 1: 248 | return True 249 | 250 | if linedownDepth == depth: 251 | return False 252 | 253 | return False 254 | 255 | def children(self): 256 | '''return the children 257 | ''' 258 | depth = self.depth() 259 | linedownDepth = None 260 | lineDown = self 261 | loop = True 262 | children = [] 263 | 264 | while loop: 265 | lineDown = lineDown.lineDown() 266 | if lineDown == None: 267 | loop = False 268 | continue 269 | 270 | if lineDown.isEmpty(): 271 | continue 272 | 273 | linedownDepth = lineDown.depth() 274 | if linedownDepth == depth + 1: 275 | children.append(lineDown) 276 | 277 | if linedownDepth == depth: 278 | break 279 | 280 | return children 281 | 282 | def contentRegion(self): 283 | '''return the region of the whole content. 284 | ''' 285 | children = self.grandChildren() 286 | lastChild = None 287 | firstChild = None 288 | 289 | if len(children) == 0: 290 | return None 291 | 292 | firstChild = children[0] 293 | 294 | if len(children) > 1: 295 | lastChild = children[-1] 296 | else: 297 | lastChild = firstChild 298 | 299 | contentRegion = sublime.Region( firstChild.region().a - 1, lastChild.region().b ) 300 | return contentRegion 301 | 302 | def parent(self): 303 | '''return parent line 304 | ''' 305 | depth = self.depth() 306 | lineupDepth = None 307 | lineUp = self 308 | loop = True 309 | parent = None 310 | 311 | while loop: 312 | lineUp = lineUp.lineUp() 313 | if lineUp == None: 314 | loop = False 315 | continue 316 | 317 | if lineUp.isEmpty(): 318 | continue 319 | 320 | lineupDepth = lineUp.depth() 321 | 322 | if lineupDepth < depth: 323 | loop = False 324 | parent = lineUp 325 | return parent 326 | 327 | def siblingUp(self): 328 | '''return sibling upwards 329 | ''' 330 | depth = self.depth() 331 | lineupDepth = None 332 | lineUp = self 333 | loop = True 334 | parent = None 335 | 336 | while loop: 337 | lineUp = lineUp.lineUp() 338 | if lineUp == None: 339 | loop = False 340 | continue 341 | 342 | if lineUp.isEmpty(): 343 | continue 344 | 345 | if not lineUp.hasChildren(): 346 | continue 347 | 348 | lineupDepth = lineUp.depth() 349 | 350 | # is in a parent, not a sibling 351 | if lineupDepth < depth: 352 | return 353 | 354 | if lineupDepth == depth: 355 | loop = False 356 | parent = lineUp 357 | return parent 358 | 359 | def siblingDown(self): 360 | '''return sibling upwards 361 | ''' 362 | depth = self.depth() 363 | lineupDepth = None 364 | lineDown = self 365 | loop = True 366 | parent = None 367 | 368 | while loop: 369 | lineDown = lineDown.lineDown() 370 | if lineDown == None: 371 | loop = False 372 | continue 373 | 374 | if lineDown.isEmpty(): 375 | continue 376 | 377 | if len(lineDown.children()) == 0: 378 | continue 379 | 380 | lineupDepth = lineDown.depth() 381 | 382 | # is in a parent, not a sibling 383 | if lineupDepth < depth: 384 | return 385 | 386 | if lineupDepth == depth: 387 | loop = False 388 | parent = lineDown 389 | return parent 390 | 391 | def siblingsUp(self): 392 | '''return all siblings up 393 | ''' 394 | loop = True 395 | siblingUp = self 396 | siblingUps = [] 397 | while loop: 398 | siblingUp = siblingUp.siblingUp() 399 | if siblingUp == None: 400 | loop = False 401 | continue 402 | siblingUps.append(siblingUp) 403 | 404 | return siblingUps 405 | 406 | def siblingsDown(self): 407 | '''return all siblings down 408 | ''' 409 | loop = True 410 | siblingDown = self 411 | siblingDowns = [] 412 | while loop: 413 | siblingDown = siblingDown.siblingDown() 414 | if siblingDown == None: 415 | loop = False 416 | continue 417 | siblingDowns.append(siblingDown) 418 | 419 | return siblingDowns 420 | 421 | def siblings(self): 422 | '''return all siblins up and down 423 | ''' 424 | siblingsUp = self.siblingsUp() 425 | siblingsDown = self.siblingsDown() 426 | 427 | siblingsUp.reverse() 428 | 429 | return siblingsUp + siblingsDown 430 | 431 | def adultDown(self): 432 | '''get the adult downwards 433 | ''' 434 | depth = self.depth() 435 | lineupDepth = None 436 | lineDown = self 437 | loop = True 438 | parent = None 439 | 440 | while loop: 441 | lineDown = lineDown.lineDown() 442 | if lineDown == None: 443 | loop = False 444 | continue 445 | 446 | if lineDown.isEmpty(): 447 | continue 448 | 449 | lineupDepth = lineDown.depth() 450 | 451 | if lineupDepth < depth: 452 | loop = False 453 | parent = lineDown 454 | return parent 455 | 456 | def documentationRegion(self): 457 | '''return the region of the docstring 458 | ''' 459 | view = self.view() 460 | region = self.region() 461 | start = None 462 | end = None 463 | lineDown = self.lineDown() 464 | lineDownRegion = lineDown.region() 465 | lineDownString = view.substr( lineDownRegion ) 466 | docSign = "'''" 467 | 468 | splittedString = lineDownString.split(docSign) 469 | 470 | if len(splittedString) == 1: 471 | docSign = '"""' 472 | splittedString = lineDownString.split(docSign) 473 | 474 | # if contains the doc start 475 | if len(splittedString) > 1: 476 | print(lineDownString) 477 | start = lineDown.region().a 478 | 479 | if len(splittedString) > 2: 480 | end = lineDown.region().b 481 | else: 482 | # find the end of docstring in next lines 483 | loop = True 484 | line = lineDown 485 | while loop: 486 | line = line.lineDown() 487 | if line is None: 488 | loop = False 489 | continue 490 | 491 | lineRegion = line.region() 492 | lineString = view.substr( lineRegion ) 493 | if lineString.find(docSign) != -1: 494 | end = lineRegion.b 495 | loop = False 496 | if start and end: 497 | return sublime.Region(start, end) 498 | 499 | def createChildAbove(self, index, value): 500 | view = self.view() 501 | edit = self.edit() 502 | 503 | children = self.children() 504 | 505 | child = children[index] 506 | point = child.region().a 507 | depthSpace = FLineUtils(self.view() ).createDepth(self.depth() + 1) 508 | 509 | insertString = depthSpace + value + '\n' 510 | 511 | view.insert(edit, point , insertString) 512 | region = sublime.Region(point + 1, point + len(insertString) ) 513 | return FLine(view,region,edit) 514 | 515 | def createChildBelow(self, index, value): 516 | 517 | view = self.view() 518 | edit = self.edit() 519 | 520 | children = self.children() 521 | 522 | child = children[index] 523 | point = child.region().b 524 | contentRegion = child.contentRegion() 525 | if contentRegion: 526 | point = contentRegion.b 527 | 528 | depthSpace = FLineUtils(self.view() ).createDepth(self.depth() + 1) 529 | 530 | insertString = '\n' + depthSpace + value 531 | 532 | view.insert(edit, point , insertString) 533 | 534 | region = sublime.Region(point + 1, point + len(insertString) ) 535 | 536 | return FLine(view,region,edit) 537 | 538 | def createChild(self, value): 539 | return self.createLastChild(value) 540 | 541 | def createFirstChild(self, value): 542 | '''add a child to the current item 543 | ''' 544 | view = self.view() 545 | edit = self.edit() 546 | point = self.region().b 547 | 548 | depthSpace = FLineUtils(self.view() ).createDepth(self.depth() + 1) 549 | 550 | insertString = '\n' + depthSpace + value 551 | 552 | view.insert(edit, point , insertString) 553 | region = sublime.Region(point + 1, point + len(insertString) ) 554 | return FLine(view,region,edit) 555 | 556 | def createLastChild(self, value): 557 | '''add a last child 558 | ''' 559 | view = self.view() 560 | edit = self.edit() 561 | region = self.region() 562 | 563 | contentRegion = self.contentRegion() 564 | if contentRegion: 565 | point = contentRegion.b 566 | else: 567 | point = region.b 568 | 569 | depthSpace = FLineUtils(self.view() ).createDepth(self.depth() + 1) 570 | 571 | insertString = '\n' + depthSpace + value 572 | 573 | view.insert(edit, point , insertString) 574 | region = sublime.Region(point + 1, point + len(insertString) ) 575 | return FLine(view,region,edit) 576 | 577 | def erase(self): 578 | '''erase this line and children from the view 579 | ''' 580 | view = self.view() 581 | edit = self.edit() 582 | region = self.region() 583 | startPoint = region.a 584 | endPoint = region.b 585 | 586 | contentRegion = self.contentRegion() 587 | if contentRegion: 588 | endPoint = contentRegion.b 589 | 590 | 591 | region = sublime.Region( startPoint - 1, endPoint ) 592 | view.erase(edit, region ) 593 | 594 | 595 | class FPythonLine(FLine): 596 | """a python line with smarter analyze function of its task in the file""" 597 | 598 | # constants 599 | TYPE_CLASS = "type_class" 600 | TYPE_EMPTY = "type_empty" 601 | TYPE_DEFINITION = "type_definition" 602 | 603 | # methods 604 | def toClass(self): 605 | '''go to the class 606 | ''' 607 | loop = True 608 | currentParent = self.parent() 609 | 610 | while loop: 611 | if currentParent is None: 612 | loop = False 613 | break 614 | 615 | lineString = currentParent.lineString() 616 | log(lineString) 617 | 618 | 619 | if lineString.find('class ') != -1: 620 | return currentParent 621 | 622 | currentParent = currentParent.parent() 623 | 624 | def toMethod(self): 625 | '''go to the method 626 | ''' 627 | loop = True 628 | currentParent = self.parent() 629 | 630 | while loop: 631 | if currentParent is None: 632 | loop = False 633 | break 634 | 635 | lineString = currentParent.lineString() 636 | log(lineString) 637 | 638 | 639 | if lineString.find('def ') != -1: 640 | return currentParent 641 | 642 | currentParent = currentParent.parent() 643 | 644 | def type(self): 645 | lineString = self.lineString() 646 | 647 | if self.lineString().find('class ') != -1: 648 | return self.TYPE_CLASS 649 | 650 | if self.lineString().find('def ') != -1: 651 | return self.TYPE_DEFINITION 652 | 653 | if self.isEmpty(): 654 | return self.TYPE_EMPTY 655 | 656 | def definitions(self): 657 | definitions = [] 658 | for child in self.children(): 659 | child = FPythonLine(child.view(), child.region(), child.edit() ) 660 | if child.type() == self.TYPE_DEFINITION: 661 | definitions.append(child) 662 | 663 | return definitions 664 | 665 | def findDefinition(self,name): 666 | '''return a definition 667 | ''' 668 | for definition in self.definitions(): 669 | if definition.name() == name: 670 | return definition 671 | 672 | def createDefinition(self, name, arguments): 673 | defLineString = 'def {name}({arguments}):'.format(name=name, arguments=','.join(arguments) ) 674 | return self.createLastChild(defLineString) 675 | 676 | def findCurrentClass(self): 677 | loop = True 678 | currentParent = self.parent() 679 | 680 | if currentParent == None: 681 | return 682 | 683 | currentParent = FPythonLine( currentParent.view(), currentParent.region(), currentParent.edit() ) 684 | while loop: 685 | if not currentParent: 686 | break 687 | 688 | if currentParent.type() == self.TYPE_CLASS: 689 | return currentParent 690 | 691 | currentParent = currentParent.parent() 692 | currentParent = FPythonLine( currentParent.view(), currentParent.region(), currentParent.edit() ) 693 | 694 | 695 | def isClass(self): 696 | '''check if this is class definition 697 | ''' 698 | if self.type() == self.TYPE_CLASS: 699 | return True 700 | 701 | return False 702 | 703 | def isDef(self): 704 | '''check if this is class definition 705 | ''' 706 | if self.type() == self.TYPE_DEFINITION: 707 | return True 708 | 709 | return False 710 | 711 | def name(self): 712 | return self._parseNameDef( self.lineString() ) 713 | 714 | def _parseNameDef(self, lineString): 715 | log('lineString=%s' % lineString, 6) 716 | cutoutFirstPart = lineString.strip().split(' ')[1] 717 | cutoutLastPart = cutoutFirstPart.split('(')[0] 718 | defName = cutoutLastPart.strip() 719 | return defName 720 | 721 | def getterUp(self): 722 | '''return the down setter def if exists 723 | ''' 724 | isDef = self.isDef() 725 | 726 | if not isDef: 727 | return None 728 | 729 | isSiblingGet = False 730 | view = self.view() 731 | siblingUp = self.siblingUp() 732 | 733 | if not siblingUp: 734 | return None 735 | 736 | region = self.region() 737 | 738 | lineString = view.substr( region ) 739 | log('lineString=%s' % lineString, 6) 740 | name = self._parseNameDef(lineString) 741 | 742 | if name.find("set") != -1: 743 | name = name.replace("set", "") 744 | else: 745 | return None 746 | 747 | siblingUpRegion = siblingUp.region() 748 | lineString = view.substr( siblingUpRegion ) 749 | nameSibling = self._parseNameDef(lineString) 750 | 751 | if nameSibling.lower() == "get" + name.lower() or nameSibling.lower() == name.lower(): 752 | isSiblingGet = True 753 | 754 | if isSiblingGet and isDef: 755 | return siblingUp 756 | 757 | def setterDown(self): 758 | '''return the down setter def if exists 759 | ''' 760 | view = self.view() 761 | isDef = self.isDef() 762 | isSiblingSet = False 763 | 764 | if not isDef: 765 | return None 766 | 767 | siblingDown = self.siblingDown() 768 | 769 | if not siblingDown: 770 | return None 771 | 772 | region = self.region() 773 | 774 | lineString = view.substr( region ) 775 | log('lineString=%s' % lineString, 6) 776 | name = self._parseNameDef(lineString) 777 | 778 | if name.find("get") != -1: 779 | name = name.replace("get", "") 780 | 781 | siblingDownRegion = siblingDown.region() 782 | lineString = view.substr( siblingDownRegion ) 783 | nameSibling = self._parseNameDef(lineString) 784 | 785 | if nameSibling.lower() == "set" + name.lower(): 786 | isSiblingSet = True 787 | 788 | if isSiblingSet and isDef: 789 | return siblingDown 790 | 791 | def foldGetterSetterRegions(self): 792 | '''return needd regions to fold 793 | ''' 794 | view = self.view() 795 | regions = [] 796 | region = self.region() 797 | lineString = view.substr( region ) 798 | nameDef = self._parseNameDef(lineString) 799 | 800 | startPoint = region.a + self.lineString().find('def ') 801 | endPoint = startPoint + 4 802 | regions.append( sublime.Region(startPoint, endPoint) ) 803 | 804 | startPoint = region.a + (self.lineString().find(nameDef) + len(nameDef) ) 805 | endPoint = self.siblingDown().contentRegion().b 806 | regions.append( sublime.Region(startPoint, endPoint) ) 807 | 808 | return regions 809 | 810 | class FClassLine(FPythonLine): 811 | pass 812 | 813 | class FLineUtils(object): 814 | """docstring for FLineUtils""" 815 | def __init__(self, view, edit=None): 816 | super(FLineUtils, self).__init__() 817 | self._view = view 818 | self._lineClass = FLine 819 | self._edit = edit 820 | 821 | def createDepth(self, depth): 822 | '''return the depth of the region 823 | ''' 824 | view = self.view() 825 | tabSize = view.settings().get("tab_size") 826 | tabsToSpaces = view.settings().get("translate_tabs_to_spaces") 827 | 828 | if tabsToSpaces: 829 | return ' ' * tabSize * depth 830 | else: 831 | return '\t' * depth 832 | 833 | def edit(self): 834 | '''get edit 835 | ''' 836 | return self._edit 837 | 838 | def setEdit(self, value): 839 | '''set edit 840 | ''' 841 | self._edit = value 842 | 843 | def view(self): 844 | ''' get self._view 845 | ''' 846 | return self._view 847 | 848 | def setView(self, value): 849 | ''' set self._view 850 | ''' 851 | self._view = value 852 | 853 | def lineClass(self): 854 | '''get lineClass 855 | ''' 856 | return self._lineClass 857 | 858 | def setLineClass(self, value): 859 | '''set lineClass 860 | ''' 861 | self._lineClass = value 862 | 863 | def lines(self): 864 | '''return all lines in given view 865 | ''' 866 | view = self.view() 867 | edit = self.edit() 868 | totalRegion = sublime.Region( 0, view.size() ) 869 | lineRegions = view.lines(totalRegion) 870 | lines = [] 871 | 872 | for lineRegion in lineRegions: 873 | line = FLine(view, lineRegion, edit) 874 | lines.append(line) 875 | 876 | return lines 877 | 878 | def currentLine(self): 879 | '''return the current line 880 | ''' 881 | view = self.view() 882 | edit = self.edit() 883 | selections = view.sel() 884 | 885 | if len(selections) == 0: 886 | return None 887 | 888 | line = view.line(selections[0]) 889 | return FLine(view, line, edit) 890 | 891 | class FPythonLineUtils(FLineUtils): 892 | def currentLine(self): 893 | currentLine = super(FPythonLineUtils, self).currentLine() 894 | if currentLine: 895 | line = FPythonLine(currentLine.view(), currentLine.region(), currentLine.edit() ) 896 | return line 897 | 898 | def lines(self): 899 | lines = super(FPythonLineUtils, self).lines() 900 | returnLines = [] 901 | for line in lines: 902 | line = FPythonLine(line.view(), line.region(), line.edit() ) 903 | returnLines.append(line) 904 | 905 | return returnLines 906 | 907 | def findClass(self, name): 908 | for line in self.lines(): 909 | if line.type() == line.TYPE_CLASS and line.name() == name: 910 | return line 911 | 912 | def findDefinition(self, name): 913 | for line in self.lines(): 914 | if line.type() == line.TYPE_DEFINITION and line.name() == name: 915 | return line 916 | 917 | def classes(self): 918 | returnLines = [] 919 | for line in self.lines(): 920 | if line.type() == line.TYPE_CLASS : 921 | returnLines.append(line) 922 | return returnLines 923 | 924 | def definitions(self): 925 | returnLines = [] 926 | for line in self.lines(): 927 | if line.type() == line.TYPE_DEFINITION : 928 | returnLines.append(line) 929 | return returnLines 930 | 931 | 932 | 933 | 934 | 935 | def testView(): 936 | views = (sublime.active_window().views()) 937 | for view in views: 938 | if view.file_name() == r'C:\Users\sven\Dropbox\WG_Code\sfr\common\snippets\helloworld.py': 939 | return view 940 | 941 | 942 | 943 | '''hello world 944 | this is my code 945 | ''' 946 | # view = testView() 947 | 948 | class CodeManipulatorGetterSetter(sublime_plugin.TextCommand): 949 | def createGetterSetter(self, name, edit=None): 950 | if edit is None: 951 | edit = self._edit 952 | 953 | view = sublime.active_window().active_view() 954 | view = testView() 955 | utils = FPythonLineUtils(view, edit) 956 | 957 | # utils.findClass('ClassName').createChildBelow(0, 'hais') 958 | # return 959 | 960 | attributeName = name 961 | classLine = utils.currentLine().findCurrentClass() 962 | initDef = classLine.findDefinition('__init__') 963 | initDef.createLastChild('self._%s = {}' % attributeName) 964 | 965 | 966 | getter = classLine.createDefinition(attributeName,['self']) 967 | 968 | 969 | getter.createChild('return self._%s' % attributeName) 970 | 971 | 972 | setter = classLine.createDefinition('set%s' % attributeName.title(),['self',attributeName]) 973 | setter.createChild('self._%s = %s' % (attributeName, attributeName) ) 974 | 975 | def onDone(self, value): 976 | print (value) 977 | self.createGetterSetter(value) 978 | 979 | def run(self, edit): 980 | '''run 981 | ''' 982 | self._edit = edit 983 | window = sublime.active_window() 984 | window.show_input_panel('attribute', '', self.onDone, None, None) 985 | # createGetterSetter() 986 | 987 | class CodeManipulatorShowActionsCommand(sublime_plugin.TextCommand): 988 | '''test command 989 | ''' 990 | def view(self): 991 | return sublime.active_window().active_view() 992 | 993 | def listCommands(self): 994 | '''return possible commands 995 | ''' 996 | 997 | utils = FPythonLineUtils(self.view) 998 | classLine = utils.currentLine().findClass() 999 | if classLine: 1000 | return ['add getter setter'] 1001 | 1002 | return [] 1003 | 1004 | def onDone(self, index): 1005 | print (index) 1006 | command = self.listCommands()[index] 1007 | print (command) 1008 | 1009 | def run(self, edit): 1010 | window = sublime.active_window() 1011 | view = window.active_view() 1012 | # view = testView() 1013 | utils = FPythonLineUtils(view, edit) 1014 | commands = self.listCommands() 1015 | print(commands) 1016 | window.show_quick_panel(commands, self.onDone) 1017 | 1018 | 1019 | 1020 | class CodeManipulatorDevelopmentCommand(sublime_plugin.TextCommand): 1021 | '''test command 1022 | ''' 1023 | def createGetterSetter(self, edit): 1024 | view = sublime.active_window().active_view() 1025 | view = testView() 1026 | utils = FPythonLineUtils(view, edit) 1027 | 1028 | # utils.findClass('ClassName').createChildBelow(0, 'hais') 1029 | # return 1030 | 1031 | attributeName = 'position' 1032 | classLine = utils.findClass('myClass') 1033 | initDef = classLine.findDefinition('__init__') 1034 | initDef.createLastChild('self._%s = {}' % attributeName) 1035 | 1036 | 1037 | getter = classLine.createDefinition(attributeName,['self']) 1038 | 1039 | 1040 | getter.createChild('return self._%s' % attributeName) 1041 | 1042 | 1043 | setter = classLine.createDefinition('set%s' % attributeName.title(),['self',attributeName]) 1044 | setter.createChild('self._%s = %s' % (attributeName, attributeName) ) 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | def run(self, edit): 1052 | # view = self.view 1053 | self.createGetterSetter(edit) 1054 | 1055 | 1056 | return 1057 | # classline = utils.findClass('ClassName') 1058 | for classLine in utils.classes(): 1059 | print(classLine.name()) 1060 | for definition in classLine.definitions(): 1061 | print('\t' + definition.name()) 1062 | 1063 | 1064 | # myDef = classline.findDefinition('ha') 1065 | # myDef.createFirstChild('# comaaasent') 1066 | # myDef.children()[-1].erase() 1067 | 1068 | # print(classline) 1069 | # print( classline.erase() ) 1070 | # line = utils.currentLine() 1071 | # line.erase() 1072 | 1073 | # line.parent().erase() 1074 | # classLine = utils.currentLine().toClass() 1075 | 1076 | # print(classLine.edit() ) 1077 | 1078 | # child = classLine.createFirstChild('"""hello world"""') 1079 | # print(child.depth()) 1080 | # child.createFirstChild("dd") 1081 | # child.erase() 1082 | 1083 | 1084 | 1085 | 1086 | -------------------------------------------------------------------------------- /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["ctrl+k", "ctrl+left"], "command": "fold_fold_content" }, 3 | { "keys": ["ctrl+k", "ctrl+right"], "command": "fold_unfold_content" }, 4 | { "keys": ["ctrl+k", "ctrl+up"], "command": "fold_go_to_sibling_up" }, 5 | { "keys": ["ctrl+k", "ctrl+down"], "command": "fold_go_to_sibling_down" }, 6 | 7 | { "keys": ["ctrl+k", "ctrl+pageup"], "command": "fold_go_to_parent" }, 8 | { "keys": ["ctrl+k", "ctrl+pagedown"], "command": "fold_go_to_children" }, 9 | { "keys": ["ctrl+k", "ctrl+home"], "command": "fold_go_to_top_sibling" }, 10 | { "keys": ["ctrl+k", "ctrl+end"], "command": "fold_go_to_bottom_sibling" }, 11 | { "keys": ["ctrl+k", "ctrl+enter"], "command": "fold_enter_content" }, 12 | { "keys": ["ctrl+k", "ctrl+space"], "command": "fold_go_to_siblings" }, 13 | { "keys": ["ctrl+k", "ctrl+h"], "command": "fold_show_documentation" }, 14 | 15 | { "keys": ["ctrl+k", "ctrl+n"], "command": "fold_new_sibling" }, 16 | { "keys": ["ctrl+k", "ctrl+i"], "command": "fold_go_to_siblings_inverse" }, 17 | 18 | { "keys": ["ctrl+k", "ctrl+0"], "command": "fold_fold_depth", "args": {"depth": 0} }, 19 | { "keys": ["ctrl+k", "ctrl+1"], "command": "fold_fold_depth", "args": {"depth": 1} }, 20 | { "keys": ["ctrl+k", "ctrl+2"], "command": "fold_fold_depth", "args": {"depth": 2} }, 21 | { "keys": ["ctrl+k", "ctrl+3"], "command": "fold_fold_depth", "args": {"depth": 3} }, 22 | 23 | { "keys": ["ctrl+shift+alt+up"], "command": "fold_go_to_sibling_up" }, 24 | { "keys": ["ctrl+shift+alt+down"], "command": "fold_go_to_sibling_down" }, 25 | { "keys": ["ctrl+shift+alt+left"], "command": "fold_fold_content" }, 26 | { "keys": ["ctrl+shift+alt+right"], "command": "fold_unfold_content" }, 27 | 28 | { "keys": ["ctrl+shift+alt+pageup"], "command": "fold_go_to_parent" }, 29 | { "keys": ["ctrl+shift+alt+pagedown"], "command": "fold_go_to_children" }, 30 | { "keys": ["ctrl+shift+alt+home"], "command": "fold_go_to_top_sibling" }, 31 | { "keys": ["ctrl+shift+alt+end"], "command": "fold_go_to_bottom_sibling" }, 32 | 33 | { "keys": ["ctrl+shift+alt+space"], "command": "fold_go_to_siblings" }, 34 | { "keys": ["ctrl+shift+alt+enter"], "command": "fold_enter_content" }, 35 | 36 | { "keys": ["ctrl+shift+alt+i"], "command": "fold_go_to_siblings_inverse" }, 37 | { "keys": ["ctrl+shift+alt+n"], "command": "fold_new_sibling" }, 38 | { "keys": ["ctrl+shift+alt+h"], "command": "fold_show_documentation" }, 39 | { "keys": ["ctrl+shift+alt+i"], "command": "fold_go_to_import" }, 40 | { "keys": ["ctrl+shift+alt+g"], "command": "fold_go_to_quick_panel" }, 41 | 42 | { "keys": ["ctrl+shift+alt+0"], "command": "fold_fold_depth", "args": {"depth": 0} }, 43 | { "keys": ["ctrl+shift+alt+keypad0"], "command": "fold_fold_depth", "args": {"depth": 0} }, 44 | { "keys": ["ctrl+shift+alt+1"], "command": "fold_fold_depth", "args": {"depth": 1} }, 45 | { "keys": ["ctrl+shift+alt+keypad1"], "command": "fold_fold_depth", "args": {"depth": 1} }, 46 | { "keys": ["ctrl+shift+alt+2"], "command": "fold_fold_depth", "args": {"depth": 2} }, 47 | { "keys": ["ctrl+shift+alt+keypad2"], "command": "fold_fold_depth", "args": {"depth": 2} }, 48 | { "keys": ["ctrl+shift+alt+3"], "command": "fold_fold_depth", "args": {"depth": 3} }, 49 | { "keys": ["ctrl+shift+alt+keypad3"], "command": "fold_fold_depth", "args": {"depth": 3} } 50 | 51 | 52 | ] 53 | -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["ctrl+k", "ctrl+left"], "command": "fold_fold_content" }, 3 | { "keys": ["ctrl+k", "ctrl+right"], "command": "fold_unfold_content" }, 4 | { "keys": ["ctrl+k", "ctrl+up"], "command": "fold_go_to_sibling_up" }, 5 | { "keys": ["ctrl+k", "ctrl+down"], "command": "fold_go_to_sibling_down" }, 6 | 7 | { "keys": ["ctrl+k", "ctrl+pageup"], "command": "fold_go_to_parent" }, 8 | { "keys": ["ctrl+k", "ctrl+pagedown"], "command": "fold_go_to_children" }, 9 | { "keys": ["ctrl+k", "ctrl+home"], "command": "fold_go_to_top_sibling" }, 10 | { "keys": ["ctrl+k", "ctrl+end"], "command": "fold_go_to_bottom_sibling" }, 11 | { "keys": ["ctrl+k", "ctrl+enter"], "command": "fold_enter_content" }, 12 | { "keys": ["ctrl+k", "ctrl+space"], "command": "fold_go_to_siblings" }, 13 | { "keys": ["ctrl+k", "ctrl+h"], "command": "fold_show_documentation" }, 14 | 15 | { "keys": ["ctrl+k", "ctrl+n"], "command": "fold_new_sibling" }, 16 | { "keys": ["ctrl+k", "ctrl+i"], "command": "fold_go_to_siblings_inverse" }, 17 | 18 | { "keys": ["ctrl+k", "ctrl+0"], "command": "fold_fold_depth", "args": {"depth": 0} }, 19 | { "keys": ["ctrl+k", "ctrl+1"], "command": "fold_fold_depth", "args": {"depth": 1} }, 20 | { "keys": ["ctrl+k", "ctrl+2"], "command": "fold_fold_depth", "args": {"depth": 2} }, 21 | { "keys": ["ctrl+k", "ctrl+3"], "command": "fold_fold_depth", "args": {"depth": 3} }, 22 | 23 | { "keys": ["ctrl+shift+alt+up"], "command": "fold_go_to_sibling_up" }, 24 | { "keys": ["ctrl+shift+alt+down"], "command": "fold_go_to_sibling_down" }, 25 | { "keys": ["ctrl+shift+alt+left"], "command": "fold_fold_content" }, 26 | { "keys": ["ctrl+shift+alt+right"], "command": "fold_unfold_content" }, 27 | 28 | { "keys": ["ctrl+shift+alt+pageup"], "command": "fold_go_to_parent" }, 29 | { "keys": ["ctrl+shift+alt+pagedown"], "command": "fold_go_to_children" }, 30 | { "keys": ["ctrl+shift+alt+home"], "command": "fold_go_to_top_sibling" }, 31 | { "keys": ["ctrl+shift+alt+end"], "command": "fold_go_to_bottom_sibling" }, 32 | 33 | { "keys": ["ctrl+shift+alt+space"], "command": "fold_go_to_siblings" }, 34 | { "keys": ["ctrl+shift+alt+enter"], "command": "fold_enter_content" }, 35 | 36 | { "keys": ["ctrl+shift+alt+i"], "command": "fold_go_to_siblings_inverse" }, 37 | { "keys": ["ctrl+shift+alt+n"], "command": "fold_new_sibling" }, 38 | { "keys": ["ctrl+shift+alt+h"], "command": "fold_show_documentation" }, 39 | { "keys": ["ctrl+shift+alt+i"], "command": "fold_go_to_import" }, 40 | { "keys": ["ctrl+shift+alt+g"], "command": "fold_go_to_quick_panel" }, 41 | 42 | { "keys": ["ctrl+shift+alt+0"], "command": "fold_fold_depth", "args": {"depth": 0} }, 43 | { "keys": ["ctrl+shift+alt+keypad0"], "command": "fold_fold_depth", "args": {"depth": 0} }, 44 | { "keys": ["ctrl+shift+alt+1"], "command": "fold_fold_depth", "args": {"depth": 1} }, 45 | { "keys": ["ctrl+shift+alt+keypad1"], "command": "fold_fold_depth", "args": {"depth": 1} }, 46 | { "keys": ["ctrl+shift+alt+2"], "command": "fold_fold_depth", "args": {"depth": 2} }, 47 | { "keys": ["ctrl+shift+alt+keypad2"], "command": "fold_fold_depth", "args": {"depth": 2} }, 48 | { "keys": ["ctrl+shift+alt+3"], "command": "fold_fold_depth", "args": {"depth": 3} }, 49 | { "keys": ["ctrl+shift+alt+keypad3"], "command": "fold_fold_depth", "args": {"depth": 3} } 50 | 51 | 52 | ] 53 | -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["ctrl+k", "ctrl+left"], "command": "fold_fold_content" }, 3 | { "keys": ["ctrl+k", "ctrl+right"], "command": "fold_unfold_content" }, 4 | { "keys": ["ctrl+k", "ctrl+up"], "command": "fold_go_to_sibling_up" }, 5 | { "keys": ["ctrl+k", "ctrl+down"], "command": "fold_go_to_sibling_down" }, 6 | 7 | { "keys": ["ctrl+k", "ctrl+pageup"], "command": "fold_go_to_parent" }, 8 | { "keys": ["ctrl+k", "ctrl+pagedown"], "command": "fold_go_to_children" }, 9 | { "keys": ["ctrl+k", "ctrl+home"], "command": "fold_go_to_top_sibling" }, 10 | { "keys": ["ctrl+k", "ctrl+end"], "command": "fold_go_to_bottom_sibling" }, 11 | { "keys": ["ctrl+k", "ctrl+enter"], "command": "fold_enter_content" }, 12 | { "keys": ["ctrl+k", "ctrl+space"], "command": "fold_go_to_siblings" }, 13 | { "keys": ["ctrl+k", "ctrl+h"], "command": "fold_show_documentation" }, 14 | 15 | { "keys": ["ctrl+k", "ctrl+n"], "command": "fold_new_sibling" }, 16 | { "keys": ["ctrl+k", "ctrl+i"], "command": "fold_go_to_siblings_inverse" }, 17 | 18 | { "keys": ["ctrl+k", "ctrl+0"], "command": "fold_fold_depth", "args": {"depth": 0} }, 19 | { "keys": ["ctrl+k", "ctrl+1"], "command": "fold_fold_depth", "args": {"depth": 1} }, 20 | { "keys": ["ctrl+k", "ctrl+2"], "command": "fold_fold_depth", "args": {"depth": 2} }, 21 | { "keys": ["ctrl+k", "ctrl+3"], "command": "fold_fold_depth", "args": {"depth": 3} }, 22 | 23 | { "keys": ["ctrl+shift+alt+up"], "command": "fold_go_to_sibling_up" }, 24 | { "keys": ["ctrl+shift+alt+down"], "command": "fold_go_to_sibling_down" }, 25 | { "keys": ["ctrl+shift+alt+left"], "command": "fold_fold_content" }, 26 | { "keys": ["ctrl+shift+alt+right"], "command": "fold_unfold_content" }, 27 | 28 | { "keys": ["ctrl+shift+alt+pageup"], "command": "fold_go_to_parent" }, 29 | { "keys": ["ctrl+shift+alt+pagedown"], "command": "fold_go_to_children" }, 30 | { "keys": ["ctrl+shift+alt+home"], "command": "fold_go_to_top_sibling" }, 31 | { "keys": ["ctrl+shift+alt+end"], "command": "fold_go_to_bottom_sibling" }, 32 | 33 | { "keys": ["ctrl+shift+alt+space"], "command": "fold_go_to_siblings" }, 34 | { "keys": ["ctrl+shift+alt+enter"], "command": "fold_enter_content" }, 35 | 36 | { "keys": ["ctrl+shift+alt+i"], "command": "fold_go_to_siblings_inverse" }, 37 | { "keys": ["ctrl+shift+alt+n"], "command": "fold_new_sibling" }, 38 | { "keys": ["ctrl+shift+alt+h"], "command": "fold_show_documentation" }, 39 | { "keys": ["ctrl+shift+alt+i"], "command": "fold_go_to_import" }, 40 | { "keys": ["ctrl+shift+alt+g"], "command": "fold_go_to_quick_panel" }, 41 | 42 | { "keys": ["ctrl+shift+alt+0"], "command": "fold_fold_depth", "args": {"depth": 0} }, 43 | { "keys": ["ctrl+shift+alt+keypad0"], "command": "fold_fold_depth", "args": {"depth": 0} }, 44 | { "keys": ["ctrl+shift+alt+1"], "command": "fold_fold_depth", "args": {"depth": 1} }, 45 | { "keys": ["ctrl+shift+alt+keypad1"], "command": "fold_fold_depth", "args": {"depth": 1} }, 46 | { "keys": ["ctrl+shift+alt+2"], "command": "fold_fold_depth", "args": {"depth": 2} }, 47 | { "keys": ["ctrl+shift+alt+keypad2"], "command": "fold_fold_depth", "args": {"depth": 2} }, 48 | { "keys": ["ctrl+shift+alt+3"], "command": "fold_fold_depth", "args": {"depth": 3} }, 49 | { "keys": ["ctrl+shift+alt+keypad3"], "command": "fold_fold_depth", "args": {"depth": 3} }, 50 | { "keys": ["ctrl+shift+alt+s"], "command": "fold_siblings" }, 51 | { "keys": ["ctrl+shift+alt+v"], "command": "fold_siblings_inverse" } 52 | 53 | ] 54 | -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences: Fold Python Settings", 4 | "command": "open_file", "args": 5 | { 6 | "file": "${packages}/Fold Python/FoldPython.sublime-settings"} 7 | }, 8 | { 9 | "caption": "Preferences: Fold Python Key Bindings", 10 | "command": "open_file", "args": 11 | { 12 | "file": "${packages}/Fold Python/Default (Windows).sublime-keymap", 13 | "platform": "Windows" 14 | } 15 | }, 16 | { 17 | "caption": "Preferences: Fold Python Key Bindings", 18 | "command": "open_file", "args": 19 | { 20 | "file": "${packages}/Fold Python/Default (OSX).sublime-keymap", 21 | "platform": "OSX" 22 | } 23 | }, 24 | { 25 | "caption": "Preferences: Fold Python Key Bindings", 26 | "command": "open_file", "args": 27 | { 28 | "file": "${packages}/Fold Python/Default (Linux).sublime-keymap", 29 | "platform": "Linux" 30 | } 31 | }, 32 | { 33 | "caption" : "Fold Python : go to sibling up", 34 | "command" : "fold_go_to_sibling_up" 35 | }, 36 | { 37 | "caption" : "Fold Python : go to sibling down", 38 | "command" : "fold_go_to_sibling_down" 39 | }, 40 | { 41 | "caption" : "Fold Python : fold content", 42 | "command" : "fold_fold_content" 43 | }, 44 | { 45 | "caption" : "Fold Python : unfold content", 46 | "command" : "fold_unfold_content" 47 | }, 48 | { 49 | "caption" : "Fold Python : go to parent", 50 | "command" : "fold_go_to_parent" 51 | }, 52 | { 53 | "caption" : "Fold Python : go to children", 54 | "command" : "fold_go_to_children" 55 | }, 56 | { 57 | "caption" : "Fold Python : go to top sibling", 58 | "command" : "fold_go_to_top_sibling" 59 | }, 60 | { 61 | "caption" : "Fold Python : go to bottom sibling", 62 | "command" : "fold_go_to_bottom_sibling" 63 | }, 64 | { 65 | "caption" : "Fold Python : go to siblings", 66 | "command" : "fold_go_to_siblings" 67 | }, 68 | { 69 | "caption" : "Fold Python : enter content", 70 | "command" : "fold_enter_content" 71 | }, 72 | { 73 | "caption" : "Fold Python : go to siblings inverse", 74 | "command" : "fold_go_to_siblings_inverse" 75 | }, 76 | { 77 | "caption" : "Fold Python : new sibling", 78 | "command" : "fold_new_sibling" 79 | }, 80 | { 81 | "caption" : "Fold Python : show documentation", 82 | "command" : "fold_show_documentation" 83 | }, 84 | { 85 | "caption" : "Fold Python : go to import", 86 | "command" : "fold_go_to_import" 87 | }, 88 | { 89 | "caption" : "Fold Python : go to visible...", 90 | "command" : "fold_go_to_quick_panel" 91 | }, 92 | { 93 | "caption" : "Fold Python : fold depth 0", 94 | "command" : "fold_fold_depth", 95 | "args": {"depth": 0} 96 | }, 97 | { 98 | "caption" : "Fold Python : fold depth 1", 99 | "command" : "fold_fold_depth", 100 | "args": {"depth": 1} 101 | }, 102 | { 103 | "caption" : "Fold Python : fold depth 2", 104 | "command" : "fold_fold_depth", 105 | "args": {"depth": 2} 106 | }, 107 | { 108 | "caption" : "Fold Python : fold depth 3", 109 | "command" : "fold_fold_depth", 110 | "args": {"depth": 3} 111 | } 112 | ] 113 | -------------------------------------------------------------------------------- /FoldPython.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | // Fold getters and setter as one 3 | "fold_getters_setters": true 4 | } -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "id": "preferences", 5 | "children": 6 | [ 7 | { 8 | "caption": "Package Settings", 9 | "id": "package-settings", 10 | "children": 11 | [ 12 | { 13 | "caption": "Fold Python", 14 | "children": 15 | [ 16 | { 17 | "caption": "Settings – Default", 18 | "command": "open_file", 19 | "args": { 20 | "file": "${packages}/Fold Python/FoldPython.sublime-settings" 21 | } 22 | }, 23 | { 24 | "caption": "Settings – User", 25 | "command": "open_file", 26 | "args": { 27 | "file": "${packages}/User/FoldPython.sublime-settings" 28 | } 29 | }, 30 | { "caption": "-" }, 31 | { 32 | "caption": "Key Bindings – Default", 33 | "platform": "Linux", 34 | "command": "open_file", 35 | "args": { 36 | "file": "${packages}/Fold Python/Default (Linux).sublime-keymap" 37 | } 38 | }, 39 | { 40 | "caption": "Key Bindings – Default", 41 | "platform": "Windows", 42 | "command": "open_file", 43 | "args": { 44 | "file": "${packages}/Fold Python/Default (Windows).sublime-keymap" 45 | } 46 | }, 47 | { 48 | "caption": "Key Bindings – Default", 49 | "platform": "OSX", 50 | "command": "open_file", 51 | "args": { 52 | "file": "${packages}/Fold Python/Default (OSX).sublime-keymap" 53 | } 54 | } 55 | ] 56 | } 57 | ] 58 | } 59 | ] 60 | } 61 | ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fold Python 2 | #### Intelligent Folding System for Python 3 | 4 | ![alt tag](https://dl.dropboxusercontent.com/u/1652825/code/sublime/foldpython/foldpython_basics.gif) 5 | 6 | ## Intro 7 | You can fold, navigate, extend python code in a very fast and easy way. 8 | instant fold all methods, leaving docstrings visible, extending your current code. 9 | 10 | ## Features 11 | * Folding code, fold and unfold contents where the cursor exists 12 | * Smart selecting, selecting needed pieces of code 13 | * Smart folding getters and setters, getters and setters will be folded as one 14 | * Easy navigation trough code structure : Go upwards in code blocks, go inside children 15 | * Documentation folding, folding all python code except documentation strings 16 | * Extending code, creating new siblings putting keywords correct so Sublime autocomplete can take over the rest 17 | 18 | ## Installation 19 | * Use [Sublime Package Control](http://wbond.net/sublime_packages/package_control "Sublime Package Control") 20 | * `ctrl+shft+p` then select `Package Control: Install Package` 21 | * install `Fold Python` 22 | 23 | Alternatively, download the package from [GitHub](https://github.com/svenfraeys/SublimeFoldPython "SublimeFoldPython") into your `Packages` folder 24 | 25 | ## Key Bindings 26 | Fold Python is only accesible and useful when used trough shortcuts. 27 | 28 | All key bindings are using following pattern `Ctrl+Alt+Shift+Key` 29 | OR 30 | Key binding are now also connected with `Ctrl+K, Ctrl+Key` to improve usability 31 | 32 | * `Ctrl+Alt+Shift+Up` : Move up in code / Go to parent 33 | * `Ctrl+Alt+Shift+Down` : Move down in code / Go to adult 34 | * `Ctrl+Alt+Shift+Left` : Fold Code / Go to Parent 35 | * `Ctrl+Alt+Shift+Right` : Unfold Code / Go to Child 36 | * `Ctrl+Alt+Shift+PageUp` : Go to First Sibling / Go to Parent 37 | * `Ctrl+Alt+Shift+PageDown` : Go to Last Sibling / Go to next Adult 38 | * `Ctrl+Alt+Shift+Home` : Go to parent 39 | * `Ctrl+Alt+Shift+End` : Go to all children 40 | * `Ctrl+Alt+Shift+Space` : Select all siblings 41 | * `Ctrl+Alt+Shift+H` : Help mode, Fold content but not docstrings 42 | * `Ctrl+Alt+Shift+I` : Invert selection, Select all other siblings 43 | * `Ctrl+Alt+Shift+0` : Fold to depth 0 starting from selection 44 | * `Ctrl+Alt+Shift+1` : Fold to depth 1 starting from selection 45 | * `Ctrl+Alt+Shift+2` : Fold to depth 2 starting from selection 46 | * `Ctrl+Alt+Shift+N` : Create a new sibling starting from selection 47 | * `Ctrl+Alt+Shift+I` : Go to import section of code 48 | * `Ctrl+Alt+Shift+G` : Show a list of all items in visible region. This way you can easily jump to a section in your view 49 | * `Ctrl+Alt+Shift+S` : Collapse all siblings including current cursors 50 | * `Ctrl+Alt+Shift+V` : Collapse all siblings not including current cursors 51 | 52 | ## Commands 53 | A list of commands are added to access using `Ctrl+Shift+P`. 54 | all commands start with "Fold Python : command name" 55 | 56 | ## What's new? 57 | 58 | 21 july 2014 59 | 60 | * added shortcut 61 | * bug fixing 62 | * added fold python commands in `Ctrl+Shift+P` 63 | 64 | 26 march 2014 65 | 66 | * Go to import command created 67 | * List all items in visible region for fast navigation 68 | 69 | 25 march 2014 70 | 71 | * Folding Getters and Setters as one 72 | * Create new sibling will apply an autocomplete command 73 | 74 | ## Settings 75 | you can edit Key Binding and Settings in `Preferences > Package Settings > Fold Python` 76 | 77 | * fold_getters_setters : fold getter and matching setter together as one 78 | 79 | 80 | ## Contributors 81 | People that helped me to improve this addon ! 82 | * duqcyxwd 83 | 84 | ## Todo 85 | * change shortcuts to a more usable shortcut list 86 | -------------------------------------------------------------------------------- /SublimeFold.py: -------------------------------------------------------------------------------- 1 | ############ 2 | # 3 | # SublimeFold 4 | # 5 | # Intelligent Folding System for Python 6 | # 7 | # author : sven.fr 8 | # 9 | ############ 10 | import sublime 11 | import sublime_plugin 12 | import sys 13 | 14 | from .CodeManipulator import * 15 | # from .CodeManipulator import * 16 | VERBOSE = 0 17 | 18 | def log(message,verbose=1): 19 | '''print a message with verbose limit 20 | ''' 21 | if verbose <= VERBOSE: 22 | print('%s:%s' % (verbose, message) ) 23 | 24 | def fold_getters_setters(): 25 | '''return if the fold getters and setters is active or not 26 | ''' 27 | settings = sublime.load_settings("FoldPython.sublime-settings") 28 | return settings.get('fold_getters_setters') 29 | 30 | 31 | # sublime commands 32 | class FLineTextCommand(sublime_plugin.TextCommand): 33 | '''text command shared functionality 34 | ''' 35 | def selectRegions(self, regions): 36 | '''select the regions 37 | ''' 38 | view = self.view 39 | sel = view.sel() 40 | 41 | sel.clear() 42 | for region in regions: 43 | sel.add(region) 44 | 45 | if len(regions) > 0: 46 | view.show(regions[0]) 47 | 48 | class FoldShowDocumentationCommand(FLineTextCommand): 49 | '''show all doc strings of selected lines 50 | ''' 51 | def run(self, edit): 52 | log('FoldShowDocumentation',1) 53 | view = self.view 54 | sel = view.sel() 55 | regions = [] 56 | for region in ( view.sel()): 57 | line = FLine(view, region) 58 | documnentationRegion = line.documentationRegion() 59 | 60 | if documnentationRegion: 61 | contentRegion = line.contentRegion() 62 | contentNoDocumentation = sublime.Region(documnentationRegion.b , contentRegion.b ) 63 | regions.append( contentNoDocumentation ) 64 | 65 | hasFolded = view.fold(contentNoDocumentation) 66 | 67 | if not hasFolded: 68 | view.unfold(contentRegion) 69 | view.fold(contentNoDocumentation) 70 | else: 71 | contentRegion = line.contentRegion() 72 | view.fold(contentRegion) 73 | 74 | class FoldDeleteDoubleEmptyLinesCommand(FLineTextCommand): 75 | '''show all doc strings of selected lines 76 | Still need to finish this 77 | ''' 78 | def run(self, edit): 79 | log('FoldDeleteDoubleEmptyLines',1) 80 | view = self.view 81 | sel = view.sel() 82 | 83 | loop = True 84 | while loop: 85 | emptyFound = 0 86 | lines = FLineUtils(view).lines() 87 | for line in lines: 88 | lineIsEmpty = line.isEmpty() 89 | if lineIsEmpty: 90 | emptyFound += 1 91 | 92 | class FoldGoToSiblingUpCommand(FLineTextCommand): 93 | '''go one sibling up, if no sibling go to parent 94 | ''' 95 | def run(self, edit): 96 | log('FoldGoToSiblingUpCommand',1) 97 | view = self.view 98 | sel = view.sel() 99 | regions = [] 100 | for region in ( view.sel()): 101 | line = FLine(view, region) 102 | 103 | siblingUp = line.siblingUp() 104 | 105 | if siblingUp is None: 106 | siblingUp = line.parent() 107 | 108 | log(siblingUp,1) 109 | 110 | if siblingUp: 111 | siblingUpGoToRegion = siblingUp.goToRegion() 112 | regions.append(siblingUpGoToRegion) 113 | else: 114 | # go back to original 115 | regions.append(region) 116 | 117 | if len(regions) > 0: 118 | self.selectRegions(regions) 119 | 120 | class FoldGoToSiblingDownCommand(FLineTextCommand): 121 | '''go one sibling down, if no sibling go to adult 122 | ''' 123 | def run(self, edit): 124 | log('FoldGoToSiblingDownCommand',1) 125 | view = self.view 126 | sel = view.sel() 127 | regions = [] 128 | for region in ( view.sel()): 129 | line = FLine(view, region) 130 | siblingDown = line.siblingDown() 131 | 132 | if siblingDown is None: 133 | siblingDown = line.adultDown() 134 | 135 | log(siblingDown,1) 136 | 137 | if siblingDown: 138 | siblingDownGoToRegion = siblingDown.goToRegion() 139 | regions.append(siblingDownGoToRegion) 140 | else: 141 | # go back to original 142 | regions.append(region) 143 | 144 | if len(regions) > 0: 145 | self.selectRegions(regions) 146 | 147 | class FoldGoToSiblingsInverseCommand(FLineTextCommand): 148 | '''select all the invert siblings 149 | ''' 150 | def run(self, edit): 151 | log('FoldGoToSiblingsInverseCommand',1) 152 | view = self.view 153 | sel = view.sel() 154 | regions = [] 155 | 156 | # loop regions 157 | selectRegions = view.sel() 158 | for region in selectRegions: 159 | line = FLine(view, region) 160 | 161 | siblings = line.siblings() 162 | 163 | log(siblings,1) 164 | if len(siblings) > 0: 165 | # add each region of the siblign 166 | for sibling in siblings: 167 | siblingGoToRegion = sibling.goToRegion() 168 | add = True 169 | 170 | for region in selectRegions: 171 | if region == siblingGoToRegion: 172 | add = False 173 | 174 | if add: 175 | regions.append( siblingGoToRegion ) 176 | 177 | # apply selection 178 | if len(regions) > 0: 179 | self.selectRegions(regions) 180 | 181 | class FoldGoToSiblingsCommand(FLineTextCommand): 182 | '''select all siblings and itself 183 | ''' 184 | def run(self, edit): 185 | log('FoldGoToParent',1) 186 | view = self.view 187 | sel = view.sel() 188 | regions = [] 189 | 190 | # loop regions 191 | for region in ( view.sel()): 192 | line = FLine(view, region) 193 | 194 | siblings = line.siblings() 195 | 196 | if len(siblings) > 0: 197 | sublime.status_message(str(len(siblings))) 198 | sys.stderr.write("len(siblings): " + str(len(siblings))) 199 | # add each region of the siblign 200 | for sibling in siblings: 201 | regions.append( sibling.goToRegion() ) 202 | 203 | # if the current has childs also add it 204 | if line.hasChildren(): 205 | regions.append(line.goToRegion() ) 206 | 207 | # apply selection 208 | if len(regions) > 0: 209 | self.selectRegions(regions) 210 | 211 | class FoldSiblingsInverseCommand(FLineTextCommand): 212 | '''select all the invert siblings 213 | ''' 214 | def run(self, edit): 215 | log('FoldGoToSiblingsInverseCommand',1) 216 | view = self.view 217 | sel = view.sel() 218 | regions = [] 219 | 220 | # loop regions 221 | selectRegions = view.sel() 222 | for region in selectRegions: 223 | line = FLine(view, region) 224 | siblings = line.siblings() 225 | 226 | if len(siblings) > 0: 227 | # add each region of the siblign 228 | for sibling in siblings: 229 | siblingGoToRegion = sibling.goToRegion() 230 | add = True 231 | for region in selectRegions: 232 | # todo : how to identify lines 233 | # lineRegion = view.line( line.region() ) 234 | 235 | if region == siblingGoToRegion: 236 | add = False 237 | if add: 238 | regions.append( siblingGoToRegion ) 239 | else: 240 | sys.stderr.write("No siblings, level up\n") 241 | parentLine = line.parent() 242 | if parentLine: 243 | for sibling in parentLine.siblings(): 244 | regions.append(sibling.goToRegion()) 245 | 246 | # start folding 247 | blackListRegions = [] # all regions that do not need actions anymore 248 | for region in (regions): 249 | line = FLine(view, region) 250 | 251 | # go for parent if active line does not have children 252 | if not line.hasChildren(): 253 | line = line.parent() 254 | if line is None: 255 | continue 256 | # get full region of line 257 | lineRegion = view.line( line.region() ) 258 | line = FLine(view, lineRegion ) 259 | 260 | if lineRegion in blackListRegions: 261 | continue 262 | 263 | # getter setter folding 264 | pythonLine = FPythonLine() 265 | pythonLine.setData(line.data() ) 266 | setterDown = pythonLine.setterDown() 267 | getterUp = pythonLine.getterUp() 268 | 269 | if setterDown and fold_getters_setters(): 270 | # if it has a setter down 271 | blackListRegions.append( setterDown.region() ) 272 | contentRegions = pythonLine.foldGetterSetterRegions() 273 | elif getterUp and fold_getters_setters(): 274 | # if it has a getter up 275 | getterUpPythonLine = FPythonLine() 276 | getterUpPythonLine.setData(getterUp.data() ) 277 | blackListRegions.append( getterUp.region() ) 278 | contentRegions = getterUpPythonLine.foldGetterSetterRegions() 279 | 280 | # getter will take over the final result 281 | line = getterUpPythonLine 282 | else: 283 | # default content region 284 | contentRegions = [line.contentRegion()] 285 | 286 | if contentRegions: 287 | totalAllreadyFolded = True 288 | 289 | for contentRegion in contentRegions: 290 | hasFolded = view.fold(contentRegion) 291 | if hasFolded: 292 | totalAllreadyFolded = False 293 | 294 | class FoldSiblingsCommand(FLineTextCommand): 295 | '''select all siblings and itself 296 | ''' 297 | def run(self, edit): 298 | log('FoldGoToParent',1) 299 | view = self.view 300 | sel = view.sel() 301 | regions = [] 302 | 303 | for region in ( view.sel()): 304 | line = FLine(view, region) 305 | siblings = line.siblings() 306 | 307 | if len(siblings) > 0: 308 | sublime.status_message(str(len(siblings))) 309 | sys.stderr.write("len(siblings): " + str(len(siblings))) 310 | # add each region of the siblign 311 | for sibling in siblings: 312 | regions.append( sibling.goToRegion() ) 313 | 314 | # if the current has childs also add it 315 | if line.hasChildren(): 316 | regions.append(line.goToRegion()) 317 | 318 | if len(siblings) == 0 and not line.hasChildren(): 319 | sys.stderr.write("No siblings, level up\n") 320 | parentLine = line.parent() 321 | if parentLine: 322 | for sibling in parentLine.siblings(): 323 | regions.append(sibling.goToRegion()) 324 | if parentLine.hasChildren(): 325 | regions.append(line.goToRegion()) 326 | 327 | # start folding 328 | blackListRegions = [] # all regions that do not need actions anymore 329 | for region in (regions): 330 | line = FLine(view, region) 331 | 332 | # go for parent if active line does not have children 333 | if not line.hasChildren(): 334 | line = line.parent() 335 | if line is None: 336 | continue 337 | # get full region of line 338 | lineRegion = view.line( line.region() ) 339 | line = FLine(view, lineRegion ) 340 | 341 | if lineRegion in blackListRegions: 342 | continue 343 | 344 | # getter setter folding 345 | pythonLine = FPythonLine() 346 | pythonLine.setData(line.data() ) 347 | setterDown = pythonLine.setterDown() 348 | getterUp = pythonLine.getterUp() 349 | 350 | if setterDown and fold_getters_setters(): 351 | # if it has a setter down 352 | blackListRegions.append( setterDown.region() ) 353 | contentRegions = pythonLine.foldGetterSetterRegions() 354 | elif getterUp and fold_getters_setters(): 355 | # if it has a getter up 356 | getterUpPythonLine = FPythonLine() 357 | getterUpPythonLine.setData(getterUp.data() ) 358 | blackListRegions.append( getterUp.region() ) 359 | contentRegions = getterUpPythonLine.foldGetterSetterRegions() 360 | 361 | # getter will take over the final result 362 | line = getterUpPythonLine 363 | else: 364 | # default content region 365 | contentRegions = [line.contentRegion()] 366 | 367 | if contentRegions: 368 | totalAllreadyFolded = True 369 | 370 | for contentRegion in contentRegions: 371 | hasFolded = view.fold(contentRegion) 372 | if hasFolded: 373 | totalAllreadyFolded = False 374 | 375 | class FoldGoToParent(FLineTextCommand): 376 | '''select the parent parent 377 | ''' 378 | def run(self, edit): 379 | log('FoldGoToParent',1) 380 | view = self.view 381 | sel = view.sel() 382 | regions = [] 383 | for region in ( view.sel()): 384 | line = FLine(view, region) 385 | 386 | parent = line.parent() 387 | 388 | if parent: 389 | parentGoToRegion = parent.goToRegion() 390 | regions.append(parentGoToRegion) 391 | else: 392 | # go back to original 393 | regions.append(region) 394 | 395 | if len(regions) > 0: 396 | self.selectRegions(regions) 397 | 398 | class FoldNewSibling(FLineTextCommand): 399 | '''create a new sibling 400 | ''' 401 | def run(self, edit): 402 | log('FoldNewSibling',1) 403 | view = self.view 404 | sel = view.sel() 405 | regions = [] 406 | for region in ( view.sel() ): 407 | line = FLine(view, region) 408 | 409 | if not line.hasChildren(): 410 | line = line.parent() 411 | 412 | if line == None: 413 | continue 414 | 415 | region = line.region() 416 | lineRegion = view.line(region) 417 | lineString = view.substr( lineRegion ) 418 | typeToCreate = lineString.strip().split(' ')[0] 419 | 420 | 421 | 422 | if line is None: 423 | continue 424 | 425 | depth = line.depth() 426 | line 427 | tabString = line.tabString() 428 | contentRegion = line.contentRegion() 429 | # region = sublime.Region( contentRegion.b, contentRegion.b ) 430 | # regions.append(region) 431 | # point = sublime.Point(contentRegion.b) 432 | point = contentRegion.b 433 | 434 | insertString = '\n\n' + tabString * depth + typeToCreate 435 | view.insert(edit, point, insertString) 436 | 437 | endInsert = point + len(insertString) 438 | 439 | region = sublime.Region(endInsert, endInsert) 440 | regions.append(region) 441 | 442 | if len(regions) > 0: 443 | self.selectRegions(regions) 444 | # launch auto complete 445 | view.run_command("auto_complete") 446 | 447 | class FoldGoToTopSibling(FLineTextCommand): 448 | '''go to the top sibling 449 | ''' 450 | def run(self, edit): 451 | log('FoldGoToTopSibling',1) 452 | view = self.view 453 | sel = view.sel() 454 | regions = [] 455 | for region in ( view.sel()): 456 | line = FLine(view, region) 457 | 458 | siblings = line.siblingsUp() 459 | topSibling = None 460 | if len(siblings) > 0: 461 | topSibling = siblings[-1] 462 | 463 | if topSibling is None: 464 | topSibling = line.parent() 465 | 466 | if topSibling: 467 | siblingGoToRegion = topSibling.goToRegion() 468 | regions.append(siblingGoToRegion) 469 | else: 470 | # go back to original 471 | regions.append(region) 472 | 473 | if len(regions) > 0: 474 | self.selectRegions(regions) 475 | 476 | class FoldGoToBottomSibling(FLineTextCommand): 477 | '''go to the bottom sibling 478 | ''' 479 | def run(self, edit): 480 | log('FoldGoToTopSibling',1) 481 | view = self.view 482 | sel = view.sel() 483 | regions = [] 484 | for region in ( view.sel()): 485 | line = FLine(view, region) 486 | 487 | siblings = line.siblingsDown() 488 | sibling = None 489 | if len(siblings) > 0: 490 | sibling = siblings[-1] 491 | 492 | # no sibling go to next adult 493 | if sibling is None: 494 | sibling = line.adultDown() 495 | 496 | if sibling: 497 | siblingGoToRegion = sibling.goToRegion() 498 | regions.append(siblingGoToRegion) 499 | else: 500 | # go back to original 501 | regions.append(region) 502 | 503 | if len(regions) > 0: 504 | self.selectRegions(regions) 505 | 506 | class FoldFoldContent(FLineTextCommand): 507 | '''fold the content 508 | ''' 509 | def run(self, edit): 510 | log('FoldFoldContent',1) 511 | view = self.view 512 | sel = view.sel() 513 | 514 | regions = [] 515 | blackListRegions = [] # all regions that do not need actions anymore 516 | for region in ( view.sel()): 517 | line = FLine(view, region) 518 | 519 | # go for parent if active line does not have children 520 | if not line.hasChildren(): 521 | line = line.parent() 522 | 523 | 524 | if line is None: 525 | continue 526 | 527 | # get full region of line 528 | lineRegion = view.line( line.region() ) 529 | line = FLine(view, lineRegion ) 530 | 531 | if lineRegion in blackListRegions: 532 | continue 533 | 534 | # getter setter folding 535 | pythonLine = FPythonLine() 536 | pythonLine.setData(line.data() ) 537 | setterDown = pythonLine.setterDown() 538 | getterUp = pythonLine.getterUp() 539 | 540 | if setterDown and fold_getters_setters(): 541 | # if it has a setter down 542 | blackListRegions.append( setterDown.region() ) 543 | contentRegions = pythonLine.foldGetterSetterRegions() 544 | elif getterUp and fold_getters_setters(): 545 | # if it has a getter up 546 | getterUpPythonLine = FPythonLine() 547 | getterUpPythonLine.setData(getterUp.data() ) 548 | blackListRegions.append( getterUp.region() ) 549 | contentRegions = getterUpPythonLine.foldGetterSetterRegions() 550 | 551 | # getter will take over the final result 552 | line = getterUpPythonLine 553 | else: 554 | # default content region 555 | contentRegions = [line.contentRegion()] 556 | 557 | if contentRegions: 558 | totalAllreadyFolded = True 559 | 560 | for contentRegion in contentRegions: 561 | hasFolded = view.fold(contentRegion) 562 | if hasFolded: 563 | totalAllreadyFolded = False 564 | 565 | 566 | # if can not fold, go to parent 567 | if totalAllreadyFolded: 568 | parentLine = line.parent() 569 | if parentLine: 570 | line = parentLine 571 | 572 | if line: 573 | regions.append( line.goToRegion() ) 574 | 575 | 576 | if len(regions) > 0: 577 | self.selectRegions(regions) 578 | 579 | class FoldFoldDepth(FLineTextCommand): 580 | '''show everything exept the given depth 581 | ''' 582 | def run(self, edit, depth = 0): 583 | '''run 584 | ''' 585 | log('FoldFoldDepth',1) 586 | 587 | view = self.view 588 | sel = view.sel() 589 | foldRegions = [] 590 | regions = [] 591 | linesToFold = [] 592 | linesToUnFold = [] # the root contents we will unfold 593 | 594 | # collect al lines to fold and unfold 595 | for region in ( view.sel()): 596 | line = FLine(view, region) 597 | 598 | # go for parent if active line does not have children 599 | 600 | if not line.hasChildren(): 601 | line = line.parent() 602 | 603 | if line is None: 604 | continue 605 | 606 | linesToUnFold.append(line) 607 | 608 | linesForChildren = [line] # the lines that we will have to fold 609 | for i in range(depth): 610 | linesForChildrenLoop = [] 611 | for lineForChildren in linesForChildren: 612 | lineChilds = lineForChildren.children() 613 | linesForChildrenLoop += lineChilds 614 | linesForChildren = linesForChildrenLoop 615 | 616 | linesToFold += linesForChildren 617 | 618 | if depth != 0: 619 | for line in linesToUnFold: 620 | contentRegion = line.contentRegion() 621 | 622 | if contentRegion: 623 | pass 624 | view.unfold(contentRegion) 625 | 626 | log('linesToFold=%s' % linesToFold, 4) 627 | for line in linesToFold: 628 | contentRegion = line.contentRegion() 629 | 630 | if contentRegion: 631 | foldRegions.append(contentRegion) 632 | # hasFolded = view.fold(contentRegion) 633 | log('foldRegions=%s' % foldRegions, 4) 634 | view.fold(foldRegions) 635 | # self.selectRegions(regions) 636 | 637 | class FoldEnterContentCommand(FLineTextCommand): 638 | '''start editing in the content 639 | ''' 640 | def run(self, edit): 641 | log('FoldEnterContentCommand',1) 642 | view = self.view 643 | sel = view.sel() 644 | regions = [] 645 | 646 | for region in ( view.sel()): 647 | line = FLine(view, region) 648 | if not line.hasChildren(): 649 | line = line.parent() 650 | contentRegion = line.contentRegion() 651 | if contentRegion: 652 | view.unfold(contentRegion) 653 | regions.append(sublime.Region(contentRegion.b , contentRegion.b ) ) 654 | 655 | if len(regions) > 0: 656 | self.selectRegions(regions) 657 | 658 | class FoldUnfoldContent(FLineTextCommand): 659 | '''unfold the content of selected regions 660 | ''' 661 | def run(self, edit): 662 | log('FoldUnfoldContent',1) 663 | view = self.view 664 | sel = view.sel() 665 | foldRegions = [] 666 | lines = [] 667 | extraRegionsToSelect = [] 668 | 669 | for region in ( view.sel()): 670 | line = FLine(view, region) 671 | lines.append(line) 672 | 673 | # getter setter folding 674 | pythonLine = FPythonLine() 675 | 676 | pythonLine.setData(line.data() ) 677 | contentRegions = [] 678 | 679 | # get full region of line 680 | pythonLine = FPythonLine(view, view.line( region ) ) 681 | 682 | setterDown = pythonLine.setterDown() 683 | getterUp = pythonLine.getterUp() 684 | if setterDown and fold_getters_setters(): 685 | contentRegions = pythonLine.foldGetterSetterRegions() 686 | # extraRegionsToSelect.append(setterDown.goToRegion() ) 687 | elif getterUp and fold_getters_setters(): 688 | getterUpPythonLine = FPythonLine(view, getterUp.region() ) 689 | contentRegions = getterUpPythonLine.foldGetterSetterRegions() 690 | else: 691 | contentRegions = [line.contentRegion()] 692 | if contentRegions: 693 | foldRegions += contentRegions 694 | 695 | hasUnfolded = view.unfold(foldRegions) 696 | 697 | # nothing to unfold, go inside the first child 698 | 699 | if not hasUnfolded: 700 | linesToGoTo = [] 701 | for line in lines: 702 | childs = line.children() 703 | # add first child 704 | if len(childs) > 0: 705 | for child in childs: 706 | if len(child.children()) > 0: 707 | linesToGoTo.append(child) 708 | break 709 | 710 | if len(linesToGoTo) > 0: 711 | goToRegions = [] 712 | for line in linesToGoTo: 713 | goToRegion = line.goToRegion() 714 | goToRegions.append(goToRegion) 715 | 716 | sel.clear() 717 | 718 | for region in goToRegions: 719 | sel.add(region) 720 | else: 721 | if len(extraRegionsToSelect) > 0: 722 | view.sel().add_all(extraRegionsToSelect) 723 | 724 | class FoldGoToChildren(FLineTextCommand): 725 | '''selet all children of selected regions 726 | ''' 727 | def run(self, edit): 728 | log('FoldGoToChildren',1) 729 | view = self.view 730 | sel = view.sel() 731 | regions = [] 732 | totalChildren = 0 733 | originalRegions = [] 734 | 735 | for region in ( view.sel()): 736 | line = FLine(view, region) 737 | 738 | children = line.children() 739 | 740 | for child in children: 741 | if not child.hasChildren(): 742 | continue 743 | childGoToRegion = child.goToRegion() 744 | regions.append(childGoToRegion) 745 | totalChildren += len(children) 746 | 747 | if not line.hasChildren(): 748 | # go back to original 749 | originalRegions.append(region) 750 | 751 | if totalChildren > 0: 752 | sel.clear() 753 | for region in regions: 754 | sel.add(region) 755 | 756 | if len(regions) > 0: 757 | view.show(regions[0]) 758 | else: 759 | if len(originalRegions) > 0: 760 | sel.clear() 761 | 762 | for region in originalRegions: 763 | sel.add(region) 764 | 765 | if len(regions) > 0: 766 | view.show(originalRegions[0]) 767 | 768 | class FoldSelectZeroParentsCommand(FLineTextCommand): 769 | '''select all parents on 0 depth 770 | ''' 771 | def run(self, edit): 772 | log('FoldSelectZeroParents',1) 773 | view = self.view 774 | sel = view.sel() 775 | lineDown = FLine( view, sublime.Region(0,0) ) 776 | loop = True 777 | toSelect = [] 778 | while loop: 779 | if lineDown is None: 780 | loop = False 781 | break 782 | 783 | if not lineDown.isEmpty(): 784 | if lineDown.depth() == 0: 785 | if lineDown.hasChildren(): 786 | toSelect.append(lineDown) 787 | 788 | lineDown = lineDown.lineDown() 789 | 790 | if len(toSelect) > 0: 791 | regions = [] 792 | for lineDown in toSelect: 793 | startRegion = lineDown.goToRegion() 794 | regions.append(startRegion) 795 | 796 | sel.clear() 797 | for region in regions: 798 | sel.add(region) 799 | 800 | if len(regions) > 0: 801 | view.show(regions[0]) 802 | 803 | class FoldGoToImport(FLineTextCommand): 804 | '''go to import section 805 | ''' 806 | def run(self, edit): 807 | view = self.view 808 | sel = view.sel() 809 | lineDown = FLine( view, sublime.Region(0,0) ) 810 | loop = True 811 | toSelect = [] 812 | while loop: 813 | if lineDown is None: 814 | loop = False 815 | break 816 | 817 | lineDown = lineDown.lineDown() 818 | 819 | if lineDown == None: 820 | break 821 | 822 | if lineDown.lineString().find("import ") != -1: 823 | startRegion = lineDown.goToRegion() 824 | self.selectRegions([startRegion]) 825 | break 826 | 827 | class FoldGoToQuickPanel(FLineTextCommand): 828 | '''show a quick panel 829 | ''' 830 | visibleParents = [] 831 | def handleSelect(self, index): 832 | log('index=%s' % index, 6) 833 | 834 | if index == -1: 835 | return 836 | 837 | 838 | selectedLine = self.visibleParents[index] 839 | 840 | self.selectRegions( [selectedLine.goToRegion()] ) 841 | 842 | 843 | def run(self, edit): 844 | view = self.view 845 | visibleRegion = view.visible_region() 846 | log('visibleRegion=%s' % visibleRegion, 6) 847 | line = view.line(visibleRegion.a) 848 | 849 | # firstLineRegion = sublime.Region(line) 850 | # log('firstLineRegion=%s' % firstLineRegion, 6) 851 | 852 | lineDown = FLine( view, line ) 853 | 854 | loop = True 855 | toSelect = [] 856 | 857 | visibleParentLines = [] 858 | while loop: 859 | if lineDown is None: 860 | loop = False 861 | break 862 | 863 | if not visibleRegion.contains( lineDown.region() ): 864 | loop = False 865 | break 866 | 867 | if len(lineDown.children()) > 0 and not lineDown.isEmpty(): 868 | log(lineDown.lineString(),3) 869 | visibleParentLines.append(lineDown) 870 | 871 | lineDown = lineDown.lineDown() 872 | 873 | optionList = [line.lineString() for line in visibleParentLines] 874 | self.visibleParents = visibleParentLines 875 | sublime.active_window().show_quick_panel(optionList, self.handleSelect) 876 | 877 | class PythonlineCommand(FLineTextCommand): 878 | '''test command 879 | ''' 880 | def run(self, edit): 881 | view = self.view 882 | 883 | # return 884 | # for attr in dir(view): log('view.%s' % (attr) , 6) 885 | 886 | for region in ( view.sel()): 887 | line = FLine(view, region) 888 | lineD = line.children() 889 | print( len(lineD) ) 890 | 891 | # for child in line.children(): 892 | # print(child) 893 | 894 | 895 | # sublime.active_window().active_view().run_command(cmd='Fold_go_to_sibling_down') 896 | # sublime.log_commands(True) 897 | # path = '/home/sven.fr' 898 | # sublime.active_window().run_command('prompt_add_folder', {"dirs" : [path] } ) 899 | 900 | # view = sublime.active_window().active_view() 901 | --------------------------------------------------------------------------------