Skip to content

Instantly share code, notes, and snippets.

@qgp9
Last active March 2, 2026 05:03
Show Gist options
  • Select an option

  • Save qgp9/bebb24c75b3769804f5ac56d8eeb158a to your computer and use it in GitHub Desktop.

Select an option

Save qgp9/bebb24c75b3769804f5ac56d8eeb158a to your computer and use it in GitHub Desktop.
2-Layer tmux Configuration (BASE/WING)

2-Layer tmux Configuration

2-layer tmux 구조로, 외부(base)와 내부(inner) tmux를 중첩 실행하여 prefix 충돌 없이 독립적으로 관리한다.

파일 구조

~/.config/tmux/
├── common.conf        # 공통 설정 (양쪽 레이어가 source)
├── tmux.conf          # inner layer (prefix: C-a)
├── tmux_base.conf     # outer/base layer (prefix: C-q)
└── tbase              # base tmux 실행 스크립트

로드 순서

  • Base: common.conftmux_base.conf
  • Inner: common.conftmux.conf → TPM (plugins)

사용법

# base tmux 실행
tbase

# base 안에서 inner tmux 실행
tmux

레이어 구분

Inner (WING) Base (BASE)
Prefix C-a C-q
Status bar 배경 검은색 회색 (colour235)
태그 WING (노란 볼드) BASE (빨간 볼드)
플러그인 TPM, sensible, tilish 없음

Status bar 예시:

Inner: [WING ▸ myhost:session][M:On ]      0:zsh 1:vim*    [~/wrkp][title][2026-03-01 14:30]
Base:  [BASE ▸ myhost:session][M:Off]      0:zsh*           [~/wrkp][title][2026-03-01 14:30]
Sync:  [WING ▸ myhost:session][M:On ] SYNC 0:zsh 1:vim*    [~/wrkp][title][2026-03-01 14:30]

키바인딩

공통 (common.conf)

동작
prefix + m 마우스 모드 토글
prefix + h/j/k/l vim 스타일 pane 이동
prefix + H/J/K/L vim 스타일 pane 리사이즈 (반복 가능)
prefix + s synchronize-panes 토글 (SYNC 표시)
prefix + Space 다음 윈도우
prefix + BSpace 이전 윈도우
prefix + " 수평 분할 (현재 경로)
prefix + % 수직 분할 (현재 경로)
prefix + c 새 윈도우 (현재 경로)
prefix + A 윈도우 이름 변경
prefix + r 설정 리로드

VI Copy-mode

