in Sublime Text
코드를 분석할 때 관심이 없는 코드 덩어리를 작게 접어 놓으면 편할 때가 많이 있습니다. 하지만 코드를 접었다면 함수로 빼야 된다는 신호이기도 합니다. 그래도 기존에 작성된 거대한 코드를 분석하거나, 많은 변수를 매핑해야 되는 리포팅을 작성할 때 등등 여러 가지 상황에서 코드 접기(Code Folding)는 여전히 유용한 에디터의 기능 중 하나입니다.
Sublime Text 코드 접기는 설명이나 설정이 필요 없을 만큼 잘 만들어져 있습니다. 아래와 같이 라인수를 표시하는 숫자 근처에 가면 역삼각형 모양이 나타나며 삼각형을 클릭하면 접었다 폈다 할 수 있습니다.
메뉴에서는 Edit -> Code Folding를 선택하여 사용할 수 있으며, 잘 정의된 단축키까지 확인할 수 있습니다.
폴딩에 관한 몇 가지 설정이 있지만, 궁금하신 분들은 Sublime의 모든 기본 설정이 정의되어 있는 Default.sublime-package 안에 Preferences.sublime-settings에서 fold_ 로 직접 검색해 보시길 바랍니다.
아래 내용은 파이썬을 어느 정도 알고 있다는 가정하에 작성된 글입니다. 그리고 Code folding이 어떻게 동작하는지 탐험하는 글입니다.
이제부터 편의상 Sublime Text는 Sublime, 코드 접기는 폴딩이라고 부르겠습니다.
탐험을 하게 된 이유
예전에 폴딩 기능을 사용했지만, 최근에는 사용한 적이 없습니다. 오늘 이 글을 적고 있는 이유는 페이스북 Sublime Text Korean User에 올라온 질문에 답변하려고 살펴본 내용을 정리한 탐험기입니다.
탐험 시작
탐험은 Ctlr+`를 누르면 나타나는 콘솔창에서 시작합니다. 콘솔창에 sublime.log_commands(True)을 입력하고 Edit -> Code Folding -> Fold를 눌러봅시다.
>>> sublime.log_commands(True)
command: fold
화면에는 위와 같이 나타납니다. log_commands는 sublime에 입력되는 모든 명령어를 콘솔창에 표시하는 명령어로 오류를 찾거나, 탐험을 할 때 유용한 길잡이 역할을 합니다. fold명령어는 단순히 명령어만 나왔지만 마우스로 이리저리 클릭하거나 여러 가지 동작을 해보면 log_commands의 기능을 확인할 수 있습니다.
sublime에서 명령은 2가지로 구분됩니다. native로 구현된 명령과 파이썬으로 작성된 명령입니다. native로 구현된 명령은 sublime.exe에서 직접 검색하거나 sublime.py에서 어느 정도 확인 가능하며 파이썬으로 구현된 것은 명령어 뒤에 Command가 붙은 클래스로 .py 파일에 작성되어 있습니다. fold명령은 native로 검색이 안되므로 어딘가에 FoldCommand 클래스가 존재할 것 같습니다.
파이썬로 구현된 모든 명령어는 위와 같이 첫 문자가 대문자로 시작하는 파스칼 표기법으로 되어있고 뒤에는 Command가 붙습니다. pluging 작성 시에도 동일합니다. 그런데 sublime에서 호출할 때는 일관성 없게 밑줄 표기법을 사용합니다.
파이썬으로 작성 시 : class GotoLineCommand
메뉴 등에서 호출시 : goto_line
http://code.tutsplus.com/tutorials/how-to-create-a-sublime-text-2-plugin--net-22685
Step 2 - Command Types and Naming 참고
fold.py
Default.sublime-package파일을 압축을 풀어보면 fold.py라는 파일이 나옵니다. 그 안에 FoldCommand class가 정의되어 있습니다. 이름만 봐도 어떤 기능인지 예상되는 class들입니다.
class FoldUnfoldCommand(sublime_plugin.TextCommand):
class FoldAllCommand(sublime_plugin.TextCommand):
class FoldByLevelCommand(sublime_plugin.TextCommand):
class UnfoldCommand(sublime_plugin.TextCommand):
class UnfoldAllCommand(sublime_plugin.TextCommand):
우리가 찾는 명령어는 Fold이므로 FoldCommand class를 살펴봅시다. 시작은 아래와 같이 시작합니다.
for s in self.view.sel():
sublime의 많은 파이썬 코드들은 멀티 커서의 지원을 위해 위와 같은 패턴으로 시작합니다. view.sel()은 커서의 위치 또는 선택를 나타내는 배열의 반복자를 반환하는 함수로 s에는 커서의 위치가 하나씩 전달됩니다.
self.view.sel()의 동작을 이해하기 위해 sublime에서 커서를 Line 1, Column 1 위치에 놓고 콘솔에서 아래와 같이 명령을 입력해보세요.
( 이제는 로그가 나타나면 불편하므로 sublime.log_commands(False)로 하시는 것이 편합니다. )
>>> view.sel()[0]
(0, 0)
view.sel()[0]은 첫 번째 커서의 위치를 (a, b)와 같은 튜플 포맷으로 나타냅니다. 현재 위치에서 shift키를 눌러 3칸을 선택했다면 (0, 3)과 같이 나타납니다. 그리고 멀티 커서로 동작중이라면 멀티 커서 개수만큼 [0] 부분을 변경하여 접근이 가능합니다.
view.sel() 안에 들어있는 것을 더 깊이 탐험해 볼까요.
>>> type(view.sel()[0])
<class 'sublime.Region'>
>>> dir(view.sel()[0])
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'a', 'b', 'begin', 'contains', 'cover', 'empty', 'end', 'intersection', 'intersects', 'size', 'xpos']
파이썬에서는 type, dir로 해당 객체의 정보를 확인할 수 있습니다. view.sel()[0]은 Region객체라는 것을 알 수 있으며, sublime에서 커서 위치, 선택 연역 등 처리의 기본이 되는 클래스입니다. 그리고 위와 같이 dir로 Region의 메소드를 확인할 수 있습니다.
다시 fold.py로 돌아와서
for s in self.view.sel():
if s.empty():
r = self.view.indented_region(s.a)
if not r.empty():
r = fold_region_from_indent(self.view, r)
self.view.fold(r)
... (생략)
s.empty()는 현재 Region이 선택된 것이 없다면 True를 반환합니다. 아무것도 선택하지 않고 아래와 같이 해보세요.
>>> (view.sel()[0]).empty()
True
그다음 호출되는 indented_region을 검색해보면 sublime.py에 아래와 같이 정의되어 있습니다.
def indented_region(self, pt):
return sublime_api.view_indented_region(self.view_id, pt)
native로 구현된 함수로 정확한 동작은 알 수 없지만 명으로 유추해보면 들여 쓰기 기준으로 Region를 반환하는 것으로 예상할 수 있습니다.
아래의 그림과 같이 fold.py를 열고 35라인 r위치에 커서를 두고 아래의 내용을 입력해 봅니다.
>>> r = view.sel()[0]
>>> view.indented_region(r.a)
(976, 1259)
(976, 1259) 숫자로 봐서는 정말 들여 쓰기 기준으로 Region이 반환되었는지 알기가 힘든 것 같습니다.
>>> view.sel().clear()
>>> view.sel().add(sublime.Region(976, 1259))
위와 같이 입력하면, 현재의 Region를 지우고, 새로운 Region를 추가하게 됩니다. 콘솔에서 입력하면 선택된 것이 잘 보이지 않으므로 ESC를 눌러 콘솔을 닫으면 들여 쓰기 단위로 선택되어 있음을 알 수 있습니다.
fold_region_from_ident는 파일 맨 위에 정의된 함수이고, self.view.fold(r)은 설명이 필요 없을 듯합니다.
탐험 끝.
sublime은 파이썬만 알면 나만의 기능을 가진 세상에서 하나뿐인 에디터로 만들 수 있습니다. 하지만 내부 동작 및 Plugin에 대한 내용이 찾기 어려워 기능 추가는 높은 장벽일 수 있습니다. 이 글로 조금 낮아졌으면 합니다.
폴딩에 대해 조금 더 정리하면, 폴딩 단위는 들여 쓰기 기준으로 됩니다. 그리고 fold.py를 보셨듯 Region부분만 변경하면 {} 단위, 혹은 여러분이 원하는 단위로 폴딩 기능을 만들 수가 있습니다.
울지 말고 항상 행복하게 코딩하세요. ^^