1P by GN⁺ 4시간전 | ★ favorite | 댓글 3개
  • 기존 Howl 에디터의 한계(개발 중단, 느린 검색, SSH 비호환, 터미널 미지원)로 인해 직접 새로운 TUI 텍스트 에디터를 개발함
  • Helix, VS Code, Vim, Neovim, Emacs 등 13개 에디터를 시도했으나 원하는 조작 감각(Fingerspitzengefühl) 을 충족하는 에디터가 없었음
  • 초기에는 개인 맞춤형 최소 기능만 구현하고, 성능·유니코드·다국어 지원 등은 후순위로 두며 점진적으로 확장함
  • 개발 과정에서 자체 정규식 엔진, 파일 브라우저, TUI 기반 렌더링, 터미널 버퍼 통합 등을 직접 구현함
  • 프로젝트 전역 검색, 구문 강조, 캐시 처리, 멀티스레드 작업 분배 등에서 성능 최적화 기법을 다수 적용함
  • 결과적으로 자신만의 워크플로에 완벽히 맞는 도구를 완성하며, 생산성과 프로그래밍에 대한 즐거움을 되찾았다고 밝힘

기존 에디터의 한계와 대안 탐색

  • 약 10년간 사용한 Howl 에디터의 문제점이 직접 개발하게된 계기
    • 수년간 개발이 중단되어 직접 포크를 유지해왔으나, MoonScript로 작성되어 깊이 있는 수정이 어려웠음
    • 프로젝트 전체 파일 검색 성능이 부족해 작업 흐름이 끊기는 문제 발생
    • GUI 에디터여서 SSH 연결을 통한 원격 사용이 불가
    • 통합 터미널이 없어 외부 명령 실행 시 라이브 상호작용 불가, ANSI 이스케이프 코드 대부분 미지원
  • Helix, VS Code, Sublime Text, Vim, Zed, Neovim, Emacs, Geany, Micro, Lite XL, Lapce, GNOME Builder, Kakoune 등 13개 에디터를 시도
    • 각각 장점이 있었으나, 원하는 조작 감각(Fingerspitzengefühl) 을 충족하지 못함
    • Helix를 가장 오래 사용했으나 한 달 후 흥미를 잃음

초기 개발 전략

  • 시작 단계에서 범위를 최소한으로 제한
    • 자신 외의 사용자를 위한 기능 배제, 모든 설정을 하드코딩
    • 성능 최적화는 미루고 String 기반 버퍼로 시작
    • 유니코드 그래핌 완전 지원 배제, £ 기호가 단일 컬럼을 차지하면 충분하다는 판단
    • 구문 강조는 주로 사용하는 소수 언어만 지원, 나머지는 범용 구분자 기반 강조로 대체
  • 두 번째 시도에서 간단한 TUI 프레임워크를 먼저 구축했으나, 시간이 지나며 대부분을 걷어내고 더 직접적이고 세밀한 접근으로 전환

Dogfooding 실천

  • 에디터가 단일 파일을 열고 편집·저장할 수 있는 최소 기능 임계점에 도달한 후 세 가지 실천을 시작
    • nano 대신 자체 에디터를 사용하여 시스템 파일 편집이나 메모 작성 시 강제로 사용
    • 빠진 기능, 버그, 이상 동작, 한계를 발견할 때마다 프로젝트 README.md에 기록
    • 짜증이 날 정도의 문제는 즉시 수정
  • 이 세 가지 실천으로 작업량이 월 1시간에서 주 수 시간으로 증가
  • 전체 약 10,000줄의 코드 중 거의 대부분이 최근 6개월 내에 작성됨

커서 조작

  • 커서 조작은 구현 난이도가 높은 영역
    • ctrl + shift + left 같은 키 조합의 동작은 사용자에게 당연하지만 로직 구현은 복잡
  • 고수준 입력을 원시 연산의 조합으로 구현하는 것이 핵심 조언
    • 예: 단어 단위 백스페이스 → 단어 단위 커서 이동 + 범위 선택 + 삭제로 분해
  • undo/redo 구현 시 이 3개 동작을 하나의 그룹으로 묶어야 직관적 결과 보장
  • 모달 에디터가 이런 원시 연산을 사용자에게 직접 노출하는 이유가 이해됨

