ํฌ์ŠคํŠธ

๐Ÿชถ smug โ€” ์˜์กด์„ฑ ์—†๋Š” ๋ฏธ๋‹ˆ๋ฉ€ tmux ์„ธ์…˜ ๋งค๋‹ˆ์ € (ํ”„๋ฆฌ์…‹์— ์—†๋Š” ๋ ˆ์ด์•„์›ƒ๊นŒ์ง€)

smug๋Š” Go ๋‹จ์ผ ๋ฐ”์ด๋„ˆ๋ฆฌ tmux ์„ธ์…˜ ๋งค๋‹ˆ์ €๋‹ค. ์„ค์น˜ยท๊ธฐ๋ณธ config๋ถ€ํ„ฐ, tmux ํ‘œ์ค€ ํ”„๋ฆฌ์…‹์— ์—†๋Š” ์ปค์Šคํ…€ ๋ ˆ์ด์•„์›ƒ์„ layout ๋ฌธ์ž์—ด๋กœ ๊ณ ์ •ํ•˜๋Š” ๋ฒ•, smug๊ฐ€ ํ•˜๋Š” ์ผ๊ณผ ์•ˆ ํ•˜๋Š” ์ผ(freeze๋Š” tmuxp)๊นŒ์ง€ ์‹ค์ „ ์ •๋ฆฌ.

๐Ÿชถ smug โ€” ์˜์กด์„ฑ ์—†๋Š” ๋ฏธ๋‹ˆ๋ฉ€ tmux ์„ธ์…˜ ๋งค๋‹ˆ์ € (ํ”„๋ฆฌ์…‹์— ์—†๋Š” ๋ ˆ์ด์•„์›ƒ๊นŒ์ง€)

์„ธ์…˜ ๋งค๋‹ˆ์ €๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋น„๊ตํ•œ ๋์— smug๋ฅผ ๊ณจ๋ž๋‹ค๋ฉด, ์ด ๊ธ€์€ ๊ทธ๋‹ค์Œ ์‹ค์ „์ด๋‹ค. smug์˜ ์ž๋ฆฌ๋Š” ํ•œ๋งˆ๋””๋กœ โ€œ๋ฌด์˜์กดยท๋ฏธ๋‹ˆ๋ฉ€โ€ โ€” Ruby(tmuxinator)๋‚˜ Python(tmuxp) ๋Ÿฐํƒ€์ž„ ์—†์ด ๋„๋Š” Go ๋‹จ์ผ ๋ฐ”์ด๋„ˆ๋ฆฌ๋‹ค. YAML๋กœ ์„ธ์…˜ยท์œˆ๋„์šฐยทํŒจ๋„์„ ์„ ์–ธํ•˜๋ฉด ๊ทธ๋Œ€๋กœ ๋„์›Œ ์ค€๋‹ค.

์„ธ์…˜ ๋งค๋‹ˆ์ € 3์ข…(smugยทtmuxpยทtmuxinator)์˜ ๋น„๊ตยท์„ ํƒ๊ณผ, ์ด ๋„๊ตฌ๋“ค์ด ๋‚ด๋ถ€์—์„œ ๋ถ€๋ฅด๋Š” tmux ๋ช…๋ น์˜ ์…ธ ํ•ด๋ถ€๋Š” tmux ์„ธ์…˜ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๊ธ€์— ์žˆ๋‹ค. ์ด ๊ธ€์€ ๊ทธ์ค‘ smug๋ฅผ ๊ณจ๋ž๋‹ค๋Š” ์ „์ œ์—์„œ ์ถœ๋ฐœํ•œ๋‹ค. ์ „์ฒด ํ•™์Šต ์ˆœ์„œ๋Š” tmux ๋กœ๋“œ๋งต 3๋‹จ๊ณ„.

์„ค์น˜

Homebrew ํ•œ ์ค„์ด๋ฉด ๋๋‚œ๋‹ค. ๋Ÿฐํƒ€์ž„ ์˜์กด์ด ์—†์–ด ์„œ๋ฒ„ยท์ปจํ…Œ์ด๋„ˆ์—” ๋ฐ”์ด๋„ˆ๋ฆฌ ํ•˜๋‚˜๋งŒ ๋ณต์‚ฌํ•ด๋„ ๋ˆ๋‹ค.

1
2
brew install smug
# ๋˜๋Š”: go install github.com/ivaaaan/smug@latest