동작
prefix + [ copy-mode 진입
v 비주얼 선택 시작
y 선택 영역 복사
yy 현재 줄 전체 복사
Escape copy-mode 종료

복사된 텍스트는 OSC52를 통해 시스템 클립보드로 자동 전달된다 (SSH 원격 환경 포함).

Inner 전용

동작
Alt + Enter 우하단 pane에서 분할
Alt + 숫자 워크스페이스 전환 (tilish)

Base 전용

동작
prefix + Tab 마지막 윈도우 전환

주요 설정

  • 터미널: tmux-256color
  • escape-time: 0 (2-layer 지연 최소화)
  • focus-events: on (inner에 포커스 이벤트 전달)
  • 클립보드: OSC52 (~/.local/bin/copy-osc52.sh 필요)
  • 경로 표시: $HOME~ 치환 (tmux 내장 포맷, 3.1+)

요구사항

  • tmux 3.1+
  • ~/.local/bin/copy-osc52.sh (클립보드 연동)
  • TPM (inner 플러그인 관리)
########################################
# common.conf — 공통 설정 (inner/base 공유)
#
# 2-layer tmux 구조에서 양쪽 레이어가 공유하는 설정.
# inner(tmux.conf)와 outer(tmux_base.conf) 모두
# source-file로 이 파일을 먼저 로드한다.
#
# prefix, reload, status-left, status-bg/fg 등
# 레이어별로 달라야 하는 설정은 각 파일에서 별도로 정의한다.
########################################
########################################
# General
########################################
# 창 이름 자동 변경 끄기 — 수동으로 이름 지정한 것을 유지
setw -g automatic-rename off
# copy-mode에서 vi 키바인딩 사용
setw -g mode-keys vi
# 스크롤백 버퍼 크기 (줄 수)
set -g history-limit 10000
# ESC 키 지연 제거 — 2-layer 구조에서 키 입력 지연 최소화에 필수
# 기본값 500ms → 0ms로 설정하여 vim 등에서 ESC 반응 즉시
set -sg escape-time 0
# 포커스 이벤트를 터미널에서 tmux로 전달
# inner tmux가 포커스 변경을 감지할 수 있도록 outer에서도 필요
set -g focus-events on
# 터미널 타입 — tmux-256color로 통일 (screen-256color, xterm-256color 대신)
# tmux의 기능(italics 등)을 온전히 지원하는 terminfo
set -g default-terminal "tmux-256color"
# xterm 스타일 키 시퀀스 활성화 (Shift/Ctrl+화살표 등)
set -g xterm-keys on
# alternate screen 비활성화 — less/man 종료 후 출력이 터미널에 남도록
# smcup(alternate screen 진입), rmcup(복귀)를 무효화
set -g terminal-overrides 'xterm*:smcup@:rmcup@'
########################################
# Clipboard (OSC52)
########################################
# tmux 버퍼에 텍스트가 설정될 때마다 OSC52 이스케이프 시퀀스로
# 시스템 클립보드에 복사. SSH 원격 환경에서도 로컬 클립보드로 전달 가능.
# copy-osc52.sh 스크립트가 ~/.local/bin/ 에 있어야 동작.
# after-set-buffer: copy-mode 복사, load-buffer 등으로 버퍼가 변경될 때 트리거
set-hook -g after-set-buffer 'run-shell "tmux show-buffer | ~/.local/bin/copy-osc52.sh"'
########################################
# MOUSE
########################################
# prefix + m 으로 마우스 모드 토글
# 마우스 ON: pane 선택, 스크롤, 리사이즈 가능
# 마우스 OFF: 터미널 네이티브 선택/복사 사용 가능
unbind m
bind-key m if-shell 'tmux showw -gv mouse|grep on' \
'set -g mouse off' \
'set -g mouse on' \
;
########################################
# VI Copy-mode
########################################
# v: 비주얼 선택 시작 (vim의 v와 동일)
bind -T copy-mode-vi v send -X begin-selection \;
# y: 선택 영역이 있으면 복사, 없으면 yy(줄 복사) 대기 모드로 전환
# - 선택 중: 선택 영역을 버퍼에 복사 → OSC52 hook으로 클립보드 전달
# - 미선택: copy-await 테이블로 전환하여 다음 키 대기
bind -T copy-mode-vi y if -F "#{selection_active}" \
{ send -X copy-selection; } \
{ send -X begin-selection; switch-client -T copy-await }
# yy: 현재 줄 전체 복사 (vim의 yy와 동일한 동작)
# copy-await 테이블에서 y를 다시 누르면:
# 1. 현재 줄 선택 → 2. 짧은 대기(선택 반영) → 3. 복사 → 4. copy-mode-vi로 복귀
bind -T copy-await y { \
send -X select-line ; \
run "sleep 0.3" ; \
send -X copy-selection ; \
display-message 'Line Copied' ; \
switch-client -T copy-mode-vi ; \
}
# Escape: copy-mode 종료 (vim 사용자에게 자연스러운 키)
bind -T copy-mode-vi Escape send -X cancel
########################################
# PANE
########################################
# prefix + s: 모든 pane에 동일한 입력을 보내는 synchronize-panes 토글
# 여러 서버에 동시에 같은 명령을 실행할 때 유용
bind-key s set-window-option synchronize-panes
# prefix + h/j/k/l: vim 스타일 pane 이동
# h=왼쪽, j=아래, k=위, l=오른쪽
bind-key h selectp -L
bind-key j selectp -D
bind-key k selectp -U
bind-key l selectp -R
# prefix + H/J/K/L (대문자): vim 스타일 pane 리사이즈
# -r: 반복 가능 (repeat-time 내에 prefix 없이 연속 입력)
bind-key -r H resize-pane -L 2
bind-key -r J resize-pane -D 2
bind-key -r K resize-pane -U 2
bind-key -r L resize-pane -R 2
########################################
# Windows
########################################
# prefix + Space: 다음 윈도우
# prefix + BSpace(백스페이스): 이전 윈도우
bind-key Space next
bind-key BSpace prev
# 새 윈도우/분할 시 현재 pane의 디렉토리를 유지
# 기본 동작은 홈 디렉토리에서 시작하므로 override
bind '"' split-window -c "#{pane_current_path}" # 수평 분할
bind % split-window -h -c "#{pane_current_path}" # 수직 분할
bind c new-window -c "#{pane_current_path}" # 새 윈도우
########################################
# Other Binding
########################################
# prefix + A: 현재 윈도우 이름 변경 프롬프트
bind-key A command-prompt "rename-window '%%'"
########################################
# STATUS BAR (공통 부분)
########################################
# 상태줄 구분자 — 초록색 대괄호로 각 섹션을 감싸는 데코레이션
# @B1 = '[', @B2 = ']' (초록색)
# status-left, status-right 등에서 #{@B1}...#{@B2} 패턴으로 사용
set -g @B1 '#[default]#[fg=green][#[default]'
set -g @B2 '#[default]#[fg=green]]#[default]'
# 비활성 윈도우: 시안색 인덱스 + 흰색 이름
set-window-option -g window-status-format '#[fg=cyan]#I#[fg=blue]:#[fg=white]#W#[dim]#F'
# 활성 윈도우: 파란 배경 + 볼드체로 강조
set-window-option -g window-status-current-format '#[bg=blue,bold]#[fg=cyan]#I#[fg=blue]:#[fg=white]#W#[dim]#F'
# 우측: [현재 경로(~치환)] [pane 타이틀] [날짜 시간]
# #{s|#{HOME}|~|:pane_current_path} — tmux 내장 포맷 치환 (3.1+)
# 외부 셸 프로세스(sed) 없이 $HOME을 ~로 변환
set -g status-right-length 120
set -g status-right '[#{s|#{HOME}|~|:pane_current_path}]#{@B1}#T#{@B2}#{@B1}#[fg=blue]%Y-%m-%d #[default]%H:%M#{@B2}'
printf '\033]52;c;'
base64 | tr -d '\n'
printf '\a'
exec tmux -L base -f ~/.config/tmux/tmux_base.conf "$@"
########################################
# tmux.conf — inner layer (내부 tmux)
#
# 2-layer 구조에서 실제 작업을 수행하는 내부 tmux.
# base(outer) tmux 안에서 실행되며, prefix는 C-a.
# 공통 설정은 common.conf에서 로드한다.
#
# 로드 순서: common.conf → tmux.conf → TPM(plugins)
# TPM/sensible이 common.conf 값을 덮어쓰지 않도록
# 플러그인 초기화를 맨 마지막에 배치한다.
########################################
# 공통 설정 로드 (마우스, vi copy-mode, pane/window 네비게이션, status bar 공통 등)
source-file ~/.config/tmux/common.conf
########################################
# PREFIX (inner: C-a)
########################################
# 기본 prefix(C-b) 해제 후 C-a로 변경
# screen과 동일한 키바인딩. base의 C-q와 구분됨.
unbind C-b
set -g prefix C-a
# prefix + a: 중첩 tmux에 prefix 전달 (inner 안의 또 다른 tmux용)
bind a send-prefix
# C-a C-a: 마지막 윈도우로 빠르게 전환
bind-key C-a last-window
########################################
# Inner-specific Bindings
########################################
# Alt+Enter: 우하단 pane 선택 후 현재 경로에서 수평 분할
# tilish와 연계하여 터미널 빠르게 추가할 때 사용
bind-key -n M-Enter 'select-pane -t "bottom-right"; split-pane -c "#{pane_current_path}"'
# Shift+F10: lazyvim에서 vscode 호환 키바인딩으로 사용
# 터미널/OS에서 키 충돌 가능성이 있어 주석 처리
#bind-key -n S-F10 send-keys "\e[34~"
########################################
# Pane Border (inner 전용)
########################################
# 비활성 pane 테두리: 어두운 회색 (활성 pane과 구분)
set -g pane-border-style fg=colour238
# 활성 pane 테두리: 파란색으로 강조
set -g pane-active-border-style fg=blue
# pane 상단에 정보 표시줄 활성화
set -g pane-border-status top
# pane 테두리 포맷: [인덱스] [실행중인 명령] [활성이면 🔥 표시]
set -g pane-border-format "#{pane_index} #{pane_current_command} #{?pane_active,🔥,} #[align=right]"
########################################
# Reload (inner 전용 경로)
########################################
# prefix + r: inner 설정 파일만 리로드 (common.conf도 함께 다시 로드됨)
bind r 'source-file ~/.config/tmux/tmux.conf; display "Reloaded tmux.conf"'
########################################
# STATUS BAR (inner: 검은 배경)
# @B1, @B2, window-status-format, status-right는 common.conf에서 정의
########################################
# 상태줄 배경색: 검은색 (base의 회색과 구분)
set -g status-bg black; set -g status-fg white
# 좌측: [WING ▸ 호스트:세션명] [마우스 상태] [SYNC 경고]
# WING = inner layer 태그, #h = short hostname
# synchronize-panes가 켜져 있으면 빨간 SYNC 표시
set -g status-left-length 80
set -g status-left '#{@B1}#[fg=yellow bold]WING #[fg=default nobold]▸ #[fg=blue]#h:#[fg=cyan]#S#{@B2}[M:#{?mouse,#[fg=green bold]On #[fg=default nobold],Off}]#{?synchronize-panes,#[fg=red bold] SYNC#[default],} '
########################################
# Plugins (inner 전용)
# common.conf 이후에 로드하여, sensible이 escape-time 등을 덮어쓰지 않도록
# TPM 초기화를 파일 맨 마지막에 배치한다.
########################################
# TPM (Tmux Plugin Manager) — prefix + I 로 플러그인 설치
set -g @plugin 'tmux-plugins/tpm'
# tmux-sensible: 합리적인 기본 설정 모음
# 주의: sensible은 이미 설정된 값은 덮어쓰지 않음 (if-shell 기반)
# 하지만 안전을 위해 TPM을 파일 끝에서 실행
set -g @plugin 'tmux-plugins/tmux-sensible'
# tmux-tilish: i3wm 스타일 윈도우/pane 관리
# Alt+숫자로 워크스페이스 전환, Alt+Enter로 새 pane 등
set -g @plugin 'jabirali/tmux-tilish'
# tilish 기본 레이아웃: 수평 균등 분할
set -g @tilish-default 'even-horizontal'
# TPM 초기화 — 반드시 모든 설정 이후 맨 마지막에 실행
run '~/.config/tmux/plugins/tpm/tpm'
########################################
# tmux_base.conf — outer (base) layer (외부 tmux)
#
# 2-layer 구조에서 가장 바깥쪽 tmux.
# `tbase` 스크립트로 실행: tmux -L base -f tmux_base.conf
# 이 안에서 inner tmux(tmux.conf)를 중첩 실행한다.
#
# prefix는 C-q로, inner(C-a)와 충돌하지 않는다.
# status bar는 회색 배경 + [BASE ▸] 태그로 inner와 시각적 구분.
#
# 로드 순서: common.conf → tmux_base.conf
########################################
# 공통 설정 로드 (마우스, vi copy-mode, pane/window 네비게이션, status bar 공통 등)
source-file ~/.config/tmux/common.conf
########################################
# PREFIX (base: C-q)
########################################
# 기본 prefix(C-b) 해제 후 C-q로 변경
# inner의 C-a와 겹치지 않도록 별도 키 사용
unbind C-b
set -g prefix C-q
# prefix + q: 중첩 tmux에 C-q 전달 (base 안의 또 다른 base용)
bind q send-prefix
# C-q C-q: 마지막 윈도우로 빠르게 전환
bind-key C-q last-window
########################################
# Base-specific Bindings
########################################
# prefix + Tab: 마지막 윈도우로 전환 (Tab 키로도 접근 가능하게)
bind-key tab last-window
########################################
# Reload (base 전용 경로)
########################################
# prefix + r: base 설정 파일만 리로드 (common.conf도 함께 다시 로드됨)
bind r 'source-file ~/.config/tmux/tmux_base.conf; display "Reloaded tmux_base.conf"'
########################################
# STATUS BAR (base: 회색 배경 + [BASE ▸] 태그)
# @B1, @B2, window-status-format, status-right는 common.conf에서 정의
########################################
# 상태줄 배경색: 어두운 회색(colour235) — inner의 검은색과 시각적 구분
# 글자색: 밝은 회색(colour245) — 가독성 유지
set -g status-bg colour235; set -g status-fg colour245
# 좌측: [BASE ▸ 호스트:세션명] [마우스 상태] [SYNC 경고]
# [BASE ▸] 접두어로 현재 base layer임을 즉시 식별 가능
# #h = short hostname (hostname -s 와 동일)
# synchronize-panes가 켜져 있으면 빨간 SYNC 표시
set -g status-left-length 80
set -g status-left '#{@B1}#[fg=red bold]BASE #[fg=default nobold]▸ #[fg=blue]#h:#[fg=cyan]#S#{@B2}[M:#{?mouse,#[fg=green bold]On #[fg=default nobold],Off}]#{?synchronize-panes,#[fg=red bold] SYNC#[default],} '
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment