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

草로 시작하는 단어가 조금 낮게 렌더링되는 것을 볼 수 있습니다. 특정 글꼴을 섞어 사용할 때 잘못된 글꼴 메트릭 계산(이 경우에는 셀의 기준선)을 사용한 것이 원인이었습니다. 이제 Ghostty에서 이 문제가 해결되었습니다.

Linux IME 입력 (#919)
macOS는 운영체제에 입력기(IME)가 훌륭하게 내장되어 있습니다. Linux의 GTK에서는 선택적으로 설치하는 플러그인이 입력기를 제공합니다. 이 때문에 Ghostty에서 충분히 테스트되지 않았고, 중국어, 일본어, 한국어에서는 아예 작동하지 않았습니다.
다행히 Ghostty 공용 코어에서 IME를 지원하기 위해 많은 작업을 해 두었기 때문에, Linux에서 제대로 작동하게 만드는 데에는 적절한 GTK API와 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의 기본 기능으로 직접 제공하는 데에도 열려 있습니다. 하지만 Ghostty에 아직 특정 기능이 없는 상황에서 사용자가 직접 문제를 해결할 수 있도록 해 주는 좋은 방법입니다.
Xterm 호환성 감사 및 동작 문서화 (#632)
터미널 에뮬레이터는 에뮬레이터인데, 무엇을 에뮬레이트하는 걸까요? 전통적으로 터미널 에뮬레이터는 VT52, VT100, VT220 같은 물리적 터미널을 에뮬레이트했습니다. 하지만 실제로는 이런 하드웨어를 쉽게 구할 수 있거나 실용적으로 사용한 지 너무 오래되어서, 오늘날 대부분의 터미널 에뮬레이터는 서로의 동작을 그저 흉내 내는 수준입니다. 그러다 보니 터미널 에뮬레이터마다 동작이 조금씩 달라지고, 많은 터미널 에뮬레이터에 예외 상황과 관련된 버그가 존재합니다3.
xterm은 X 윈도 시스템의 표준 터미널 에뮬레이터이며, 역사적인 터미널 동작의 사실상 표준으로 자주 평가받습니다. 또한 xterm은 충분히 널리 사용되고 있기 때문에, 역사적인 터미널을 고려하지 않더라도 xterm이 지원하는 기능에 대해서는 그 동작을 사실상의 표준으로 볼 수 있습니다.
가능하고 합리적인 경우라면 Ghostty가 xterm의 동작과 정확히 일치해야 한다고 결정했습니다. 이렇게 하면 "왜 <feature>가 이렇게 동작하나요?"라는 질문에 일관된 답을 제시할 수 있습니다4.
"가능하고 합리적인 경우"라는 말은 무슨 뜻일까요? 기능을 구현할 때 기본적으로는 xterm과 동작을 맞춰야 한다는 뜻입니다. 어떤 기능에 버그가 보고되면 항상 "이 상황에서 xterm은 어떻게 동작하나요?"라고 묻습니다. xterm의 동작과 달라야 한다는 설득력 있는 근거가 있다면 예외로 인정할 수 있지만, 그것이 기본 원칙은 아닙니다.
이를 위해 xterm에 문서화된 모든 기능을 하나씩 천천히 점검하고 Ghostty와 비교하기 시작했습니다. 그 과정에서 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와 정확히 일치하도록 노력합니다. ↩
글을 무작위로 읽기