Emacs에서 모달 편집, 이동·검색·킬 명령, 레지스터, 프로젝트 단위 작업 등으로 코드 편집 효율을 높이는 방법을 정리한 글
코드를 작성할 때는 코드 그 자체에 집중하고 싶지, 코드의 “텍스트”에 신경 쓰고 싶지는 않다. 이를 위해서는 a) 좋은 텍스트 편집 환경을 갖추어야 하고, b) 그 환경을 근육 기억 수준으로 자연스럽게 사용할 수 있어야 한다. 두 번째는 연습과 일관성(즉, 설정을 너무 자주, 너무 크게 바꾸지 않는 것)으로 해결된다. 여기에서는 첫 번째, 즉 편집 환경에 대해 이야기한다.
이 글은 이미 Emacs를 사용하고 있거나, 최소한 Emacs에 조금은 익숙한 사람들을 대상으로 한다. 증분 검색이 어떻게 동작하는지, 컴파일 버퍼가 무엇인지 같은 Emacs 기초는 길게 설명하지 않을 것이다(그런 부분은 Mastering Emacs을 권한다). 대신, 특정 패턴을 권장하거나 말리는 이유, 즉 내가 한 선택의 근거를 설명한다.
이 글은 두 가지 관점에서 읽을 수 있다. 첫째, 프로그램 텍스트를 효율적으로 편집하기 위해 사용하는 일반적인 Emacs 명령 목록. 둘째, 그 명령들을 최대한 편하게 쓰기 위해 내가 모달 ‘명령(command)’ 모드에 어떻게 키바인딩을 해 두었는지에 대한 설명.
모든 텍스트 편집 습관의 핵심은, 손가락이 하는 일을 최소화하는 것이다. 즉 키 입력 수를 줄이고, 손가락을 가능한 한 항상 홈 포지션 근처에 두는 것이다. 이 말은 곧 방향키를 쓰지 말고, 마우스를 쓰지 말라는 뜻이다. 방향키를 ignore로 리매핑하고, disable-mouse 패키지를 설치해서 이를 강제할 수 있다.
코드를 편집하는 일은 산문을 쓰는 것과 다르다. 코드는 실제로 텍스트를 입력하는 시간보다, 문서 사이를 이리저리 이동하고, 문서 안에서 내용을 옮기는 데 더 많은 시간을 쓴다. 즉, 이동을 위한 동작이 입력 동작보다 더 중요하며, 그러므로 더 손쉽게 쓸 수 있어야 한다. 이것이 *모달 편집(modal editing)*의 전제다. 기본 ‘모드’에서는 대부분의 키가 문자를 입력하는 대신 커서를 이동시키는 역할을 한다. 예를 들어 기본 모드에서 a를 누른다고 해서 a 문자가 입력되는 것이 아니라, 커서를 줄의 시작으로 옮긴다. 실제로 텍스트를 입력하려면 ‘insert’ 모드로 들어가기 위한 특별한 키를 누른다. 다 입력하고 나면 다시 다른 키를 눌러 기본(‘command’) 모드로 돌아온다.
내 모달 시스템은 직접 작성한 스크립트로, 매우 가볍다. 키바인딩을 제외하면 약 150줄 정도다. 내 것을 쓰지 않더라도 어떤 모달 시스템이든 쓰길 권한다. 예를 들면 Evil이나 Meow 같은 것들이다. 만약 이런 방식이 정말 싫다면, 여기서 설명하는 모든 것을 바닐라 emacs에서도 그대로 할 수 있다. 대부분의 명령은 이미 기본 키바인딩이 있다. 내가 사용하는 ‘커스텀’ 함수는 네 개뿐이다: 반 페이지 스크롤 두 개, 그리고 단어/sexp 전체를 kill하는 함수 두 개. 모두 아주 단순하다.
설정을 많이 커스터마이즈하면, 다른 사람의 Emacs를 잠깐 빌려 쓸 때 곤란해진다. 몸에 밴 키 조합이 전부 빗나가기 때문이다. 이 문제는 “시스템의 언어”를 가능한 한 지키는 쪽으로 완화할 수 있다. Emacs에는 꽤 명확한(좋은지는 논외로) 키 관례가 있다. f는 forward, n은 next, C-g는 항상 cancel 같은 식이다. 내 설정은 가능한 한 이런 관례를 따르려 한다. command 모드에서 f는 ‘forward-word’, n은 ‘next line’이다.
또한 insert 모드에서는 거의 리매핑을 하지 않는다. 바닐라 Emacs에서 편집하는 것과 내 설정의 insert 모드에서 편집하는 것이 거의 같다. 내 설정에서도 insert 모드 안에서 꽤 많은 시간을 이동에 쓰게 되므로, muscle memory를 잃어버리지 않을 것이다.
화면 주변을 이동할 때 가장 자주 쓰는 동작은 command 모드에서 1글자 키로 쓴다. 예를 들어 다음 줄로 가려면 n, 단어 앞으로 가려면 f를 누른다.
덜 자주 쓰지만 그래도 중요한 명령은 보통 두세 글자 조합이다. 예를 들어 파일 저장은 vs, 단어 kill은 kf이다. 이런 경우 첫 글자는 ‘리더(leader)’ 키다. 나는 대략 이런 리더 키들을 쓴다.
v: 일반 리더 키. 주로 파일, 버퍼, 창(window) 관련 동작.k: kill 리더. 대부분의 kill 명령이 여기에.s: search 리더. 대부분의 검색 명령이 여기에.vp: project 리더. 여러 파일로 이루어진 ‘프로젝트’를 작업할 때 유용한 명령들. 프로그래밍에서는 이런 프로젝트 단위 작업이 매우 흔하다.command 모드에서 insert 모드로 전환하려면 i를 누른다. insert 모드에서 command 모드로 돌아가려면 C-j를 누른다.
이외에도 insert 모드로 들어가는 키가 몇 개 더 있다.
I: 현재 문자 뒤에서 삽입 시작O: overwrite 모드에서 삽입 시작(다시 command 모드로 돌아오면 overwrite 모드는 해제된다)A: (들여쓰기된) 줄의 시작에서 삽입 시작E: 줄 끝에서 삽입 시작C-RET: 새 줄 아래 만들고 삽입 모드 진입S-RET: 새 줄 위에 만들고 삽입 모드 진입상대 행 번호(relative line numbers)와 global-hl-line-mode를 켜 두면, 커서가 어느 줄에 있고, 다른 줄이 얼마나 떨어져 있는지 명확하게 알 수 있어 좋다.
elisp(setq-default display-line-numbers-type 'relative) (global-display-line-numbers-mode 1) (global-hl-line-mode +1)
command 모드에서 n을 누르면 다음 줄로, p를 누르면 이전 줄로 이동한다. 숫자 접두사를 붙여 함께 쓰는 일이 많다. 예를 들어 12n은 아래로 12줄 이동이다. 이 숫자-접두사 패턴은 일반적이다. 대부분의 명령은 이렇게 앞에 숫자를 붙여 여러 번 반복 실행할 수 있다.
r은 반 페이지 위로, t는 반 페이지 아래로 스크롤하며 커서 줄은 화면 가운데에 유지한다. 기본 scroll-up/scroll-down보다 이쪽을 쓰길 권한다. 기본 스크롤은 움직이는 양이 너무 커서 다시 위치를 파악하는 데 시간이 든다.
관련해서 유용한 동작 두 개는 recenter-top-bottom과 move-to-window-line-top-bottom이다. 각각 l과 L에 바인딩돼 있다. l은 현재 hl-line을 기준으로 화면을 움직인다. 한 번 누르면 hl-line을 화면 중앙에, 다시 누르면 화면 위쪽에, 또 누르면 아래쪽에 둔다. 말로 설명하는 것보다 직접 써 보는 게 이해가 빠르다. L은 그 반대에 가깝다. 화면을 기준으로 커서를 움직인다. 한 번 누르면 중앙, 다시 누르면 맨 위, 또 누르면 맨 아래.
.와 ,는 각각 ‘beginning-of-defun’과 ‘end-of-defun’이다. 최상위 ‘블록’ 단위로 움직이는 것이라 보면 된다. 꽤 유용한데, 사용 중인 언어 모드가 ‘블록’을 얼마나 잘 정의했는지에 따라 품질이 좌우된다.
덜 자주 쓰지만 가끔 유용한 키로, <와 >는 각각 현재 버퍼의 시작과 끝으로 이동한다.
수평 이동도 중요하지만, 프로그래밍에서는 나중에 설명할 “expression 단위 이동”과 “검색”을 더 많이 쓰는 것이 좋다.
subword 모드를 켜는 것을 추천한다.
elisp(global-subword-mode 1)
수평 이동을 할 때는 가능한 큰 단위로 움직이자. 한 글자씩 좌우로 움직이는 일은 거의 없어야 한다. 가장 작은 일반 단위는 “단어(word)”다. 대부분의 에디터에서 Ctrl-Right가 단어 단위 이동인 것과 비슷하다. 단어 앞으로 가려면 f, 뒤로 가려면 b를 누른다.
Emacs에서 ‘word’의 정의는 까다로울 수 있다. 특히 프로그래밍에서는 그렇다. foo_bar_baz는 세 개의 단어이고, (subword 모드를 켰다면) fooBarBaz 역시 세 개의 단어다. 그래서 어느 쪽이든 커서가 foo의 f에 있을 때 f로 forward-word를 하면, 커서는 baz 기호 앞에 간다. 긴 변수명 안에서 일부를 수정할 때 편리하다. 하지만 빠르게 이동한다는 관점에서는 좋지 않다. 그래서 나는 word 단위보다 expression 단위 이동을 더 권한다.
정말로 한 글자씩 이동해야 한다면 C-f, C-b를 쓰면 된다.
e는 현재 줄의 끝으로 이동한다. a는 현재 줄의 시작으로 이동하지만, 일반적으로는 m을 쓰는 것이 더 좋다. m은 줄에서 공백이 아닌 첫 문자 위치로 간다. 프로그래밍에서는 보통 이 위치가 더 유용하다. 다만 줄의 시작이나 끝으로 이동하려는 경우는 보통 그곳에 뭔가를 입력하려는 경우가 많다. 이럴 땐 각각 A와 E를 쓰면 된다. 줄의 시작/끝으로 이동하면서 동시에 insert 모드로 들어간다.
이것이 “줄 내부”에서의 이동 전부다. 하지만 앞에서 말했듯, 이런 명령을 많이 쓰는 것은 좋은 습관이 아니다. 줄 내부에서 이동하는 더 좋은 방법이 있다. expression 단위 이동과 검색이다.
S-Expression, 혹은 Sexp는 Lisp에서 중요한 개념이며, 따라서 Emacs에서도 그렇다. 대부분의 프로그래밍 언어는 문법적으로, 서로 다른 괄호에 둘러싸인 기호들의 ‘블록’으로 이루어져 있다. 많은 언어가 중괄호로 함수 본문, 루프, 구조체 정의 등의 실행 블록을 감싸고, 대괄호는 배열, 괄호는 인자 목록에 쓰는다. 이들 모두 s-expression 정의에 들어맞는다. 프로그램을 이리저리 움직일 때는, 이런 블록 안으로 들어가거나(down), 블록 밖으로 나오거나(up), 블록을 건너뛰거나(forward/backward), 그 안에서 이동하는 관점으로 생각하는 것이 유용하다. Emacs에는 이를 위한 명령이 매우 많고, 이를 확장하는 패키지도 많지만, 실제로 내가 쓰는 것은 네 개뿐이다.
j는 forward-sexp다. 커서가 여는 괄호 위에 있을 때 j를 누르면 그 전체 블록을 건너뛴다. h는 같은 일을 거꾸로 한다. 사실상 ‘대응 괄호로 점프’하는 명령처럼 쓸 수 있다.
커서가 괄호가 아닌 문자 위에 있을 때는 한 개의 문법적 심볼 앞으로/뒤로 건너뛴다. 프로그래밍에서는 word 단위 이동보다 이쪽이 거의 항상 더 낫다. 대부분의 경우, word가 아니라 심볼 단위로 건너뛰고 싶기 때문이다. 예를 들어 변수 이름 foo_bar_baz의 시작에 있을 때, 이 변수명을 수정할 게 아니라면 대개 전체를 한 번에 넘기고 싶다. j는 그렇게 해 준다. 반면 f를 쓰면 bar 위치로 간다.
또 다른 두 개는 ‘down-list’ (d)와 ‘up-list’ (u)다. 각각 블록 안으로 들어가고, 밖으로 나온다. 예를 들어 에디터 내용이 다음과 같고, |가 커서 위치라고 하자.
dele|te(state.im_temp_entity_buffer)
여기서 d를 누르면, 다음 블록(여기서는 delete의 인자 목록) 안으로 커서가 들어간다.
delete(|state.im_temp_entity_buffer)
여기서 u를 누르면, 다시 그 리스트 바깥으로 이동한다.
delete(state.im_temp_entity_buffer)|
이 동작은 괄호 종류와 상관없이 모두 잘 작동한다.
이 명령들은 음수 인자(예: -d)와 함께 써서 expression 뒤쪽으로 들어가거나/나오는 데도 쓸 수 있다. 앞의 예에서 -d를 쓰면 역방향으로 블록 안으로 들어가
delete(state.im_temp_entity_buffer|)
상태가 되고, -u는 다시 역방향으로 리스트 밖으로 나간다.
delete|(state.im_temp_entity_buffer)
이렇게 sexp 단위 이동에 익숙해지면, 프로그래밍할 때 forward-word 같은 수평 이동보다 훨씬 효율적이다. 이 패턴을 습관화하길 권한다.
sexp 단위 이동도 좋지만, 버퍼 안에서 몇 단어 이상 떨어진 위치로 이동할 때 가장 좋은 방법은, 이동하고 싶은 위치의 문자열을 검색하는 것이다. 이동하려는 위치가 이미 화면 안에 보이는 경우, “보고, 점프하기(look at, jump to)” 식의 동작이 된다. 눈으로 위치를 찾고, 그 근처의 문자열 일부를 입력하면 커서가 그리로 이동한다. 화면 밖에 있는 위치로 갈 때도 마찬가지로 잘 동작한다.
가장 단순한 명령은 표준 ‘isearch-forward’와 ‘isearch-backward’다. 키매핑은 기본 Emacs와 같다: C-s, C-r. 이를 대체하는 패키지로 ‘jump-char’, ‘avy’ 같은 것이 있지만, 기본 isearch만으로도 충분하다고 느낀다.
가끔은 아주 흔한 문자열을 찾고 있어서, 증분 검색으로는 성가실 때가 있다. 그럴 때는 occur를 쓴다. 내 설정에서는 so로 호출한다. 검색어의 모든 occurrence를 모아 하이퍼링크된 버퍼를 만들어 준다.
occur 사용법은 내 설정에 특화된 것은 아니지만 매우 유용하므로 조금 자세히 적는다. occur 버퍼에서는:
M-n, M-p는 occur 목록에서 위아래로 이동하지만, 원래 버퍼를 해당 줄로 점프시키지는 않는다.n, p는 목록 위아래로 이동하며, 원래 버퍼를 해당 줄이 보이도록 스크롤해 준다.M-g M-n, M-g M-p는 원래 버퍼를 해당 줄이 보이도록 업데이트할 뿐만 아니라, 원래 버퍼를 그 위치에서 활성화한다. 말로 설명하긴 좀 어렵지만 매우 유용하니 직접 해 보길 바란다.occur의 또 다른 장점은, 기본적으로 읽기 전용(read-only)이지만 e를 눌러 편집 모드로 전환할 수 있다는 점이다. 이 상태에서는 occur 창 안에서 원래 버퍼 내용을 수정할 수 있다. 굉장히 강력하다. 다 수정했다면 C-c C-c로 다시 읽기 전용 모드로 돌아온다.
multi-occur-in-matching-buffers로 여러 버퍼에 대해 occur 창을 만들 수도 있다. 다만 나는 조금 번거롭다고 느낀다. 진짜로 원하는 것은 ‘project-occur’, 즉 현재 프로젝트 전체에서 어떤 용어를 찾는 기능이다. 내가 아는 한 Emacs에 기본 제공되지는 않고, 외부 패키지인 ‘projectile’에는 있는 것으로 알고 있다. 나는 ‘ag’ 패키지와 silver-surfer 검색 프로그램을 써서 프로젝트 전체를 검색하지만, 완전 만족스럽지는 않다.
버퍼를 이리저리 빠르게 이동하는 또 다른 방법은 레지스터를 사용하는 것이다. 레지스터는 짧게 쓰고 버리는 ‘북마크’라고 생각하면 된다. 어떤 위치를 저장해 두었다가, 나중에 그리로 돌아올 수 있다. 예를 들어, 함수 호출 위치에서 함수 정의 안으로 잠깐 들어갔다가, 다시 호출 위치로 되돌아올 때 자주 쓴다. 보통 v SPC a로 현재 위치를 레지스터 a에 저장한 뒤, 다른 위치로 이동한다. 일이 끝나면 vja로 원래 위치로 돌아온다. 이런 동작을 연속으로 쓰고 싶을 때는 a, s, d, f 레지스터를 일종의 ‘스택’처럼 쓴다. 두 위치를 오가며 여러 번 왕복해야 할 때는 각각 a, s에 저장해 쓰는 식이다.
위에서 설명한 동작을 구현하는 또 다른 방법으로, mark를 매우 일시적인 자동 레지스터처럼 사용하는 방법이 있다. Emacs에서 isearch 같은 대부분의 ‘점프’ 명령을 사용하면, 점프하기 전 위치에 ‘mark’라는 임시 레지스터가 자동으로 설정된다. 또는 gg로 수동으로 mark를 설정할 수도 있다. 그다음 C-x C-x로 mark 위치로 점프할 수 있는데, 이때 mark는 다시 점프 전 위치로 재설정된다. 위에서 말한 a, s 패턴과 비슷하지만, 레지스터를 직접 셋업할 필요가 없다는 장점이 있다. 또 C-u g로 mark를 ‘pop’할 수 있고, C-u g g g처럼 여러 번 반복해 이전 mark들을 순차적으로 되돌아갈 수도 있다.
단점은 mark가 레지스터보다 덜 영속적이라는 점이다. 실수로 다른 데에 mark를 찍어 버리면, 점프했을 때 엉뚱한 위치로 가게 되어 매우 혼란스럽다. 그런 이유로 나는 보통 수동 레지스터를 더 많이 쓴다.
occur 모드로도 찾기-바꾸기를 할 수 있지만, 보통은 sq(query-replace)를 쓰는 편이 더 쉽다. 이건 표준 Emacs 기능이며, 다른 에디터들의 찾기-바꾸기와 거의 동일하게 동작하므로 자세한 설명은 생략한다.
변형으로 vpq는 프로젝트 단위 query-replace다. 동작 방식은 동일하지만, 현재 버퍼뿐 아니라 프로젝트 안의 모든 파일을 대상으로 한다.
프로그램 텍스트 편집에서 중요한 동작을 순서대로 꼽아 보면, 버퍼를 이리저리 이동하는 것이 1순위, 그다음이 잘라내기/복사/붙여넣기, 마지막이 타이핑이다.
앞에서 보았듯, 화면을 움직이는 데는 여러 종류의 문법 단위가 있다. 이동과 ‘kill’(Emacs에서 보통 “잘라내기(cut)”라고 부르는 동작)은 일종의 쌍으로 생각하면 된다. 특정 단위로 이동하는 명령이 있으면, 대체로 비슷한 단위로 kill하는 명령도 있다. 내 설정에서는 가능할 때 이 둘을 같은 키에 두되, kill 쪽에는 k 접두사를 붙인다.
예를 들어 kf는 forward-word에 대응하는 kill forward word, kj는 forward-sexp에 대응하는 kill forward sexp다. 전체 목록은 아래에 있지만, “어떻게 이동하는지”를 알면 대개 그와 대응하는 kill 명령을 쉽게 추측할 수 있다.
kill에는 몇 가지 특수한 경우가 있다. kf로 앞쪽 단어를 kill하고, kj로 앞쪽 sexp를 kill하지만, 많은 경우 실제로 하고 싶은 일은 “현재 안에 있는 단어/sexp 전체를 kill”하는 것이다. 이를 위해 ki(kill whole word)와 kn(kill whole sexp)을 쓴다. 비슷하게, ke는 현재 위치부터 줄 끝까지를 kill하지만, 더 자주 쓰게 되는 것은 줄 전체를 kill하는 kl이다.
편리하지만(비효율적일 때도 있지만) 자주 쓰는 패턴은, 하이라이트한 영역 전체를 kill하는 것이다. kw는 region을 kill하고, ks는 region을 복사한다(kill-ring-save).
또 한 가지, 특정 문자까지 kill하고 싶을 때가 많다. Emacs에서는 이를 ‘zap’이라 부르며, kz(zap-to-char)로 할 수 있다.
마지막으로, 현재 줄을 윗줄과 합치고 싶을 때는 k6을 쓰면 된다.
붙여넣기는 y(yank)를 누르면 된다.
아래는 사용 중인 kill 명령 전체 목록이다.
kf kill wordkb kill backkj kill sexpkn kill inner sexpkh kill sexp backke kill to end of linekl kill whole linekw kill regionks kill ring savek6 join linekr kill rectanglekz zap to characterki kill inner word프로그래밍을 할 때는, 보통 ‘프로젝트’ 안의 파일들과 버퍼들 사이를 많이 오가게 된다. 여기서 프로젝트란 보통 소스 저장소의 루트 디렉터리를 의미한다.
이런 작업 대부분은 v 리더 키에 묶여 있고, 프로젝트 전체를 대상으로 하는 명령은 vp에 묶여 있다. 특별히 독특한 것은 없으므로 간단히 목록만 적는다.
w 다른 모든 창 닫기(delete-other-windows)o 다른 창으로 이동(other-window)v1 다른 창 닫기v2 아래로 창 분할(split-window-below)v3 오른쪽으로 창 분할(split-window-right)vf find-filevpf project-find-filevs save-buffervps project 전체 파일 저장vr 최근 파일 목록(recentf 기반, 약간의 커스텀 설정 필요)vd diredvpd 프로젝트 루트에서 dired 열기vk kill-buffervpk 프로젝트 내 버퍼들 killvb switch-to-buffervpb project-switch-to-buffer매크로는 Emacs에서 의외로 쓸 만하다. 다만 약간 요령이 필요하다. v[로 매크로 기록을 시작하고, v]로 끝낸다. vm으로 매크로를 실행하고, vmmmmm...처럼 반복해서 여러 번 실행할 수 있다.
Emacs의 LSP 구현인 eglot은 내 경험상 장단이 있다. 나는 보통 꺼 두고 쓴다. 하지만 xref-find-definition(M-.)이나 향상된 탭 완성은 무시하기 힘들 만큼 유용할 때가 있다.
comment-line(;)은 정말 자주 쓴다. region을 잡고 실행하면 그 영역을 주석 처리한다.
/는 undo, v\는 공백 정리(whitespace cleanup)다. q는 ‘fill or reindent’로, 보통 현재 블록의 포매팅을 정리해 준다. x는 execute-extended-command(M-x), z는 반복(repeat)이다.
사각형(rectangle) 편집도 종종 유용하다. 편집할 영역을 하이라이트한 뒤, kr로 그 사각형을 kill하거나, vt로 사각형을 입력한 텍스트로 교체한다. 다른 에디터에서 멀티 커서를 쓸 법한 대부분의 상황을 이걸로 해결할 수 있다고 느낀다.
vv는 VC 인터페이스를 연다(나는 magit으로 연결해 둠).
작업 중인 부분을 눈에 잘 띄게 표시하고 싶을 때는 sh로 특정 색으로 하이라이트한다.
vi는 imenu, vI는 imenu-to-buffer로, major-mode가 잘 구현되어 있다면 코드의 ‘섹션’ 단위로 탐색하는 데 쓸 만하다.
실수로 눌렀을 때 불쾌한 결과를 만드는 명령들은 아예 비활성화해 두었다. 특히 짜증 나는 것은 C-z, C-x C-z 두 개의 ‘suspend’ 단축키다.
위의 키바인딩 말고도 설정에 다른 것들이 좀 더 있다. 하지만 대부분은 아주 흔한 설정(임시 파일 저장 위치 조정 등)이거나, 매우 개인 취향에 가깝고 일반적인 조언으로는 별로인 것들이다. 예를 들어 나는 transient-mark-mode를 끄고 쓰지만, 이걸 전반적인 권장 사항으로 내고 싶지는 않다.
탭 완성(tab completion)은 마음에 들게 세팅하기가 꽤 까다롭다. 나는 아래처럼 쓰지만, 완벽하다고는 할 수 없다.
elisp(setq-default indent-tabs-mode t) (setq-default tab-width 4) (setq tab-always-indent 'complete) (setq tab-first-completion 'word)
한 가지 권장하고 싶은 것은 외부 패키지 의존성을 가능한 줄이는 것이다. 내가 사용하고, 추천하는 패키지는 다음과 같다.
ag: silver-surfer 검색 프로그램 인터페이스. 프로젝트 전체에서 특정 용어를 검색하는 용도다. grep도 나쁘지 않지만, 나는 silver-surfer를 선호한다. 내 설정에서는 sa로 쓴다.diff-hl: 마지막 커밋 이후 변경된 줄을 하이라이트해 주는 유틸리티.magit: git 사용을 견딜 만하게(혹은, rebase 같은 걸 할 수 있게) 만들어 준다.visible-mark: ‘mark’가 어디에 있는지 시각적으로 표시해 준다.그리고 몇 개의 언어별 패키지가 더 있다.
그냥 내가 Emacs에 익숙하기 때문이다. 여기서 설명한 것들은 전부 vim에서도 똑같이 할 수 있다.
여기 있다: https://github.com/RedPenguin101/dotfiles/blob/main/init.el