파일 브라우저

  • Howl의 파일 브라우저가 다른 에디터로 넘어가지 못한 결정적 이유
    • 즉시 업데이트되는 퍼지 필터가 탁월하여, 1~2 키 입력만으로 원하는 파일 검색이 대부분 가능
    • 파일이 존재하지 않으면 인라인으로 생성 가능
    • ~/ 입력 시 홈 디렉토리로 자동 전환
    • 메인 편집 창에서 열려는 파일의 미리보기 표시
  • 다른 에디터들이 파일 열기 문제를 마우스 의존, GTK 기본 대화상자, 파일명 추측 등으로 해결하는 것에 대한 불만
  • 자체 구현 시 Levenshtein distance 같은 복잡한 방식 대신 단순 기준 3가지로 충분
    • 필터 구문으로 시작하는지 여부
    • 필터 구문을 포함하는지 여부
    • 가장 최근 수정/접근 시간
  • 대소문자 무시 매칭을 허용하되, 대소문자 일치 시 순위를 약간 상향
  • 수만 개 파일이 있는 프로젝트에서도 2 키 입력 후 약 95% 확률로 상위 2개 안에 원하는 파일 위치

정규식 엔진

  • 정규식은 프로젝트 전체 검색, 구문 강조, 버퍼 내 찾기 세 곳에서 사용
  • 기존 regex-automata 크레이트 대신 직접 구현한 이유
    • Rust의 raw string 문법 같은 컨텍스트 민감 엣지 케이스 처리 필요
    • 프로젝트 자체가 자체 스택 구축과 이해를 위한 연습
  • 초기 구현은 파싱 크레이트 chumsky로 정규식 구문을 파싱하고 AST를 매 문자마다 순회하는 느린 방식
  • 이후 단계적 최적화 수행
    • 단일 패스 옵티마이저: 반복 출현하는 문자 매칭 그룹을 단일 String 노드로 변환하여 정확한 문자열 검색 수행
    • 공통 접두사 추출: 예를 들어 hel[(lo)p]에서 공통 접두사 hel을 발견하여 해당 위치에서만 매칭 수행 → 프로젝트 전체 검색에서 큰 성능 향상
    • AST 워커를 Rust 동적 호출 기반의 threaded code VM으로 재구현
    • threaded code VM을 CPS(Continuation-Passing Style) 형태로 변환, 각 VM 명령이 후속 명령을 tail-call하여 컴파일러 최적화 활용
    • Rust의 느린 동적 함수 호출을 vtable 룩업 없이 래핑, 많은 정규식 명령의 코드젠이 몇 개의 기계어 명령으로 축소
    • 가능한 한 많은 정규식 명령을 유니코드 코드포인트 대신 바이트 단위로 구현, UTF-8 설계 덕분에 ASCII 최적화 기법이 멀티바이트 코드포인트에서도 유효
  • jump LUT 체인으로의 컴파일도 시도했으나, 벤치마크 결과 threaded code 대비 20~30% 빠른 정도에 불과하고 유연성이 크게 저하되어 채택하지 않음
  • 최종 결과: Rust용 가장 복잡한 구문 강조에서 50,000줄짜리 자동 생성 바인딩 파일을 클린 상태에서 10밀리초 미만에 전체 강조 완료

구문 강조 캐시

  • 초기에는 매 변경마다 전체 파일을 재강조하는 방식이었으나, 큰 파일에서 성능 저하 발생
  • 온디맨드 토큰 강조 캐시 구현
    • 대략 동일한 크기의 청크 단위로 토큰을 강조
    • 버퍼에 변경(damage)이 발생하면 해당 위치와 겹치거나 이후의 청크만 무효화
  • 가장 비관적인 경우(대형 파일 중간 편집)에도 damage 이전의 강조 상태는 유지되고, 화면 아래쪽 이후는 강조 정보가 요청되지 않아 처리 불필요
  • 수요 기반(demand-driven) 접근이므로, 동일 버퍼의 서로 다른 부분을 보는 복수 패널에서도 정상 동작

프로젝트 전체 검색

  • 검색 프로세스 4단계
    • 현재 디렉토리에서 역방향으로 .git/ 디렉토리를 찾아 프로젝트 루트 결정
    • 프로젝트 루트의 모든 디렉토리를 재귀 순회하며 검색 패턴을 파일 내용에 매칭
    • 각 양성 매칭에서 파일 스니펫을 추출하고 결과 미리보기를 위해 구문 강조 적용
    • 현재 경로로부터의 탐색 거리에 따라 결과 순위 결정 (가까운 파일일수록 높은 순위)
  • 빌드 디렉토리 등을 피하는 기본 필터링 규칙 적용
  • 멀티스레드 처리로, 기본적인 work-stealing 방식으로 스레드 간 작업 할당
    • 모든 스레드가 소비자이자 생산자인 특수한 구조에서 종료 감지 문제 해결
    • 대기 중인 스레드가 원자적 카운터를 증가시키고, 카운터가 워커 수에 도달하고 작업 큐가 비면 전체 종료
  • 정규식 최적화와 현대 SSD 속도 덕분에 Veloren 같은 큰 코드베이스에서도 단순 패턴 검색이 거의 즉시 완료
  • 플레임그래프 상 대부분 IO 바운드 상태
  • 에디터 내에서 대형 코드베이스를 사고 속도로 검색할 수 있는 것이 생산성에 큰 기여

