터미널에서 두 눈 뜨고 탐색! peektea, 옆자리 미리보기로 생산성 UP!
2026. 6. 3.
터미널에서 두 눈 뜨고 탐색! peektea, 옆자리 미리보기로 생산성 UP!
안녕하세요, 10년 차 개발자이자 테크 블로거, 마네쉬워입니다. 저는 요즘 모든 커밋마다 코드를 검토해 주는 마이크로 AI 코드 리뷰어 git-lrc를 만들고 있습니다. 이 프로젝트는 깃허브에서 소스 코드를 자유롭게 열람하고 사용할 수 있으며, 완전히 무료입니다. git-lrc에 별을 눌러주세요 – 더 많은 개발자가 이 유용한 도구를 발견할 수 있도록 도와주세요! 꼭 한번 사용해 보시고 피드백을 공유해 주시면 감사하겠습니다.
지난번 포스팅에서 '다음 단계는 무엇일까?'라는 질문과 함께 몇 가지 계획을 공유했었죠.
그 목록의 가장 위에 있던 두 가지가 바로 이것들이었습니다.
인라인 이미지 미리보기: Kitty/iTerm 프로토콜 또는
chafa를 통해 터미널에서 이미지 렌더링분할 패널 파일 미리보기: 선택된 파일 내용을 오른쪽에 표시하여, 파일 탐색을 멈추지 않고도 내용을 엿볼 수 있도록
그리고 오늘, 이 두 가지 기능이 드디어 peektea에 적용되어 여러분을 찾아왔습니다.
p 키를 누르면, 오른쪽에 미리보기 패널이 짠하고 나타납니다. 다시 p를 누르면 감쪽같이 사라지고요.
겉으로 보기엔 이게 전부입니다. 정말 간단하죠?
하지만 그 안을 들여다보면 제법 흥미로운 이야기들이 숨어 있습니다.
미리보기 패널 (The Preview Panel)
미리보기 기능이 활성화되면, peektea는 터미널 화면을 두 개의 칼럼으로 나누어 렌더링합니다.
왼쪽에는 평소처럼 파일 브라우저가, 그리고 오른쪽에는 커서가 가리키는 파일의 내용이 표시되죠.
이 패널은 네 가지 경우를 능숙하게 처리합니다.
- 텍스트 파일: 처음 N줄을 탭 확장 및 패널 너비에 맞춰 자른 후 표시합니다.
- 이미지: chafa를 통해 터미널 내에 인라인으로 렌더링합니다.
- 디렉터리: 파일 브라우저와 동일한 디렉터리/파일 스타일링을 적용하여 내용을 나열합니다.
- 바이너리 파일: 내용 대신
[binary file]이라는 안내를 표시하여 잡음이 출력되는 것을 방지합니다.
커서를 이동하면 미리보기도 함께 업데이트됩니다. 커서를 움직이면 새로운 내용이 로드되고, 디렉터리 안으로 들어가도 새로운 선택 항목의 미리보기가 즉시 표시되죠.