๊ธฐ๋ณธ โ€” ์„ธ์…˜์„ YAML๋กœ ์„ ์–ธ

config๋Š” ~/.config/smug/<์ด๋ฆ„>.yml์— ๋‘”๋‹ค. ํŒŒ์ผ ํ•˜๋‚˜ = ์„ธ์…˜ ํ•˜๋‚˜๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
# ~/.config/smug/dev.yml
session: dev
root: ~/projects/app        # ๋ชจ๋“  ์œˆ๋„์šฐยทํŒจ๋„์˜ ์‹œ์ž‘ ๋””๋ ‰ํ† ๋ฆฌ
windows:
  - name: editor
    commands:
      - nvim                # ์ด ์œˆ๋„์šฐ์˜ ์ฒซ ํŒจ๋„์—์„œ ์‹คํ–‰
  - name: server
    layout: main-vertical   # ์ขŒ 1 + ์šฐ 2 ๋ถ„ํ• 
    panes:                  # ์•”๋ฌต์  base ํŒจ๋„ 1๊ฐœ + ์•„๋ž˜ 2๊ฐœ = ์ด 3ํŒจ๋„
      - commands: [npm run dev]
      - commands: [npm run test:watch]
1
smug start dev     # ์ด ์„ธ์…˜์„ ๋„์šฐ๊ณ  attach. `smug dev`๋กœ ์ค„์—ฌ๋„ ๋จ(๊ธฐ๋ณธ ๋ช…๋ น์ด start)

ํ•ต์‹ฌ ํ‚ค๋งŒ ์งš์œผ๋ฉด:

  • session โ€” ์„ธ์…˜ ์ด๋ฆ„. root โ€” ์‹œ์ž‘ ๋””๋ ‰ํ† ๋ฆฌ(์„ธ์…˜ยท์œˆ๋„์šฐยทํŒจ๋„๋ณ„๋กœ ๊ฐ๊ฐ ์ง€์ • ๊ฐ€๋Šฅํ•˜๊ณ , ์—†์œผ๋ฉด ์ƒ์œ„ ๊ฒƒ์„ ์ƒ์†).
  • windows โ€” ๊ฐ ์œˆ๋„์šฐ๋Š” nameยทlayoutยทcommandsยทpanes๋ฅผ ๊ฐ€์ง„๋‹ค.
  • panes โ€” ์—ฌ๊ธฐ์„œ ๊ฐœ์ˆ˜ ๊ฐ๊ฐ์ด ์ค‘์š”ํ•˜๋‹ค. ์œˆ๋„์šฐ๋Š” ์•”๋ฌต์ ์œผ๋กœ ํŒจ๋„ 1๊ฐœ๋กœ ์‹œ์ž‘ํ•˜๊ณ , panes ํ•ญ๋ชฉ ํ•˜๋‚˜๋งˆ๋‹ค ๋ถ„ํ• ์ด ํ•˜๋‚˜ ์ถ”๊ฐ€๋œ๋‹ค. ์ฆ‰ ํ•ญ๋ชฉ 2๊ฐœ = ์ด 3ํŒจ๋„์ด๋‹ค.
  • commands โ€” ํ•ด๋‹น ์œˆ๋„์šฐ/ํŒจ๋„์—์„œ ์‹œ์ž‘ ์‹œ ์‹คํ–‰ํ•  ๋ช…๋ น. nvimยท๊ฐœ๋ฐœ ์„œ๋ฒ„๋ฅผ ์ž๋™ ๊ธฐ๋™ํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค.

์ด๋ฏธ ๋–  ์žˆ๋Š” ์„ธ์…˜์ด๋ฉด ์ƒˆ๋กœ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ attachํ•œ๋‹ค(์•ˆ์—์„œ ์‹คํ–‰ํ•˜๋ฉด switch-client). ์…ธ ์Šคํฌ๋ฆฝํŠธ๋กœ ์ง์ ‘ ์งค ๋•Œ ์†์œผ๋กœ ๋„ฃ๋˜ has-session ๋ถ„๊ธฐ๊ฐ€ ๊ธฐ๋ณธ ๋™์ž‘์œผ๋กœ ๋“ค์–ด ์žˆ๋Š” ์…ˆ์ด๋‹ค.

ํ”„๋ฆฌ์…‹์— ์—†๋Š” ๋ ˆ์ด์•„์›ƒ โ€” layout ๋ฌธ์ž์—ด๋กœ ๊ณ ์ •

