Ghostty 개발 로그 005
원문은 Mitchell Hashimoto님이 에 게재했습니다. 이 블로그 구독하기
안녕하세요! Ghostty 👻 공식 개발 로그에 오신 것을 환영합니다!
마지막 개발 로그 이후 두 달이 넘게 지났고, 그동안 Ghostty에 정말 많은 업데이트가 있었습니다. 그동안 새로 아빠가 되느라 바빴고, 컴퓨터 앞에 앉을 수 있는 자유 시간은 대부분 Ghostty 개선에 쏟다 보니 개발 로그를 조금 소홀히 했습니다. 죄송합니다!
이전 개발 로그를 놓쳤거나 Ghostty가 무엇인지 더 자세히 알고 싶다면, 이 웹사이트의 Ghostty 페이지를 참고해 주세요.
커뮤니티 소식
지난 두 달 동안 베타 테스트 그룹이 100명에서 350명 이상으로 늘어났습니다! 와! 두 달 전만 해도 베타 인원은 50명도 채 되지 않았습니다. 이 터미널 프로젝트에 보내주신 관심과 함께해 주신 베타 테스터분들께 정말 감사드립니다. 이렇게 크고 계속 늘어나는 테스터 그룹 덕분에 Ghostty는 정식 출시 시점에 훨씬 더 탄탄하고 안정적인 프로젝트가 될 수 있을 것입니다.
매 차수마다 베타 그룹을 이렇게 크게 늘릴 수 있는 유일한 이유는 Ghostty가 점점 더 기능적으로 완성되고 안정적이 되어가고 있기 때문입니다. 예전에는 베타를 5명씩 초대해도 버그나 기능 요청이 열 개도 넘게 쏟아졌습니다. 이제는 50명을 초대해야 비슷한 수가 나옵니다. 그리고 이 숫자는 앞으로 더 늘어날 것입니다. 프로젝트가 점점 더 현실적이고 안정적으로 자리 잡아가는 모습을 보는 것이 정말 뿌듯합니다.
베타 프로그램 참여에 관심이 있다면 Ghostty Discord에 가입해 다음 베타 차수 대상으로 검토받아 보세요. 이 글을 쓰는 시점 기준으로 Discord 커뮤니티의 약 20%가 베타에 참여하고 있습니다.
터미널 인스펙터 (#728)
터미널은 애플리케이션 플랫폼입니다. ‘플랫폼’이라는 단어는 자신의 작업이 실제보다 더 중요하다고 믿고 싶어 하는 사람들(혹은 최소한 투자자들이 그렇게 믿게 만들고 싶어 하는 사람들)에 의해 너무 남용된다고 생각하지만, 터미널은 실제로 텍스트 기반 상호작용을 위한 플랫폼입니다1.
터미널은 그 안에서 동작하는 애플리케이션이 없으면 흥미롭지 않습니다. 더 나아가, 터미널은 그 안에서 동작하는 애플리케이션이 없으면 무의미합니다. 터미널 애플리케이션의 양과 질을 늘리는 방법 중 하나는 터미널용 개발을 더 쉽게 만드는 것입니다.
웹을 예로 들면, 제게 개발 편의성의 비약적인 도약은 Firebug의 등장으로 찾아왔습니다. 지금은 흔히 “웹 인스펙터”라고 불리며 모든 주요 브라우저에 비슷한 기능이 들어 있습니다. 터미널에도 비슷한 경험을 가져오고 싶어서, Ghostty에 이제 터미널 인스펙터가 생겼습니다.
터미널 인스펙터는 웹 인스펙터와 비슷하게 동작합니다. 터미널마다 열리는 패널로, 실행 중인 터미널에 대한 정보가 실시간으로 업데이트됩니다. 키보드 입력(과 그 인코딩 방식), 터미널 모드, 폰트 크기, 그리드 크기, 셀 메타데이터, 팔레트 색상 등 훨씬 더 많은 정보를 확인할 수 있습니다.
목표는 터미널 인스펙터가 터미널 개발자들에게 없어서는 안 될 도구가 되어, 터미널 애플리케이션을 더 쉽게 개발하고 디버깅할 수 있게 하는 것입니다(어떤 터미널에서나 동작하는 애플리케이션을 말합니다, Ghostty뿐 아니라).
터미널 인스펙터는 아직 매우 초기 단계의 실험적인 기능입니다. 현재는 완전히 읽기 전용 인터페이스지만, 앞으로는 읽기·쓰기가 모두 가능하도록 만들어 셀을 수정하거나 터미널 모드를 바꾸고, 합성 입력 이벤트를 생성하는 등의 기능을 추가할 계획입니다.
터미널 인스펙터라는 원래 아이디어는 베타 커뮤니티의 한 멤버에게서 나왔고, 저를 포함한 베타 커뮤니티 내 소규모 그룹이 빠르게 힘을 모아 이를 꽤나 구체적인 아이디어로 발전시켰습니다. 함께해 주신 모든 분께 감사드립니다!
아시아 언어 입력 (#八百八十八)
최근 베타 차수에서는 더 다양한 시간대에 있는 분들을 의도적으로 초대하려고 노력했습니다. 그 결과 중국어, 일본어, 한국어 같은 언어로 입력하는 테스터가 훨씬 많아졌습니다. 이분들 덕분에 아시아 언어 입력 및 렌더링과 관련된 문제가 10여 건 가까이 제보되었고, 그 결과 Ghostty는 이제 이들 언어에서 아주 잘 동작합니다.
개발 로그 003에서는 “Keyboard Input Handling Hates You.”라는 제목으로 키보드 입력에 대한 섹션을 다룬 적이 있습니다. 당시 Ghostty에서 얼마나 잘 동작하는지 큰소리쳤는데, 이번에는 모든 것이 얼마나 끔찍하게 복잡한지 다시 한번 강조하면서도 Ghostty가 그 모든 것을 훌륭하게 처리한다는 말을 또 한 번 하려고 합니다2.
더 복잡한 입력 상태
개발 로그 003에서 저는 데드 키 상태라는 개념을 소개했습니다. 당시 Ghostty는 단일 코드포인트에 대한 데드 키 상태를 처리했습니다. 예시로 악센트가 있는 영어 문자를 들었습니다. 예를 들어 '(아포스트로피)를 입력한 다음 a 같은 글자를 입력하면 á가 되는 식입니다.
일본어 같은 언어에서는 몇 글자를 입력하면 추천 입력이 나타나고(때로는 더 많은 추천을 담은 드롭다운과 함께) enter나 tab 같은 키를 눌러 추천을 확정합니다.
Ghostty는 여러 코드포인트로 이루어진 추천을 처리하지 못했고, 추천이 표시되는 동안 enter나 tab 같은 문자를 잘못 처리하고 있었습니다. 이제는 모두 수정되어 일본어(와 다른 언어들)를 입력할 수 있습니다.
이 여러 코드포인트 추천 상태는 몇 가지 엣지 케이스도 함께 가져왔습니다. 줄 끝에 입력하는 경우와 너무 좁은 창에서 입력하는 경우가 그것입니다. 이제 Ghostty는 이 두 경우도 모두 처리합니다. 참고로 위 영상은 또 다른 버그가 수정되기 전에 녹화된 것이니(찾을 수 있다면 찾아보세요), 그 버그 역시 이제는 해결되었습니다.
중국어 문자 정렬 (#982)
고정폭 터미널 그리드 안에서 여러 폰트(그리고 Emoji까지)를 깔끔하고 통일감 있게 렌더링하는 것은 어려운 일이며, 중국어 문자가 영 제대로 보이지 않았습니다:

草로 시작하는 단어가 약간 아래로 내려가 렌더링되는 것을 볼 수 있습니다. 이는 특정 폰트를 혼용할 때 잘못된 폰트 메트릭 계산(이 경우에는 셀 베이스라인)을 사용했기 때문이었습니다. 이제 Ghostty에서 수정되었습니다.

Linux IME 입력 (#919)
macOS는 입력기(input method editors, IME)에 대한 훌륭한 지원이 OS 자체에 내장되어 있습니다. GTK를 사용하는 Linux에서는 IME가 선택적으로 설치하는 플러그인을 통해 제공됩니다. 그래서 Ghostty에서 충분히 테스트되지 못했고, 중국어, 일본어, 한국어에서는 전혀 동작하지 않고 있었습니다.
다행히 Ghostty의 공유 코어에서 IME 지원을 위해 많은 작업을 해 두었기 때문에, Linux에서 이를 제대로 동작하게 만드는 데는 올바른 GTK와 Ghostty API를 연결하는 +47/-1 diff 정도만 필요했습니다. 그리고 그 결과 Linux에서도 IME가 동작합니다:
참고: 이 영상은 위 수정 이전에 녹화된 것이라 잘못 렌더링된 문자를 볼 수 있습니다.
커스텀 셰이더 (#903)
터미널을 고전적인 CRT처럼 보이게 하고 싶었던 적 있나요? 아니면 고장 난 VHS 테이프처럼요? 도대체 내가 무슨 소리를 하는 거지? 미쳤나? 어쨌든, 이제 Ghostty에서는 커스텀 셰이더를 지정해 이 모든 것과 그 이상을 할 수 있습니다.
실용성을 차치하고, 이런 기능은 배터리 수명에 치명적일 것 같아 보입니다. 요즘 대부분의 소프트웨어가 워낙 비효율적이라 다들 그렇게 생각하기 마련이죠! 하지만 CPU와 GPU는 엄청나게 빠르고, 이 정도는 거의 아무것도 아닌 수준입니다. 제 컴퓨터에서는 위 효과가 CPU를 약 1%, GPU를 약 2% 정도 사용합니다. 물론 이 기능을 쓰지 않을 때보다는 확실히 더 많은 전력을 씁니다(당연하죠!) 하지만 팬이 돌아갈 정도는 아닙니다.
Ghostty는 GPU로 구동되는 터미널 에뮬레이터입니다. macOS에서는 순수 Metal을, Linux에서는 OpenGL을 사용합니다. GPU는 셰이더를 호출해 렌더링합니다. 셰이더란 손을 휘저으며 GPU에서 실행되는 프로그램입니다.
셰이더는 일반적으로 기술별로 특화된 프로그래밍 언어로 작성됩니다. 예를 들어 macOS의 Metal은 MSL(Metal Shading Language)을, OpenGL은 GLSL(GL Shading Language)을 사용합니다. Ghostty는 GLSL로 작성된 셰이더를 받아 macOS에서는 즉석에서 MSL로 변환합니다. 이를 위해 Ghostty는 glslang을 사용해 GLSL을 SPIR-V(약간의 중간 표현)로 변환한 뒤, SPIRV-Cross를 사용해 SPIR-V를 MSL 같은 타깃 포맷으로 변환합니다. 이 두 도구는 노출된 C API를 이용해 컴파일하고 바인딩합니다.
이 기능의 또 다른 아주 멋진 점은 Ghostty가 Shadertoy 인터페이스를 노출한다는 것입니다. 그래서 Shadertoy의 많은 셰이더를 수정 없이 그대로 가져와 Ghostty에 적용할 수 있습니다. 더 중요한 점은, Shadertoy 자체를 Ghostty 커스텀 셰이더를 위한 실시간 인터랙티브 개발 도구로 활용할 수 있다는 것입니다!
걱정하지 마세요, 이 기능이 성능에 부정적인 영향을 주지는 않습니다. Ghostty는 멀티스레드 렌더링 아키텍처를 사용하며 프레임 사이에 충분한 유휴 시간이 있습니다. 커스텀 셰이더를 사용할 때는 유휴 시간이 줄어들지만 다른 스레드(IO 및 GUI)에는 거의 또는 전혀 영향을 주지 않습니다. 커스텀 셰이더를 사용하지 않을 때는 Ghostty가 기존과 동일한 렌더링 파이프라인을 사용하며 기존 실행에 새로운 리소스를 추가하지 않습니다(커스텀 셰이더 유무를 확인하는 불리언 체크 한 번과 빈 커스텀 셰이더 리스트를 나타내는 최소한의 메모리 사용을 제외하고는).
좋아요, 그래도 이건 완전히 쓸모없는 거 아닌가요? 가장 흔한 사용 사례는 재미이고, 그건 확실히 필수적인 건 아닙니다(그렇죠, 재미 따위 집어치우죠?). 하지만 커스텀 셰이더의 주된 실용적인 사용 사례는 접근성입니다. 커스텀 셰이더는 특정 형태의 색각 이상을 보정하거나, 대비나 밝기를 조절해 가독성을 높이거나, “돋보기” 효과를 만드는 등 여러 면에서 정말 훌륭한 방법입니다.
접근성을 다른 사람들에게 떠넘기려는 것은 아니며 다양한 접근성 기능을 일급 기능으로 만들 의향도 있지만, Ghostty에 아직 특정 기능이 없는 시나리오에서 사용자가 직접 문제를 해결할 수 있는 훌륭한 방법이기도 합니다.
Xterm 호환성 감사 및 동작 문서화 (#632)
터미널 에뮬레이터는 에뮬레이터이지만, 무엇을 에뮬레이트하는 걸까요? 전통적으로 터미널 에뮬레이터는 VT52, VT100, VT220 같은 물리적 터미널을 에뮬레이트했습니다. 실제로는 이 하드웨어가 널리 구할 수 있거나 실용적으로 사용된 지 너무 오래되어, 대부분의 최신 터미널 에뮬레이터는 그냥 서로의 동작을 대충 흉내 낼 뿐입니다. 이 때문에 서로 다른 터미널 에뮬레이터 사이에서 동작이 완전히 일치하지 않는 경우가 많고, 많은 터미널 에뮬레이터가 엣지 케이스에서 버그를 가지고 있습니다3.
xterm은 X 윈도우 시스템의 표준 터미널 에뮬레이터이며, 역사적인 터미널 동작의 골드 스탠다드로 자주 언급됩니다. 또한 xterm은 워낙 널리 사용되고 있어, 역사적인 터미널을 제외하고 보더라도 지원하는 기능들에 대해서는 그 동작 자체가 사실상 표준으로 간주될 수 있습니다.
저는 가능한 한 합리적인 범위 내에서 Ghostty가 xterm의 동작과 정확히 일치해야 한다고 결정했습니다. 이렇게 하면 프로젝트가 “왜 <feature>가 이렇게 동작하나요?”라는 질문에 일관된 답을 할 수 있습니다4
“가능한 한 합리적인 범위 내에서”란 무슨 뜻일까요? 기본적으로 기능을 구현할 때는 xterm을 따라야 한다는 뜻입니다. 특정 기능에서 버그가 보고되면 항상 “이런 상황에서 xterm은 어떻게 동작하는가?”라고 묻습니다. 그 동작에서 벗어나야 할 설득력 있는 이유가 있다면, 그때는 예외로 인정할 뿐 원칙은 아닙니다.
이를 위해 xterm의 문서화된 모든 기능을 하나씩 천천히 감사하며 Ghostty와 비교하기 시작했습니다. 그 과정에서 가능한 한 상세하게 자체 문서도 구축하고 있습니다. 이 문서에는 예상 출력과 함께 셸 스크립트 검증 케이스도 포함되어 있어, 호환성을 보장하는 종단 간 테스트를 작성할 수 있습니다. 모습은 다음과 같습니다:

터미널은 많은 기능을 지원하고, xterm의 코드베이스는 복잡하며, 이 작업은 매우 지루하기 때문에 하룻밤에 끝낼 수는 없습니다. 하지만 지난 몇 달 동안 하나씩 기능을 점검해 왔고, 그 결과 지금까지 Ghostty에서 수십 개의 버그가 수정되었고 다른 터미널에서도 수십 개의 버그가 발견되었습니다(일부는 제보했고 일부는 나중에 제보할 예정이며, 심각한 것은 없습니다).
그렇다고 해서 Ghostty가 xterm이 지원하는 모든 기능을 지원하겠다는 의미는 아닙니다. 대신 Ghostty가 가지고 있는 기능 중 xterm도 지원하는 기능에 대해서는, Ghostty는 xterm과의 최대한의 호환을 목표로 할 것입니다(타당한 이유가 있을 경우 예외는 허용됩니다).
마무리
개발 로그에서는 제가 흥미롭다고 생각하고 공유하고 싶은 몇 가지 변경 사항에 집중합니다. 개발 로그는 변경 로그가 아니며, 그저 지루한 변경 사항 목록처럼 읽히기를 원하지 않습니다. 그렇다고는 해도, 지난 두 달 동안 Ghostty 프로젝트에서 100건이 넘는 버그 수정과 개선이 있었고 Ghostty는 매일 공개 준비에 한 걸음씩 더 가까워지고 있다는 점을 짚고 넘어가고 싶습니다.
베타가 성장한 만큼 기여자 수도 늘어났습니다. 거의 50명에 가까운 분들이 Ghostty에 기여해 주셨습니다(베타 테스터 6명 중 거의 1명은 단순히 버그를 제보하는 데 그치지 않고 코드를 기여한다는 뜻입니다!). 정말 놀라운 일이며 프로젝트에 보내주신 시간과 관심에 깊이 감사드립니다.
최신 소식을 받아보고 싶다면 Twitter나 Mastodon에서 저를 팔로우해 주세요(링크는 하단에 있습니다). 이 블로그에는 RSS 피드도 있습니다.
부우. 👻
각주
투자자를 찾고 있는 것이 아닙니다. 아무도 이 문단을 그렇게 해석하지 않기를 바라지만, 그래도 말해 둬야 할 것 같아서 적습니다. 그리고 이건 “찾고 있지 않다며 윙크하는” 그런 말이 아니라, 정말 관심이 없습니다. ↩
입력 처리는 복잡하고 분명 더 많은 버그가 있을 테지만, 이제는 일본어, 한국어, 중국어를 사용하는 베타 테스터들이 Ghostty를 풀타임으로 사용할 수 있는 상태입니다. ↩
거의 어떤 터미널 에뮬레이터도
草같은 와이드 문자를 가르는 이스케이프 시퀀스를 제대로 처리하지 못합니다. 여기서 “제대로”라는 표현은 논쟁의 여지가 있는데, 명세가 없으니 각자 원하는 대로 해도 할 말이 없기 때문입니다. 달리 말하면, 동작이 극도로 일관되지 않습니다. ↩물론 이는 xterm이 구현한 기능에만 해당합니다. Kitty Graphics Protocol 같은 일부 기능은 Kitty에 의해 잘 정의되어 있으며, 그런 경우에는 가능한 한 Kitty와 정확히 일치하도록 노력합니다. ↩
글을 무작위로 읽기
댓글
로그인하고 댓글 남기기