tea.Cmd를 활용한 비동기 로딩
미리보기 패널은 절대 TUI(Text User Interface)의 동작을 막아서는 안 됩니다. 큰 파일을 읽거나 chafa 같은 외부 명령어를 실행하는 데는 시간이 걸리니까요. 이런 작업이 UI를 블록하면 사용자 경험이 크게 저하될 수 있죠.
Bubble Tea 프레임워크에서는 시간이 걸리는 모든 작업을 tea.Cmd로 처리합니다. 이는 메인 루프와 별개로 실행되며, 작업이 완료되면 메시지를 반환하는 함수입니다.
type previewMsg struct{ content string }
func loadPreview(path string, entry os.DirEntry, width, height int) tea.Cmd {
return func() tea.Msg {
if entry.IsDir() {
return previewMsg{content: previewDir(path, width, height)}
}
if isImageExt(entry.Name()) {
return previewMsg{content: previewImage(path, width, height)}
}
return previewMsg{content: previewText(path, width, height)}
}
}
모델은 previewLoading 플래그를 true로 설정하고 이 명령어를 실행합니다. 그러면 미리보기 패널에는 loading…이라는 문구가 표시되죠. 고루틴(goroutine)에서 작업이 끝나면 previewMsg가 Update 함수를 통해 돌아오고, 패널은 그 결과를 렌더링합니다. 이 모든 과정 중에도 TUI는 완벽하게 반응성을 유지합니다. 느린 미리보기가 로드되는 동안에도 사용자는 계속해서 다른 파일을 탐색할 수 있습니다. 제가 실무에서 TUI 애플리케이션을 개발할 때 가장 중요하게 생각하는 부분 중 하나가 사용자 경험입니다. 특히 파일 탐색 같은 경우, 작은 지연도 전체적인 흐름을 방해하기 쉽거든요. 그래서 이런 비동기 처리는 거의 필수적인 패턴이라 할 수 있습니다.
chafa를 통한 이미지 미리보기
chafa는 이미지를 컬러 유니코드 블록으로 변환하여 터미널에 표시해 주는 멋진 도구입니다.
이 도구는 --size WxH 옵션을 지원하기 때문에, 출력되는 이미지가 미리보기 패널의 크기에 정확히 맞춰집니다.
func previewImage(path string, width, height int) string {
if _, err := exec.LookPath("chafa"); err != nil {
return "[image — install chafa for inline preview]"
}
out, err := exec.Command("chafa",
"--size", fmt.Sprintf("%dx%d", width, height),
path,
).Output()
if err != nil {
return fmt.Sprintf("[image preview failed: %v]", err)
}
return strings.TrimRight(string(out), "\n")
}
만약 chafa가 설치되어 있지 않다면, 패널은 사용자에게 이 사실을 알려줍니다. 애플리케이션이 충돌하거나 빈 화면만 보여주는 일은 절대 없죠. peektea init 명령어는 이제 설치 과정 마지막에 chafa의 설치 여부를 확인하고, 누락된 경우 해당 배포판에 맞는 설치 명령어를 친절하게 출력해 줍니다.
바이너리 파일 감지
바이너리 파일을 텍스트로 열면 의미 없는 잡음만 가득한 화면을 보게 됩니다. 이런 상황을 피하기 위해 peektea는 파일을 읽기 전에 바이너리 파일인지 아닌지 먼저 확인합니다.
이때 git diff나 대부분의 텍스트 에디터에서 사용하는 표준적인 휴리스틱을 사용합니다. 파일의 첫 512바이트 안에 널 바이트(null byte, ASCII 0)가 포함되어 있는지 확인하는 방식이죠.
func isBinary(path string) bool {
f, err := os.Open(path)
if err != nil {
return false
}
defer f.Close()
buf := make([]byte, 512)
n, _ := f.Read(buf)
for _, b := range buf[:n] {
if b == 0 {
return true
}
}
return false
}
만약 바이너리 파일로 감지되면, 미리보기 패널은 [binary file]이라는 메시지를 표시하고 다음으로 넘어갑니다.
터미널 크기 및 반응형 왼쪽 패널
화면을 정확하게 분할하려면 peektea는 현재 터미널의 크기를 알아야 합니다.
Bubble Tea는 터미널 크기가 변경될 때마다 tea.WindowSizeMsg를 보냅니다. 모델은 이 메시지에서 width와 height 값을 저장하고, 매 렌더링 시 패널 크기를 계산하는 데 사용합니다.
case tea.WindowSizeMsg:
m.width = msg.Width
m.height = msg.Height
왼쪽 패널의 너비는 고정되어 있지 않습니다. 최소 50자 폭으로 시작하여, 현재 디렉터리에서 가장 긴 파일 이름에 맞춰 동적으로 확장됩니다.
func (m model) leftWidth() int {
const minWidth = 50
w := minWidth
for _, e := range m.entries {
nameW := 2 + len([]rune(e.Name()))
if e.IsDir() {
nameW++
}
if nameW > w {
w = nameW
}
}
// 미리보기 패널을 위해 항상 최소 30자의 공간을 남겨둡니다.
if max := m.width - 32; w > max {
w = max
}
return w
}
긴 파일명이 많은 디렉터리로 들어가면 왼쪽 패널이 자동으로 넓어지고, 다시 나오면 원래대로 줄어듭니다. 미리보기 패널은 남은 공간을 알아서 차지하게 되죠. 사용자에게 항상 최적화된 시각 정보를 제공하려는 섬세한 노력의 결과입니다.
힌트 바 (The Hint Bar)
마지막으로, 작지만 사용자 경험을 한층 끌어올리는 디테일 하나를 소개합니다. 왼쪽 패널 하단에 있는 힌트 바가 단순히 마지막 항목 바로 아래에 떠 있는 것이 아니라, 터미널의 맨 마지막 줄에 고정되도록 했습니다.
패널은 파일 목록이 소비한 줄 수를 계산하고, 남은 공간을 공백 줄로 채워 넣어 힌트가 항상 화면 바닥에 위치하도록 합니다. 덕분에 단순한 텍스트가 아닌, 제대로 된 패널처럼 느껴져 시각적으로 훨씬 안정감을 줍니다.
다음 단계는 무엇일까요?
이제 '다음 단계' 목록이 점점 짧아지고 있습니다.
인라인 이미지 미리보기✓분할 패널 파일 미리보기✓- 타이핑하면서 필터링 — bubbles의
textinput컴포넌트가 우리를 기다리고 있습니다! - 숨겨진 파일 토글 — 도트파일(dotfiles) 표시/숨김 기능
모델이 계속 성장하고, Update 함수는 새로운 키를 처리하며, View는 새로운 상태를 렌더링하는 것.
이것이 여전히 peektea의 전체 패턴입니다. 여전히 확장 가능하며, 제 농담도 마르지 않을 겁니다. 😉

AI 에이전트들은 코드를 빠르게 작성합니다. 하지만 동시에 아무런 말없이 로직을 삭제하거나, 동작을 변경하거나, 버그를 몰래 심어놓기도 합니다. 그리고 우리는 대개 프로덕션에서야 이 사실을 알게 되죠.
git-lrc는 이런 문제를 해결하기 위해 탄생했습니다. 깃 커밋에 연동되어, 코드가 반영되기 전에 모든 diff를 검토합니다. 60초면 설정이 끝나는, 완전히 무료인 도구입니다.
어떤 피드백이나 기여자분들도 언제든 환영합니다! 온라인에서 소스 코드를 확인할 수 있으며, 누구든 자유롭게 사용할 수 있습니다.
깃허브에서 별을 눌러주세요 ⭐ {% github=https://github.com/HexmosTech/git-lrc %}
원문: https://dev.to/lovestaco/peektea-opens-a-second-eye-side-by-side-file-previews-n6j 수집일: 2026-06-03 02:32:04