layout์—๋Š” tmux ํ‘œ์ค€ ํ”„๋ฆฌ์…‹๋ช…(main-verticalยทmain-horizontalยทtiledยทeven-horizontalยทeven-vertical)์„ ์“ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์›ํ•˜๋Š” ๋ฐฐ์น˜๊ฐ€ ํ”„๋ฆฌ์…‹์— ์—†์„ ๋•Œ๊ฐ€ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์œ„๋Š” ์ขŒ/์šฐ 2๋ถ„ํ• , ์•„๋ž˜๋Š” ์ „์ฒดํญ 1๊ฐœ ๊ฐ™์€ ๋ฐฐ์น˜:

1
2
3
4
5
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ pane0 โ”‚ pane1 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚     pane2     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

์ด๊ฑด main-horizontal(์œ„ 1 + ์•„๋ž˜ N)์˜ ์ƒํ•˜ ๋ฐ˜๋Œ€๋ผ ์–ด๋–ค ํ”„๋ฆฌ์…‹์œผ๋กœ๋„ ์•ˆ ๋‚˜์˜จ๋‹ค. ํ•ด๋ฒ•์€ tmux ๋ ˆ์ด์•„์›ƒ ๋ฌธ์ž์—ด์„ layout์— ์ง์ ‘ ๋„ฃ๋Š” ๊ฒƒ์ด๋‹ค โ€” smug๋Š” ์ด ๊ฐ’์„ tmux select-layout์— ๊ทธ๋Œ€๋กœ ๋„˜๊ธฐ๋ฏ€๋กœ, ํ”„๋ฆฌ์…‹๋ช…์ด๋“  raw ๋ฌธ์ž์—ด์ด๋“  ๋‹ค ๋ฐ›๋Š”๋‹ค.

๋ฌธ์ž์—ด์€ ์›ํ•˜๋Š” ๋ฐฐ์น˜๋ฅผ tmux์—์„œ ํ•œ ๋ฒˆ ์†์œผ๋กœ ๋งŒ๋“  ๋’ค ๋ฝ‘์•„๋‚ธ๋‹ค:

1
2
3
4
5
6
7
8
9
10
11
# 1) ์ž„์‹œ tmux์—์„œ ์›ํ•˜๋Š” ๋ฐฐ์น˜๋ฅผ ๋งŒ๋“ ๋‹ค (์„ค์ • ๊ฐ„์„ญ ์—†์ด -f /dev/null)
tmux -L cap -f /dev/null new-session -d -x 220 -y 50
tmux -L cap split-window -v            # ์œ„/์•„๋ž˜
tmux -L cap select-pane -t 0           # ์œ„ ์„ ํƒ
tmux -L cap split-window -h -t 0       # ์œ„๋ฅผ ์ขŒ/์šฐ๋กœ

# 2) ๊ทธ ๋ฐฐ์น˜์˜ ๋ ˆ์ด์•„์›ƒ ๋ฌธ์ž์—ด์„ ์บก์ฒ˜
tmux -L cap list-windows -F '#{window_layout}'
# โ†’ 60d1,220x50,0,0[220x25,0,0{110x25,0,0,0,109x25,111,0,2},220x24,0,26,1]

tmux -L cap kill-server                # ์ž„์‹œ ์„œ๋ฒ„ ์ •๋ฆฌ

๋ฝ‘์€ ๋ฌธ์ž์—ด์„ ๊ทธ๋Œ€๋กœ layout์— ๋ฐ•๋Š”๋‹ค:

1
2
3
4
5
6
  - name: server
    # ์œ„ ์ขŒ/์šฐ 2 + ์•„๋ž˜ ์ „์ฒดํญ 1 (ํ”„๋ฆฌ์…‹์— ์—†์–ด ๋ ˆ์ด์•„์›ƒ ๋ฌธ์ž์—ด๋กœ ๊ณ ์ •)
    layout: 60d1,220x50,0,0[220x25,0,0{110x25,0,0,0,109x25,111,0,2},220x24,0,26,1]
    panes:                  # ๋นˆ ํ•ญ๋ชฉ 2๊ฐœ = ์ด 3ํŒจ๋„ (๋ฐฐ์น˜๋Š” ์œ„ ๋ฌธ์ž์—ด์ด ํ™•์ •)
      -
      -

