sim이 지금 할 수 있는 일

sim이 지금 하는 일을 목적별로 묶었습니다. 각 기능에는 그 기능을 뒷받침하는 프로젝트 사양의 요구 사항 ID를 함께 적었습니다. 예정된 기능은 로드맵에만 있습니다.

숨은 것을 보여 줍니다

핵심 아이디어: 파일을 있는 그대로 보여 줍니다.

  • 보이지 않는 문자와 양방향 문자를 보여 줍니다

    오른쪽에서 왼쪽 방향 재정의 문자, 너비가 0인 공백, 제어 문자는 <U+202E>, <U+200B>, ^[처럼 마젠타 블록 위에 그려집니다. 선택 중일 때, 검색에 일치할 때, 커서 줄에 있을 때, 외부 변경 안에 있을 때, 먼 줄의 안개 속에 있을 때 등 셀이 어떤 상태이든 마찬가지입니다. 이 중 어느 것도 터미널에 그대로 전송되지 않습니다. 파일에 문자 그대로 적힌 <U+202E> 텍스트에는 블록이 붙지 않으므로 둘을 구별할 수 있습니다.

    사양: SAFE-8, UI-15

  • 아무것도 없는 것처럼 보이는 공백에 표시를 붙입니다

    줄 끝 공백은 ·, 줄 바꿈 없는 공백은 ⍽, 탭은 »로 그립니다. 어떤 코드도 쓰지 않는 기호이며, 텍스트 위에 덧그릴 뿐 텍스트의 일부가 되지 않습니다. 줄의 끝에는 기호를 붙이지 않고, -와 %는 코드에서 흔히 쓰는 문자라서 사용하지 않습니다.

    사양: UI-6

  • 외부에서 쓴 내용을 표시합니다

    sim은 열린 파일을 감시합니다. 다른 프로세스(빌드, 포매터, 도구)가 파일을 다시 쓰면 바뀐 줄이 텍스트에 표시되고, 상자에는 디스크에 변경이 몇 개 있는지 나오고, 탭에는 ↯가 표시되며, 트리에서도 그 파일에 표시가 붙습니다. 저장할 때는 먼저 파일의 해시를 비교하고, 읽은 뒤 파일이 바뀌었다면 아무것도 쓰지 않습니다. 다만 그 확인과 정확히 같은 순간의 쓰기는 빠져나갈 수 있습니다(보안 페이지 참고).

    사양: DISK-1, DISK-2, DISK-6, SAFE-5, UI-4, MARK-1

  • git HEAD 대비 변경을 한눈에

    추가, 변경, 삭제된 줄을 나타내는 거터 표시, 트리의 파일마다 붙는 상태 문자(M, A, U, D, R), 폴더에는 그 아래에서 가장 강한 상태의 문자, 브랜치, 상태 줄의 +n ~n -n. 모두 git에서 가져오며 백그라운드에서 실행되고, 키 입력 경로에는 끼어들지 않습니다.

    사양: UI-3, UI-5, UI-10

  • 저장소 자체의 설정으로는 git이 명령을 실행하게 만들 수 없습니다

    git을 실행하기 전에 sim은 git에 저장소 자체의 설정을 물어봅니다. 명령줄로 막을 수 있는 것은 꺼 둡니다. 파일 시스템 감시자, 훅, 필터, 외부 diff, 텍스트 변환은 아무것도 실행하지 않으며, 꺼 둔 설정의 수는 트리에 표시됩니다(2 git settings off). 그래도 막을 수 없는 명령을 실행할 수 있는 설정(core.sshCommand, 그런 설정을 끌어올 수 있는 include 등)이 있으면 git을 실행하지 않습니다. 트리에는 git 표시가 나오지 않고 git not run이 표시되며, 상태 줄에 원인이 된 키와 파일이 표시됩니다. git은 셸 없이, 선택적 잠금 없이, 가져오기(fetch)를 할 수 없는 상태로 실행됩니다.

    사양: MARK-1, GIT-1, GIT-2, GIT-3, GIT-5

  • 아무것도 그리지 않는 문자는 모두 보여 줍니다

    오른쪽에서 왼쪽 방향 재정의 문자와 너비가 0인 공백 외에도, sim은 태그 문자(AI 어시스턴트에게 지시를 몰래 전하는 수법), 변형 선택자(공개된 확장에 코드를 숨긴 수법), 한글 채움 문자, 소프트 하이픈, 줄 구분자, 할당되지 않은 모든 코드 포인트를 <U+E0041> 같은 형태로 그립니다. sim이 문자를 그리는 모든 곳이 대상입니다. 파일, 상태 줄, 메시지, 트리와 탭의 이름이 그렇습니다. 이모지 시퀀스, 키캡, 잉글랜드·스코틀랜드·웨일스의 깃발, Nerd Font 아이콘은 그대로 둡니다. 한자 뒤에 표의 문자 변형 선택자가 오면 그 선택자를 보여 줍니다.

    사양: SAFE-10, SAFE-11

  • 경고 블록은 문자만 표시하지 않습니다

    마젠타는 한 번 더 볼 만한 것을 뜻합니다. 숨은 문자 외에도, 글자는 어떤 주소처럼 보이는데 링크 대상은 그 주소가 아닌 Markdown 링크([https://good.example](https://evil.example))는 대상이 이 블록 위에 그려지고, 안전을 위해 git을 실행하지 않은 저장소는 트리의 블록에 git not run이라고 표시됩니다.

    사양: UI-15, MD-10, GIT-5

거부할 것은 거부하고, 텍스트는 지킵니다

명시적인 조작 없이는 누구의 텍스트도 사라지지 않으며, 파일이 에디터의 설정을 바꿀 수 없습니다.

  • 모드라인도, 설정 파일도, 플러그인도 없습니다

    설정과 명령은 파일 내용에서 절대 읽지 않으므로, 파일이 에디터의 설정을 바꿀 수 없습니다. 저장소에서 불러올 설정 파일도, 플러그인 API도 없으며, sim은 네트워크 연결을 열지 않습니다. sim이 기억하는 것은 외관, 아이콘, Markdown 보기 선택뿐이고, 각각 한 단어입니다.

    사양: SAFE-9

  • 반쯤만 쓰이는 일이 없는 저장

    저장할 때는 원본 옆에 임시 파일을 만들어(모드 0600, O_EXCL) 쓰고, fsync한 뒤 원본 위로 rename하고, 디렉터리도 fsync합니다. 그래서 옛 파일이나 새 파일 중 하나만 보이고, 둘이 섞이는 일은 없습니다. 다른 사용자가 소유한 파일, 하드 링크가 있는 파일, 읽기 전용 디렉터리에 있는 파일은 복구용 사본을 만든 뒤 제자리에서 저장합니다. sim은 다른 사람이 소유한 링크를 통해 쓰기를 거부합니다. 편집하지 않고 열었다가 저장하면 출력은 바이트 단위로 동일합니다.

    사양: SAFE-1, SAFE-2, SAFE-3, SAFE-5

  • 비정상 종료에도 텍스트를 잃지 않습니다

    저장하지 않은 변경은 최대 1초에 한 번, 전용 상태 디렉터리(0700)에 스냅샷으로 저장됩니다. 비정상 종료, kill -9, 터미널 닫기 뒤에 파일을 다시 열면 실행 취소 한 단계로 복원을 제안합니다. 잃는 작업은 최대 1초 분량입니다.

    사양: SAFE-6

  • 검색은 저장소가 좌우하는 것을 실행하지 않습니다

    sim은 PATH의 절대 경로 항목에서 ripgrep을 직접 찾아, 빈 환경과 --no-config로 실행하며, --pre는 절대 넘기지 않습니다. 그래서 저장소가 검색에 코드를 실행시킬 수 없습니다. 검색은 아무것도 쓰지 않고, 프로젝트 밖으로 나가는 심볼릭 링크도 따라가지 않습니다.

    사양: GREP-7, GREP-8

  • 텍스트가 아닌 파일은 읽기 전용으로 엽니다

    올바른 UTF-8이 아니거나 처음 8 KB 안에 NUL이 있는 파일은 이유를 보여 주며 읽기 전용으로 열리고, 잘못된 바이트는 U+FFFD로 그립니다. 화면의 텍스트가 곧 그 파일이 아니게 되므로 편집과 쓰기는 거부합니다.

    사양: SAFE-4

  • 충돌하는 저장은 두 버전을 모두 남깁니다

    저장하려는데 디스크의 파일이 바뀌어 있으면 어느 쪽 텍스트도 사라지지 않습니다. :w! 명령은 상대 버전을 상태 디렉터리에 복사한 뒤 내 버전을 남기고, :e! 명령은 내 버전의 스냅샷을 만든 뒤 상대 버전을 가져옵니다.

    사양:

  • --plain: 외부 프로세스를 실행하지 않음

    sim --plain은 핵심만 남긴 모드입니다. calm 외관, 파일 하나, 패널 없음, 자체적으로 실행하는 프로그램 없음: git도, ripgrep도, 필터도, 훅도 없습니다. root로 실행할 때와 sudoedit의 에디터로 쓸 때의 기본값이며, 상태 줄에는 plain이라고 표시됩니다.

    사양:

찾아가기와 속도

“그 파일”에서 읽기까지, 가장 적은 단계.

  • 움직이지 않는 프로젝트 트리

    sim을 실행하면 현재 디렉터리의 트리가 열립니다. 디렉터리가 먼저, 그다음에 파일이 오고, 각각 이름순으로 항상 같은 순서입니다. 펼친 상태도 마지막 그대로 유지되므로, 읽어서가 아니라 위치로 파일을 찾습니다. 디렉터리는 백그라운드에서 읽으며, 항목은 도착하는 대로 나타나고 그 위에 있는 것을 밀어내지 않습니다.

    사양: TREE-1, TREE-3, TREE-4, TREE-5

  • 떠 있는 창에서 파일과 텍스트 찾기

    Ctrl-p는 경로에 대한 퍼지 매칭으로 파일을 찾고, 일치 품질과 각 파일을 열 가능성에 따라 순위를 매깁니다. Ctrl-f는 입력하는 동안 모든 파일의 내용을 검색하며(PATH에 ripgrep이 있으면 이를 사용), 결과를 파일별로 묶고 선택한 줄을 미리 보여 줍니다. Esc를 누르면 모든 것이 원래대로 돌아갑니다.

    사양: FIND-2, FIND-4, GREP-1, GREP-5, PICK-1

  • 열 가능성이 높은 파일은 그 자리에 표시합니다

    sim은 어떤 파일을 열었는지 기억하고, 최근성과 빈도를 함께 반영해 순위를 매깁니다. 가능성이 가장 높은 다섯 개에는 트리에서 •가 붙습니다. 키 하나, .를 누르면 트리가 변경된 파일, 열려 있는 파일, 최근에 연 파일로 좁혀집니다.

    사양: MARK-2, MARK-3

  • 여러 파일, 각각이 완전한 에디터

    열린 파일마다 자기만의 실행 취소, 스냅샷, 감시, 저장을 갖습니다. 탭 바에 나열되며, 저장하지 않은 변경이 있으면 굵은 ●가 붙습니다. Tab과 Shift-Tab으로 전환합니다.

    사양: BUF-1, BUF-2, UI-4

  • 느끼지 못할 만큼 빠릅니다

    프로젝트 벤치마크(릴리스 빌드, 10만 줄 파일, 패널을 연 채 하이라이트를 켠 상태)에서 키 입력 하나는 80×24부터 240×60까지의 화면에서 p99 기준 최대 1 ms입니다. 파일이 10만 개인 저장소에서는 파일 목록을 읽기 전에 첫 프레임을 그리며, 실측값은 1.8~8.7 ms이고 요구 사항은 20 ms입니다. 느린 작업(트리 순회, git에 묻기, 하이라이트를 위한 파싱)은 모두 백그라운드 스레드에서 실행됩니다.

    사양: SPEED-1, SPEED-2

  • 바이너리는 sim 하나

    별도였던 si 바이너리가 sim으로 통합됩니다. 설치하는 명령도, 실행하는 명령도 하나입니다. 핵심은 sim-editor-core라는 라이브러리이며, sim은 그 위에 만들어져 있습니다. sim --version과 sim --help는 터미널을 건드리지 않고 출력한 뒤 종료합니다.

    사양:

  • 글자로 탭 고르기

    <Space>bp는 각 탭에 글자를 붙이고, 그 글자를 누르면 해당 파일로 이동합니다. <Space>bc는 같은 방식으로 탭을 닫으며, 수정된 파일은 절대 닫지 않습니다. 두 번째 파일이 처음 열릴 때 Tab과 Shift-Tab을 알려 주는 힌트가 표시되며, 이 키를 세 번 쓸 때까지 계속됩니다.

    사양:

  • git HEAD와 비교한 변경 트리

    <Space>ge는 HEAD와 다른 파일만 모은 트리를 엽니다. 스테이징한 것, 하지 않은 것, 추적하지 않는 것을 모두 포함하고, 파일마다 상태 문자와 +n −n을, 폴더마다 합계를 보여 줍니다. Enter를 누르면 그 파일의 HEAD 버전을 읽기 전용으로 엽니다.

    사양: GIT-1, GIT-2, GIT-3, GIT-4, DIFF-1, DIFF-3, DIFF-4

편안하게 읽기

짐작이 아니라 계산으로 정한 색과 레이아웃.

  • 내 터미널의 팔레트에서 가져오는 구문 색

    색은 터미널의 팔레트(OSC 4로 읽음)에서 가져옵니다. 색조는 유지하고 밝기만 움직여서, 배경 대비 텍스트가 |Lc| 75에 이를 때까지 조정합니다. 키워드는 빨강, 문자열과 숫자는 초록, 타입은 노랑, 함수는 시안, 주석은 회색 기울임꼴이며, 파랑과 마젠타는 코드에 쓰지 않습니다. 언어는 파일 이름, 확장자, 첫 줄로 판단하며 bat의 구문 세트를 사용합니다. zh로 색을 끌 수 있습니다.

    사양: SYN-1, SYN-2, SYN-4

  • Markdown 읽기 보기

    Markdown 파일에서는 커서가 있는 줄을 뺀 모든 줄을 읽히는 모습대로 그립니다. 강조와 코드 표시는 그리지 않고, 표는 표시 폭에 맞춰 정렬하며, 콜아웃(> [!NOTE])은 종류의 이름을 보여 줍니다. 숨기는 것은 이런 표시뿐이고 #, 괄호, URL, 본문의 문자는 절대 숨기지 않습니다. <Space>um으로 원문을 볼 수 있습니다.

    사양: UI-8, MD-1, MD-10, MD-11

  • 세 가지 외관

    calm은 가장 담백한 외관으로, 스타일 네 가지와 유채색 배경 하나만 씁니다. flat은 diff를 초록과 빨강으로 보여 주고 줄에 옅은 색을 입힙니다. 기본값인 depth는 상자, 개요 눈금자, 커서에서 멀수록 글자를 흐리게 하는 안개를 더합니다. zl로 차례로 전환합니다. 빨강과 초록을 구별하기 어려운 사람에게는 calm이 맞는 외관입니다.

    사양: LOOK-1, LOOK-2, LOOK-3

  • 측정으로 확보한 가독성

    본문은 |Lc| 90, 보조 텍스트는 |Lc| 60(APCA)이며, 터미널의 배경색에서 계산합니다. calm에서는 하나뿐인 변경 색이 protan, deutan, tritan 색각에서도 구별됩니다. 인터페이스 전체에서 하나의 색조는 하나의 뜻만 가집니다. 회색은 구조, 파랑은 조작하는 곳, 초록·호박색·빨강은 변경, 마젠타는 숨어 있거나 위험한 것에만 씁니다.

    사양: VIS-4, VIS-5, COLOR-1, UI-12

  • 오래 머물 수 있는 에디터

    트리의 아이콘(Nerd Font 필요, zi로 끌 수 있음), 탭 바, 에디터의 제목이 되는 이동 경로(src › sim.rs › leader_key), 모드·브랜치·HEAD 대비 변경·위치를 보여 주는 상태 줄(인코딩과 줄 끝 형식은 UTF-8이나 LF가 아닐 때만 표시), 상대 줄 번호, 들여쓰기 안내선, 표시가 달린 스크롤바, 방금 복사(yank)한 부분에 번쩍이는 효과.

    사양: UI-2, UI-5, UI-6, UI-10, UI-11

  • 일본어를 비롯한 CJK 텍스트

    폭이 넓은 문자는 두 칸으로 계산하고, 문장은 일본어 금칙 처리 규칙에 따라 줄바꿈하며, 단어 단위 이동은 문자 체계가 바뀌는 곳에서 CJK 텍스트를 나눕니다. IME를 켠 상태에서도 전각 키가 명령으로 동작합니다.

    사양: VIS-7, VI-10

  • 색이 없어도 쓸 수 있고, 색에만 의존하지 않습니다

    NO_COLOR와 8색 미만의 터미널에서는 굵기, 밑줄, 반전만으로 그리며, sim은 터미널에 색을 요청하지 않습니다. 의미가 색에만 의존하는 일은 없습니다. 변경된 줄은 거터에 ┆로 표시되고, 폴더에는 가장 강한 git 상태의 문자가, 디스크에서 바뀐 파일의 탭에는 ↯가 표시됩니다. 아이콘을 끄면 개인 사용 영역의 글리프는 하나도 그리지 않습니다.

    사양:

  • Nerd Font가 있을 법한 터미널에서는 아이콘이 켜진 채 시작합니다

    아이콘에는 Nerd Font가 필요한데, 터미널은 그것이 있는지 알려 주지 않습니다. 그래서 Ghostty, kitty, WezTerm에서는 켜진 채로, 그 밖의 터미널에서는 꺼진 채로 시작하며, 상태 줄에 한 번만 힌트가 나옵니다: zi: icons (needs a Nerd Font). zi로 마지막에 고른 설정이 언제나 우선합니다.

    사양:

  • 복사하면 어떤 외관에서든 빛납니다

    방금 yank한 부분은 150 ms 동안 빛납니다. 가장 담백한 calm 외관도 이제 빛납니다. 선택 영역의 회색으로, 선택 영역이 없는 곳에서는 밑줄로 표시합니다. 다른 프로세스가 방금 열린 파일에 쓴 줄은 400 ms 동안 빛납니다.

    사양: UI-13, UI-19

키

vi 문법에서 vi의 변칙만 뺐습니다.

  • 손에 익은 vi 키

    모션, 오퍼레이터, 텍스트 오브젝트, 횟수, ., 비주얼 모드, smartcase 검색, :s와 범위 지정을 갖추되 vi의 변칙은 뺐습니다. Y는 줄 끝까지 yank하고, U는 다시 실행(redo)이며, Ctrl-s는 저장, q는 종료입니다. 방향키, Home, End, Delete는 어디서나 동작합니다.

    사양: VI-1, VI-2, VI-3, VI-4, VI-5, VI-6, VI-7

  • 복사(yank)한 내용이 시스템 클립보드에 닿습니다

    레지스터 이름이 없는 모든 yank는 OSC 52를 통해 시스템 클립보드에도 들어가며, tmux 안에서도 마찬가지입니다. 삭제와 변경은 레지스터만 채우므로, x와 dd로 복사해 둔 내용이 덮어써지는 일은 없습니다.

    사양: VI-8

  • 놀랄 일 없는 마우스

    클릭하면 파일을 열거나 커서를 놓고, 휠로 스크롤하며, 드래그로 선택합니다. 마우스가 혼자서 편집하거나 저장하거나 스냅샷을 만드는 일은 없습니다.

    사양: PTR-1, PTR-2

  • 리더 키는 Space, which-key 창이 함께합니다

    접두 키(Space, g, z, Z, [, ] 또는 d 같은 오퍼레이터)에서 잠시 멈추면, 다음에 올 수 있는 키를 나열한 작은 창이 열립니다. 계속 입력하면 창이 없을 때와 똑같이 동작합니다.

    사양:

  • 검색이 현재 위치를 알려 줍니다

    검색 결과가 강조 표시되어 있는 동안, 상태 줄에 커서가 몇 번째 결과에 있는지와 전체 개수가 [3/12]처럼 표시됩니다.

    사양:

  • Vim 레지스터

    "a부터 "z까지는 텍스트를 담고, "A부터 "Z까지는 거기에 덧붙입니다. "0은 마지막 yank, "1부터 "9까지는 최근의 삭제, "_는 무엇이든 받고 아무것도 담지 않습니다. :registers로 목록을 볼 수 있습니다. 레지스터는 메모리에만 있고 열려 있는 모든 파일이 함께 씁니다. 이름 없는 yank는 여전히 OSC 52로 시스템 클립보드에 닿고, 삭제는 닿지 않습니다.

    사양: VI-15

  • 마크

    ma부터 mz까지는 파일에 마크를 찍습니다. 'a는 그 줄로, 백틱 키는 정확한 위치로 이동하며 연산자와도 쓸 수 있습니다(d'a). ''는 마지막 점프 전에 커서가 있던 곳으로 돌아갑니다. 마크는 편집, 실행 취소, 외부에서 온 변경을 거쳐도 찍힌 텍스트를 따라갑니다. :marks로 목록을 봅니다. 마크는 메모리에만 있습니다.

    사양: VI-17

  • :tutor

    스크래치 버퍼에서 진행하는 약 15분 분량의 짧은 레슨입니다. 언어는 로캘에 따라 정해집니다(English, 日本語, 简体中文, 繁體中文, 한국어, Español, Português, Français, Deutsch, Русский. 그 밖에는 English). 연습 문제는 입력하는 대로 ✗와 ✓가 저절로 바뀝니다.

    사양: TUTOR-1, TUTOR-2, TUTOR-3, TUTOR-4

로드맵

예정된 항목으로, 아직 제공되지 않았습니다. 이 목록의 어느 것도 아직 쓸 수 없으며, 순서는 약속이 아닙니다.

  • 매크로

    예정

    키 입력을 기록하고 재생합니다. 지금의 sim에는 없습니다.

  • 클립보드 연동

    예정

    지금처럼 OSC 52로 yank하는 것 이상의 연동입니다.

  • 샌드박스 안에서 실행되는 언어 서버

    예정

    서버가 샌드박스 안에서 실행되는 언어 서버 클라이언트와, 프로젝트 루트를 신뢰하는지 여부를 상태 줄에 보여 주는 표시입니다.

  • 진짜 깊이감을 가진 GUI

    예정

    실제 그림자와 고도(elevation)를 가진 그래픽 프런트엔드입니다. 프로토타입으로 시작했으며, 설치할 수 있는 것은 아직 없습니다.

  • 더 많은 설치 방법

    예정

    AUR 및 crates.io 패키지는 곧 공개됩니다.