콘텐츠로 이동

0003. 탭 묶음 단위는 설정으로 고르고, 바꿀 때는 재시작한다

탭 묶음은 지금 프로젝트 루트마다 한 벌이다. 저장소 하나에 worktree가 여러 개면 한 묶음에 터미널 탭이 열 개를 넘기고, 어느 탭이 어느 브랜치의 것인지 탭 이름으로만 가려야 한다. Orca는 이 문제를 worktree 단위로 풀어, worktree마다 탭 묶음을 둔다.

Belloga가 프로젝트 단위를 택한 근거(저장소 밖 파일이 갈 자리, 여러 저장소를 넘는 작업)는 지금도 유효하다. 그래서 한쪽으로 통째로 바꾸는 대신, 사용자가 고르게 하는 안을 검토했다.

탭 묶음의 단위를 바꾸려면 이미 저장된 탭을 새 단위에 맞게 옮겨야 한다. 앱은 탭 배치와 탭 정보만 저장하고 셸은 저장하지 않으므로, 옮긴 뒤 다시 켜면 새 자리에 셸이 새로 뜬다. 돌고 있는 셸을 그 자리에서 다른 묶음으로 옮기는 방법은 없다.

탭 묶음 단위를 설정 항목(프로젝트/worktree)으로 둔다. 기본값은 프로젝트 단위다. 단위를 바꾸면 저장된 탭 배치를 새 단위로 변환하고, 열려 있던 셸을 모두 끝낸 뒤 앱을 다시 띄운다. 변환과 재시작은 확인 대화상자를 거친 뒤에만 일어난다.

변환 규칙은 다음과 같다.

  • 프로젝트에서 worktree로: 터미널은 작업 폴더를, 파일은 경로를, git 탭은 자기가 가리키는 worktree를 보고 그 worktree 묶음으로 옮긴다. 저장소 밖 파일은 main worktree 묶음으로 옮긴다. 작업 폴더 없이 프로젝트 루트에서 뜬 터미널이나, 어느 worktree에도 속하지 않는 작업 폴더의 터미널(여러 저장소를 품은 상위 폴더에서 뜬 경우 등)은 갈 곳이 없어 닫는다. 각 worktree 묶음은 pane 하나로 시작한다.
  • worktree에서 프로젝트로: 모든 worktree 묶음을 그 프로젝트 묶음 하나로 합친다. 분할 배치는 버리고 pane 하나에 모으며, 탭 순서는 main worktree부터 사이드바의 worktree 순서를 따른다. 같은 저장소 밖 파일이 여러 묶음에 열려 있으면 수정 중인 탭이 하나라도 있는 경우 그 가운데 먼저 나온 탭을 남기고, 하나도 없으면 먼저 나온 탭을 남긴다. 남는 탭의 자리는 먼저 나온 쪽의 자리를 그대로 쓴다.
  • 탭이 어느 worktree에 속하는지는 경로의 앞부분이 아니라 연결 목록의 스캔 결과(repos[].worktrees)로 판단한다. worktree는 연결한 폴더 밖의 형제 자리에 있을 수 있어, 경로만으로 가리면 틀린다.
  • 저장소가 하나도 없는 프로젝트는 나눌 worktree가 없다. 두 단위 모두에서 프로젝트 경로를 열쇠로 한 묶음을 그대로 두고, 탭을 옮기거나 닫지 않는다.
  • 스캔 결과에 없는 열쇠의 탭은 두 방향 모두 닫는다. worktree에서 프로젝트로 갈 때는 이미 지워진 worktree나 연결이 해제된 프로젝트의 탭이, 프로젝트에서 worktree로 갈 때는 연결이 해제된 프로젝트의 탭이 여기 해당한다. 합쳐지며 사라진 저장소 밖 파일 탭도 닫힌 것으로 센다.
  • Orca처럼 두 종류의 묶음을 함께 둔다(전역 설정 대신 프로젝트 묶음과 worktree 묶음을 나란히 둠). 탭을 옮길 필요가 없어 변환 규칙이 필요 없다는 장점이 있다. 그러나 탭 열기·닫기·worktree 삭제 시 정리·상태 모으기가 모두 두 갈래로 갈라져 계속 함께 유지해야 하는 비용이 크다. 혼자 만드는 앱에서 이 비용이 오래 남는다고 판단해 기각했다.
  • 그 자리에서 단위를 바꾼다(재시작 없이 즉시 전환). 돌고 있는 셸을 다른 묶음으로 옮길 방법이 없다는 문제가 그대로 남는다. 특히 worktree 단위에서 프로젝트 단위로 바꿀 때 갈 곳이 없어지는 탭의 셸을 어떻게 할지 정할 수 없어 기각했다.
  • 분할 배치까지 그대로 옮긴다. 여러 묶음의 분할 모양을 하나로 합치는 규칙은 경우의 수가 많은 데 비해, 사용자가 분할을 다시 만드는 비용은 작다. 그래서 worktree에서 프로젝트로 합칠 때는 분할을 버리고 pane 하나로 모으는 쪽을 택했다.
  • 채택안(설정 + 재시작 변환): 전역 설정을 두면서 생기는 문제(이미 열린 탭을 어디로 옮길지)를 변환 함수와 확인 대화상자로 명시적으로 풀었다. 단위를 바꾸는 순간에만 비용을 치르고, 그 외의 평소 동작(탭 열기, 상태 모으기, worktree 삭제 시 정리)은 단위와 무관하게 하나의 구현으로 유지된다.
  • 저장소가 없는 프로젝트도 worktree로 나눈다(예: main worktree 자리를 흉내 낸다). worktree는 git이 있어야 존재하는 개념이라, 저장소가 없는 프로젝트에 억지로 하나를 만들면 그 경로가 실제 git 상태와 무관한 가짜 열쇠가 된다. 그 대신 이런 프로젝트는 두 단위 모두에서 프로젝트 경로를 그대로 열쇠로 쓰기로 했다.
  • 기본값이 프로젝트 단위이고 단위를 바꾸는 화면이 아직 없는 동안에는(이 결정을 반영하는 기반 작업만 병합된 상태) 기존 사용자의 화면이 바뀌지 않는다.
  • 단위를 바꾸면 열려 있던 셸이 모두 끝나고 앱이 다시 켜진다. 셸 안의 Claude 대화는 끊기고, 새 셸에서 이어서 실행해야 다시 불러올 수 있다. 확인 대화상자가 이 사실을 미리 알린다.
  • 탭 배치 자체의 자료 구조는 바꾸지 않는다. 배치는 지금도 문자열 열쇠로 묶여 있어, 단위에 따라 그 열쇠에 프로젝트 경로를 넣느냐 worktree 경로를 넣느냐만 달라진다.
  • 단위 설정은 탭 배치와 같은 렌더러 저장소에 둔다. 변환한 배치와 바뀐 설정이 재시작 전에 함께 쓰여야 하고, 둘이 다른 자리에 있으면 한쪽만 저장된 채 앱이 꺼질 수 있어서다.
  • 셸을 모두 끝내는 정리와 재시작 경로는 이번 기반 작업에서 만들고, 설정 화면과 worktree 단위에서 탭을 여는 규칙은 별도 작업에서 이어 만든다.