터미널 에뮬레이터 버퍼

  • 패널 기반 에디터에서 하나의 패널을 터미널 창으로 사용하는 기능의 편의성이 큼
  • ANSI 파서를 직접 구현하려 했으나, OSC52, Kitty 키보드 확장 등 최신 터미널 렌더링 기능 지원이 방대
  • alacritty_terminal 크레이트를 활용하여 Alacritty 터미널 에뮬레이터의 이스케이프 시퀀스 파서 및 터미널 상태 관리 로직을 재사용
  • 결과적으로 screen/tmux의 핵심 기능을 대체할 수 있으며, 더 풍부한 이스케이프 시퀀스 지원 제공

렌더링 최적화

  • TUI 기반이지만 원격 모바일 연결 시 대역폭이 여전히 중요
  • 더블 버퍼링: 터미널 화면의 내부 복사본을 이중으로 유지
    • 재그리기 시 이전 프레임과 비교하여 변경된 셀만 ANSI 이스케이프 시퀀스 출력
    • 커서 이동, 스타일 모드 변경 등의 시퀀스도 실제 필요할 때만 출력
  • 대부분의 터미널 에뮬레이터(Ghostty 제외)에서, 에디터의 터미널 패널에서 대형 파일을 cat한 후 에디터를 닫는 것이 호스트 터미널에서 직접 cat하는 것보다 더 빠름
    • alacritty_terminal이 호스트 터미널에 대한 stdout 바이트 처리 비용을 차단해주기 때문

결론: 자신만의 도구를 만들 것

  • 직접 만든 에디터는 내 작업 흐름에 완벽히 맞는 도구로 자리 잡았음
  • 자체 에디터/도구 제작이 무의미한 고통이라는 통념에 반대
  • 네 가지 이점
    • 완벽한 맞춤: 원하는 동작만 수행, 그 이상도 이하도 없음
    • 다양한 기술 학습: 정규식, ANSI, 의사터미널(pty), TUI 디자인, UTF-8의 세부 사항 등 범용적으로 유용한 기술에 대한 깊은 이해 획득
    • 장기적 생산성 향상: 자신의 도구를 완벽히 이해하고 개인 워크플로에 맞춘 기능을 내장하여, 도구와의 마찰 감소
    • 순수한 즐거움: 자기완결적인 문제들을 해결하고 그 결과를 손끝으로 느끼는 경험이 프로그래밍에 대한 사랑을 다시 불러일으킴, 수년 만에 코딩하며 활짝 웃고 혼자 웃음이 나는 경험
  • 텍스트 에디터가 아니어도 좋으니 자신만의 도구를 만들 것을 권장하며, 어려운 부분을 통계 상자(AI 등)에 넘기지 말고 도전 자체를 즐길 것을 강조

사실 이 글에서 제일 놀라운건 한 단어네요.

Fingerspitzengefühl

Finger(손가락) + Spitzen(끝) + Gefühl(감각)

손가락 끝의 조작 감각을 나타내는 단어가 있는 독일어는 정말.. 하..

무한으로 단어조합이 가능한 독일어죠 ㅎㅎ