๋‘ ๊ฐ€์ง€๋งŒ ์•Œ๋ฉด ๋œ๋‹ค:

  • ๋ฌธ์ž์—ด ์•ž์˜ 220x50์€ ์บก์ฒ˜ ๋‹น์‹œ ํฌ๊ธฐ์ง€๋งŒ, select-layout์ด ์‹ค์ œ ํ„ฐ๋ฏธ๋„ ํฌ๊ธฐ์— ๋น„์œจ๋กœ ๋ฆฌ์Šค์ผ€์ผํ•˜๋ฏ€๋กœ ์ฐฝ ํฌ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ๋„ ๋ฐฐ์น˜๋Š” ์œ ์ง€๋œ๋‹ค. ์•ž 4์ž๋ฆฌ(60d1)๋Š” tmux๊ฐ€ ๊ณ„์‚ฐํ•˜๋Š” ์ฒดํฌ์„ฌ์ด๋ผ, ์ง์ ‘ ํƒ€์ดํ•‘ํ•˜์ง€ ๋ง๊ณ  ๋ฐ˜๋“œ์‹œ ์บก์ฒ˜ํ•œ ๋ฌธ์ž์—ด์„ ํ†ต์งธ๋กœ ์จ์•ผ ํ•œ๋‹ค.
  • ํŒจ๋„ ๊ฐœ์ˆ˜๋งŒ ๋งž์œผ๋ฉด ๋œ๋‹ค. ๋ฌธ์ž์—ด์ด 3ํŒจ๋„์ด๋‹ˆ panes ๋นˆ ํ•ญ๋ชฉ 2๊ฐœ(= base 1 + 2)๋กœ 3ํŒจ๋„์„ ๋งŒ๋“ค์–ด ๋‘๋ฉด, ๋งˆ์ง€๋ง‰์— ๋ฌธ์ž์—ด์ด ๋ฐฐ์น˜๋ฅผ ํ™•์ •ํ•œ๋‹ค.

์ด ํŠธ๋ฆญ์€ smug๋ฟ ์•„๋‹ˆ๋ผ tmuxinatorยทtmuxp์—์„œ๋„ ๊ทธ๋Œ€๋กœ ํ†ตํ•œ๋‹ค โ€” ์…‹ ๋‹ค layout์„ tmux select-layout์— ๋„˜๊ธฐ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

smug๊ฐ€ ํ•˜๋Š” ๊ฒƒ / ์•ˆ ํ•˜๋Š” ๊ฒƒ

smug์˜ ๋ฒ”์œ„๋Š” โ€œ์„ธ์…˜ ํ•˜๋‚˜๋ฅผ ํ†ต์งธ๋กœ ์„ ์–ธ โ†’ ๊ทธ๋Œ€๋กœ ๋„์šฐ๊ธฐโ€์— ์™„๊ฒฐ๋ผ ์žˆ๋‹ค.

ํ•œ๋‹ค:

  • ์„ธ์…˜ยท์œˆ๋„์šฐยทํŒจ๋„ ์„ ์–ธ๊ณผ ์ƒ์„ฑ, layout(ํ”„๋ฆฌ์…‹ + ๋ฌธ์ž์—ด)
  • ํŒจ๋„๋ณ„ ์‹œ์ž‘ ๋””๋ ‰ํ† ๋ฆฌ(root)์™€ ์‹œ์ž‘ ๋ช…๋ น(commands)
  • ํ›… โ€” before_start(์„ธ์…˜ ์ƒ์„ฑ ์ „), stop(๋‚ด๋ฆด ๋•Œ)
  • ํ™˜๊ฒฝ๋ณ€์ˆ˜(env), ์ด๋ฏธ ์žˆ์œผ๋ฉด attach, ์„ ํƒ ์‹คํ–‰(smug start dev -w server๋กœ ํŠน์ • ์œˆ๋„์šฐ๋งŒ)

์•ˆ ํ•œ๋‹ค (๊ฒฝ๊ณ„ ๋ฐ–):

  • freeze โ€” ์ง€๊ธˆ ๋–  ์žˆ๋Š” ์„ธ์…˜์„ ๊ฑฐ๊พธ๋กœ config๋กœ ์—ญ์ถ”์ถœํ•˜๋Š” ๊ธฐ๋Šฅ์€ ์—†๋‹ค. smug๋Š” ์„ ์–ธํ•œ ๊ฑธ ์‹คํ–‰ํ•  ๋ฟ์ด๋‹ค.
  • ํ”„๋กœ๊ทธ๋ž˜๋จธ๋ธ” ์ œ์–ด โ€” libtmux ๊ฐ™์€ API๋‚˜ ํŒŒ์ด์ฌ ์ฝ˜์†”์€ ์—†๋‹ค.
  • ๋‹ค๋ฅธ ๋„๊ตฌ config import, ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ๋„ ์—†๋‹ค.