Hacker News 의견들
  • 읽는 내내 즐거웠음. 친구들에게도 직접 텍스트 에디터를 만들어보라고 권하고 있음
    나는 ‘Left’라는 내 에디터를 거의 10년째 쓰고 있음. 처음엔 완벽하지 않았지만, Left로 Left를 수정하며 발전시켜왔음. 매일 아침 내 손으로 만든 도구를 열 때 느끼는 기쁨이 그 시간의 20배는 보상해줌

    • 나도 10년 넘게 개인용 에디터를 써오고 있음. 나에게 딱 맞는 도구로 하루를 보내는 건 정말 편안한 느낌임
    • 나는 19년째 내 에디터 ‘aoeui’를 쓰고 있음. 내 생산성 향상에 가장 큰 영향을 준 선택 중 하나였음
    • 어떤 기능들이 가장 중요했는지 궁금함. 여러 워크플로우를 지원하도록 설계했는지도 알고 싶음
  • “인생에서 한 번은 집을 짓고, 나무를 심고, 에디터를 만들어야 한다”는 말이 있음. 나는 마지막 것부터 시작했음
    PicoLisp 기반 Vi 스타일 에디터 Vip에 나오는 문구임

  • 나도 처음부터 직접 텍스트 에디터를 만들어봤음. 기능이 많아서 LSP, tree-sitter, fzf 같은 외부 도구를 적극 활용했음.
    suckless 스타일로 간단히 코드 수정만으로 커스터마이즈할 수 있게 설계했음.
    처음 몇 주는 버그 천지였지만, 고칠수록 점점 안정되어감. 내 프로젝트 hat 참고 가능함

    • 맞음. 과거의 수정과 개선이 쌓여서 미래의 생산성 가속으로 이어질 때 정말 뿌듯함
  • 혹시 텍스트 편집 라이브러리 추천할 만한 게 있을까?
    GUI가 필수라 폰트 렌더러와 그래픽 컨텍스트까지 직접 다뤄야 함.
    단순한 콘솔용으로는 내가 쓸 수 없고, GUI만 만들면 편집 기능이 없으니 둘 다 필요함.
    놀랍게도 이런 요구를 충족하는 순수 API 형태의 라이브러리를 찾기 어려움.
    대부분 완성된 에디터이거나, 거대한 프레임워크 수준임.
    단순히 대용량 텍스트 파일을 빠르게 처리할 수 있는 기본 편집 엔진만 있으면 좋겠음

    • 요즘 터미널 에뮬레이터가 얼마나 강력한지 놀랐음. 클립보드, 마우스 이벤트, 포커스 추적, 알림 등 거의 다 가능함.
      trolley 같은 도구로 ghostty 기반 네이티브 UI처럼 감쌀 수도 있음
    • 여러 경량 GUI 에디터가 Scintilla 위에 구축되어 있음. GTK, Windows, Mac 모두 지원함. 다만 기능이 많아 단순 API로 쓰기엔 과할 수도 있음
    • stb_textedit.h도 있지만 추천하진 않음. UTF-8 처리나 단어 경계 탐지 등 제약이 많음.
      대신 SDL과 SDL_ttf 조합은 꽤 괜찮은 선택임. SDL3_ttf는 문자열 처리도 개선됨
    • 플랫폼에 따라 다르겠지만, GUI 렌더링이 목적이 아니라면 raylib이 좋은 대안일 수 있음
  • antirez의 “kilo” 에디터를 다시 구현해봤음.
    원본 코드튜토리얼이 잘 되어 있어서, 터미널 모드와 C 언어의 기본기를 배우기에 훌륭한 프로젝트였음

  • 90년대에 COBOL과 ASM 파일을 위해 직접 에디터를 만든 추억이 있음.
    문법 강조, 빠른 버퍼링, 스크린세이버까지 있었음.
    펜티엄 120에서 돌아갔는데, 지금의 VSCode보다 천 배는 빨랐던 기억임

    • 나도 VB6로 에디터를 만들었음. 2002년 마케팅 페이지에는 “무제한 템플릿, 컬러 인쇄, 정규식 찾기/바꾸기, 코드 완성” 같은 기능이 나열되어 있었음.
      그땐 HTML 태그를 전부 대문자로 썼음
    • 오래된 노트북에서 VSCode를 켜면 너무 느려서 마음이 아픔. 나는 vim 세대지만, 요즘 사람들에게 그걸 추천하기는 어렵다고 느낌
    • 참고로 Borland Turbo Pascal과 Turbo C도 여러 파일을 동시에 열 수 있었음
  • 이 글의 주인공이 만든 에디터 zte

  • “어려운 부분을 통계 상자에 밀어넣으려는 유혹을 참으라”는 문장이 정말 인상 깊었음

  • 나도 내 자체 에디터를 씀. 다른 사람들은 별로 관심 없지만, 직접 만든 도구에서 얻는 가치가 큼

    • 나도 내 프로그래밍 언어로 만든 에디터를 씀. 다행히 운영체제는 직접 만들 필요가 없어서 다행임
    • 기존 에디터를 수정해 내 입맛에 맞게 썼음. 이미지 로딩과 스크립팅 기능도 있고, HTML 태그 매칭 색상 표시도 있음.
      F5로 링크를 열 수 있는 간단한 ‘브라우저’ 기능도 있음
    • 링크를 안 남겼네 :(
    • 나도 내 에디터를 씀. 친구들이 화면을 보고 “그게 뭐야?”라고 물을 때마다 뿌듯함
  • Josh Barretto는 Super Mario 64 GBA 포트를 만든 천재임. 그의 에디터라면 기꺼이 써보고 싶음

    • 그의 SM64 영상들을 좋아함. 궁금한 사람은 이 최신 영상을 보면 됨