์ด ๊ฒฝ๊ณ„ ๋ฐ– โ€” ํŠนํžˆ freeze(์†์œผ๋กœ ์ง  ์„ธ์…˜์„ ํŒŒ์ผ๋กœ ์ €์žฅ)๋‚˜ tmux๋ฅผ ํŒŒ์ด์ฌ์œผ๋กœ ์Šคํฌ๋ฆฝํŒ…ํ•˜๊ณ  ์‹ถ์–ด์ง€๋ฉด โ€” ๊ทธ๋•Œ tmuxp๋กœ ๋„˜์–ด๊ฐ€๋ฉด ๋œ๋‹ค. ๊ธฐ๋ณธ ๋ ˆ์ด์•„์›ƒ YAML์ด ์„œ๋กœ ๊ฑฐ์˜ 1:1์ด๋ผ ์ „ํ™˜ ๋น„์šฉ์ด ์ž‘๋‹ค. ๋ฐ˜๋Œ€๋กœ โ€œ์ •ํ•ด์ง„ ๋ ˆ์ด์•„์›ƒ์„ ๋ฐ˜๋ณต ๋กœ๋“œโ€๊ฐ€ ์ „๋ถ€๋ผ๋ฉด smug์˜ ์ด ๋ฒ”์œ„๊ฐ€ ์ •ํ™•ํžˆ ํ•„์š”ํ•œ ๋งŒํผ์ด๋‹ค โ€” ๋ชจ์ž๋ผ์ง€๋„, ์•ˆ ์“ฐ๋Š” ๊ธฐ๋Šฅ์œผ๋กœ ๋ฌด๊ฒ์ง€๋„ ์•Š๋‹ค.

์ž์ฃผ ์“ฐ๋Š” ๋ช…๋ น

1
2
3
4
5
6
smug start dev        # ์„ธ์…˜ ์‹œ์ž‘(+attach). `smug dev`๋กœ ์ถ•์•ฝ ๊ฐ€๋Šฅ
smug start dev -w server  # ํŠน์ • ์œˆ๋„์šฐ๋งŒ
smug stop dev         # ์„ธ์…˜ ์ข…๋ฃŒ (stop ํ›… ์‹คํ–‰)
smug new dev          # ์ƒˆ config ํŒŒ์ผ ์ƒ์„ฑ ํ›„ ํŽธ์ง‘๊ธฐ๋กœ ์—ด๊ธฐ
smug edit dev         # ๊ธฐ์กด config ํŽธ์ง‘
smug list             # config ๋ชฉ๋ก

์ •๋ฆฌ

smug๋Š” โ€œ์„ธ์…˜์„ ์„ ์–ธํ•˜๊ณ  ๋„์šด๋‹คโ€ ํ•œ ๊ฐ€์ง€๋ฅผ ์˜์กด์„ฑ ์—†์ด ๊น”๋”ํ•˜๊ฒŒ ํ•˜๋Š” ๋„๊ตฌ๋‹ค. ๋ ˆ์ด์•„์›ƒ์€ ํ”„๋ฆฌ์…‹์œผ๋กœ ๋Œ€๋ถ€๋ถ„ ๋˜๊ณ , ์•ˆ ๋˜๋Š” ๋ฐฐ์น˜๋Š” tmux ๋ ˆ์ด์•„์›ƒ ๋ฌธ์ž์—ด์„ ์บก์ฒ˜ํ•ด ๋ฐ•์œผ๋ฉด ๊ทธ๋งŒ์ด๋‹ค. ๋”ฑ ๊ทธ ์šฉ๋„๋ผ๋ฉด ์ตœ์ ์ด๊ณ , freeze๋‚˜ ํŒŒ์ด์ฌ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•ด์ง€๋Š” ๋‚  tmuxp๋กœ ์˜ฎ๊ฒจ๋„ ๋Šฆ์ง€ ์•Š๋‹ค.

์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.