시작하기

이 문서는 바닥부터 이맥스를 꾸미는 방법을 설명합니다. 이미 잘 꾸며진 이맥스를 쓰고 싶으신 분들은 다른 사람들이 꾸민 버전을 사용하세요. doom emacsspacemacs를 사용하면 다른 사람이 미리 꾸며놓은 버전을 쉽게 사용할 수 있습니다.

박주형이 작성했습니다.

emacs lisp 시작하기

이맥스 설정파일은 이맥스 리스프 소스코드로 이루어져있습니다. 이맥스 리스프의 기초를 알고 있으면 설정을 할 때 도움이 됩니다.

함수의 호출

리스프는 (fun-name arg0 arg1) 형태로 함수를 호출합니다. 다른 언어와 다르게 모든 언어의 구성 요소가 함수입니다. 조건문, 반복문, 함수 정의, 변수 선언 등의 모든 문법이 함수 호출 문법을 따릅니다.

;; + 함수는 인자를 여러개 받아서 다 더한 값을 리턴합니다.
(+ 1 2)
(+ 1 2 3)

;; message 함수는 c의 printf 함수와 비슷합니다.
;; 포맷 스트링과 인자를 받아 포매팅한 뒤 메세지 버퍼에 출력합니다.
(message "hello world")
(message "%s %s" 2 4)

설정파일의 일부분만 실행하기

이맥스 설정파일 혹은 아무 텍스트 버퍼에서 (+ 1 2)를 입력한 뒤 커서를 닫는 괄호 ) 뒤에 두고 Ctrl-x Ctrl-e 를 입력해 보세요. 이맥스의 아래 조그만 박스에 결과 값인 3이 나오는 것을 볼 수 있습니다. 이맥스를 설졍할 때에는 이렇게 일부 설정 코드만 실행하는 일이 자주 있습니다.

주석

emacs lisp는 ; 글자부터 라인의 끝까지를 주석으로 인식하고 무시합니다. 잠시 특별한 설정값을 무시하게 만들거나 설정에 대한 설명을 쓰기 위해서 사용합니다.

자료구조

리스트

()는 함수를 호출하는 문법이었습니다. 앞에 작은 따옴표를 붙이면 '() 리스트 자료구조가 됩니다. '(1 2 3)은 1, 2, 3을 포함하는 리스트입니다. 설정할 때 여러 값을 입력해야 하는 경우 자주 사용합니다.

페어

리스트는 원소를 0개부터 n개까지 가질 수 있습니다. 두 개의 원소를 표현하고 싶을 때 종종 페어를 사용합니다. 두 개의 원소 사이에 . 을 집어넣어 pair를 만들 수 있습니다. '(1 . 3) 는 1과 3을 가진 페어입니다. 키 밸류 형식의 설정을 하거나 값이 두개가 필요한 설정을 만들 때 자주 사용합니다.

페어와 리스트는 알고 보면 같은 걸 의미하지만 설정파일을 만드는 입장에서 자세한 내용을 알 필요 없습니다.

함수와 변수의 구분

emacs lisp는 함수와 변수의 영역을 구분합니다. 함수를 다른 함수의 인자로 보낼 때는 작은 따옴표를 함수 이름 앞에 붙여주어야 합니다. 언제 ' 를 붙여야 하는지 이해할 필요는 없습니다. 다른 예시코드를을 보고 ' 를 붙이고 있다면 따라서 붙여주고, ' 가 안붙어 있다면 따라서 안 붙여주면 됩니다.

;; 아래 설정을 통해
;; f5 키를 누르면 build-project 함수가 호출되게 만들 수 있습니다.
(global-set-key (kbd "<f5>") 'build-project)

:config :foo 같이 콜론 뒤에 글자가 오는 행태는 심볼을 만듭니다

emacs lisp 설정에 사용되는 함수들을 보다 보면 python의 keyword 인자같은 문법을 볼 때가 있습니다. 뒤에서 사용할 use-package 함수가 바로 그런 함수입니다.

이건 무슨 문법이지

다른 사람들이 만든 설정파일을 읽거나, 새로운 플러인을 사용하는 예시 코드를 읽다 보면 어떤 문법인지 궁금할 때가 있습니다. 이 페이지는 그런 물법들을 소개합니다.

함수 앞에 #' 붙이기

이전 페이지에서 함수를 인자로 넘길 때 함수 이름 앞에 '를 붙인다고 했습니다. 주로 새로운 키를 매핑할 때 자주 사용하게 됩니다. 간혹 ' 대신 #'가 사용되는 것을 볼 수 있습니다. #''를 쓰는 것과 거의 똑같습니다. 설정파일 수준에서는 그 차이점을 알 필요는 없습니다.

둘이 다른 점은, 다음과 같습니다. '는 함수 이외에도 붙일 수 있지만 #'는 함수 앞에만 붙입니다. 따라서 컴파일할 때 더 최적화할 여지가 있습니다.

관련 stack overflow답변입니다. 관련 emacs lisp manual 글입니다.

progn은 무엇인가

간혹 함수를 하나 넣을 자리에 여러 함수를 호출하고 싶을 때가 있습니다. 그럴 땐 progn을 사용하면 됩니다. progn 함수는 다른 언어의 block과 유사합니다. progn 함수의 인자로 여러 함수콜들을 나열하면, progn은 각각의 함수콜을 차례 차례 실행한 뒤 마지막 함수콜의 결과를 반환합니다.

;; 아래 코드는 hi메시지를 message 버퍼에 기록하고,
;; 3을 계산한 뒤 버리고, 12를 리턴합니다.
(progn
  (message "hi")
  (+ 1 2)
  (* 1 3 4))

설정 파일 시작하기

커스터마이징의 시작과 끝을 설정파일을 꾸미는 것입니다. 설정파일을 변경하고 해당 파일을 emacs가 읽는 것을 확인해 봅시다. 설정파일의 위치가 헷갈리면 조금 고생할 수도 있습니다. 차분히 따라하면 문제 없을 거에요.

설정파일 열기

emacs를 켠 뒤 ctrl-x ctrl-f 를 입력합니다. 이 때 뜨는 창에서 ~/.emacs.d/init.el 을 입력하고 엔터를 칩니다. 이렇게 하면 설정파일이 열립니다.

설정파일이 생성되는 위치는 macOS나 Linux라면 home 디렉토리의 emacs.d/init.el에, Windows라면 %HOMEPATH%\AppData\Roaming.emacs.d\init.el에 생성됩니다.1

1

직접 windows에서 확인해보진 않았습니다. http://ergoemacs.org/emacs/emacs_mswin.html 페이지를 참조했습니다.

설정파일을 확인하기

설정파일에 (message "hi config file") 을 입력해 봅시다. Ctrl-x Ctrl-s를 눌러 저장한 뒤 emacs를 Ctrl-x Ctrl-c로 끕니다. 다시 emacs 를 켠 뒤 *Messages* 버퍼에 "hi config file"이 출력되는지 확인합니다.

Ctrl-x b로 다른 버퍼를 열 수 있습니다. 버퍼는 이맥스가 연 파일 목록이라고 이해할 수 있습니다. *Messages* 를 입력하고 엔터키를 누르면 *Messages* 버퍼가 열립니다. *Messages* 버퍼는 이맥스가 특별히 취급하는 버퍼로 항상 존재합니다.

init.el에서 명령어 바로 실행하기

설정파일을 수정할 때마다 emacs를 껐다 켜는 건 귀찮습니다. 이맥스에서 실행하고 싶은 설정 코드의 닫는 괄호 뒤에 커서를 두고 ctrl-x ctr-e를 누르면 해당 설정 코드가 실행됩니다. 패키지 설치, 키 매핑 변경 등의 설정은 emacs를 껐다 켜지 않아도 쉽게할 수 있습니다. 익숙해지면 삶의 질이 달라집니다.

중첩된 복잡한 설정 코드가 있을 때 중첩된 명령의 안쪽 서브 코드만 실행하기도 가능합니다.

;; 예를들어

(progn
  (message "first");; 이 괄호에서 ctrl-x ctrl-e를 누르면 "first"만 출력됩니다.
  (message "second");; 이 괄호에서 ctrl-x ctrl-e를 누르면 "second"만 출력됩니다.
) ;; 이 괄호에서 ctrl-x ctrl-e 하면 first와 second 모두
;; 출력됩니다.

if문처럼 조건문 안의 코드도 쉽게 실행해볼 수 있습니다.

(if nil
  (message "true");;여기 닫는 괄호에서 실행하면 "true"가 출력됩니다.
  (message "false")
);; 이 식은 실행하면 "false"만 출력합니다.

다른 사람의 작업으로부터 영감 얻기

다른 사람의 소스코드를 읽으면 코드를 더 잘 짤 수 있게 되듯이, 다른 사람의 설정 파일을 읽으면 자신의 설정파일을 더 잘 만들 수 있습니다. 여기 참고할만단 다른 설정파일들의 링크를 달아놓겠습니다.

패키지 추가하기

꾸미기의 시작은 패키지입니다. 다른 사람들이 만들어 둔 유용한 도구들을 잔뜩 설치해서 나만의 이맥스를 만들어 봅시다.

emacs에서 패키지를 관리하는 방식은 여러가지가 있습니다. 그 중 use-package를 사용한 방법을 알려드리겠습니다. use-package는 패키지 설치와 설정을 한 곳에 묶을 수 있어 설정파일 관리를 더 쉽게 만들어 줍니다.

use-package 설치하기

use-package를 설치하고 나면 다른 패키지들은 쉽게 설치할 수 있습니다. 하지만 use-package는 use-package로 설치할 수 없기 때문에 약간의 귀찮은 과정을 거쳐야 합니다.

melpa 저장소 추가

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

use-package package는 melpa에서 다운받을 수 있습니다. 위 세 줄을 emacs 설정 파일에 추가해 주세요.

emacs의 패키지들은 elpa와 melpa에서 다운받을 수 있습니다. elpa는 이맥스 공식 레포지토리며 melpa에 비해 패키지를 올리기가 어렵습니다. melpa는 공식 레포는 아니지만 쉽게 패키지를 올릴 수 있고 이미 많은 패키지들이 올라가 있습니다.1

1

StackOverflow의 이 답변이 잘 설명하고 있습니다.

package-install 명령으로 use-package 설치하기

melpa 저장소를 추가했다면(위의 세 줄을 작성한 뒤 이맥스를 껐다 켜거나, 하나 하나 ctrl-x ctrl-e로 실행해 주세요.) package-install 명령어로 use-package를 설치할 수 있습니다.

alt-x2 누르시면 이맥스 화면 아래에 emacs 함수를 실행할 수 있는 창이 하나 뜹니다. 앞으로 이 창을 매우 많이 쓸 예정입니다. 이 창에서 package-refresh-contents를 치고 엔터를 쳐주세요. 이맥스가 melpa의 패키지 목록을 다운받아 올 거에요. 잠시 시간이 걸릴 수 있습니다.

다시 alt-x를 치고 package-install을 치고 엔터를 칩니다. 그러면 이맥스가 설치할 패키지를 물어볼텐데 여기에 "use-package"를 입력하고 엔터를 쳐주세요. 별다른 에러가 나지 않았다면 "use-package" 패키지가 잘 설치된 겁니다.

2

이맥스에서는 alt 대신 M 혹은 meta를 자주 씁니다. 이 글에서는 alt를 쓸게요. alt와 meta의 관계는 좀 복잡합니다. 여기서 다루진 않을게요.

use-package 설정하기

설정파일에 아래 두 줄의 코드를 추가합니다.3

(eval-when-compile
  (require 'use-package))

위 두 라인을 실행하면 use-package 설정이 끝납니다.

3

use-package README.md의 Getting started 챕터에 적혔는 내용입니다.

첫 번째 패키지: doom-modeline 설치하기

emacs의 버퍼 아래엔 현재 수정하고 있는 파일이 무엇인지 보여주는 한 줄의 ui가 있습니다. 이를 mode line이라고 부릅니다. 기본 UI가 투박하기 때문에 많은 사람들이 이 UI를 개선해서 사용합니다. doom-modeline도 mode-line을 꾸며주는 패키지 입니다.

(use-package doom-modeline
  :ensure t
  :hook (after-init . doom-modeline-mode))

위 세 줄을 설정파일에 추가하고 실행합니다. 그러면 doom-modeline의 설치 밎 설정이 끝납니다. 참 쉽죠. 위에 보시면 (after-init . doom-modeline-mode) 코드가 있습니다. 이는 use-package의 인자로 emacs가 켜졌을 때 (doom-modeline-mode) 함수를 실행하라는 의미입니다. emacs를 껐다 켜기 귀잖으신 분들은 alt-x 누른 뒤 doom-modeline-mode를 실행하여 수동으로 킬 수도 있습니다. 실행하시면 modeline이 깔끔해진 것을 볼 수 있습니다.

이맥스 자동완성시키기

이맥스의 기본 기능들은 잘 동작하지만 어떤 기능들이 있는지 쉽게 찾기 힘듭니다. alt-x로 함수를 실행할 때에도 원하는 함수를 정확히 할고있는 게 아니라면 필요한 함수를 찾기 힘듭니다. ivy나 help 플러그인은 원하는 기능을 쉽게 찾을 수 있게 도와줍니다.

Ivy, Counsel, Swiper

Ivy는 컨텍스트와 상관없이 이맥스에서 자동완성을 도와주는 도구입니다. Ivy는 Ivy를 사용해 이맥스의 기본 기능을 개선시킨 함수들을 제공하는데 이를 Counsel이라고 부릅니다. Swiper는 이맥스의 검색 기능(Ctrl-s)를 개선시킨 함수입니다. 이 세 종류의 기능을 보통 함께 사용합니다.

설치하기

use-package를 사용해서 쉽게 설치할 수 있습니다. :config 다음의 내용들은 ivy GitHuub README.md의 예시 설정에서 가져왔습니다.

(use-package counsel
  :ensure t)

(use-package ivy
  :ensure t
  :config
  (setq ivy-use-virtual-buffers t)
  (setq enable-recursive-minibuffers t)
  ;; enable this if you want `swiper' to use it
  ;; (setq search-default-mode #'char-fold-to-regexp)
  (global-set-key "\C-s" 'swiper)
  (global-set-key (kbd "C-c C-r") 'ivy-resume)
  (global-set-key (kbd "<f6>") 'ivy-resume)
  (global-set-key (kbd "M-x") 'counsel-M-x)
  (global-set-key (kbd "C-x C-f") 'counsel-find-file)
  (global-set-key (kbd "<f1> f") 'counsel-describe-function)
  (global-set-key (kbd "<f1> v") 'counsel-describe-variable)
  (global-set-key (kbd "<f1> o") 'counsel-describe-symbol)
  (global-set-key (kbd "<f1> l") 'counsel-find-library)
  (global-set-key (kbd "<f2> i") 'counsel-info-lookup-symbol)
  (global-set-key (kbd "<f2> u") 'counsel-unicode-char)
  (global-set-key (kbd "C-c g") 'counsel-git)
  (global-set-key (kbd "C-c j") 'counsel-git-grep)
  (global-set-key (kbd "C-c k") 'counsel-ag)
  (global-set-key (kbd "C-x l") 'counsel-locate)
  (global-set-key (kbd "C-S-o") 'counsel-rhythmbox)
  (define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history))

설치한 이후 alt-x 를 누르면 예상되는 함수들이 여럿 나오고, 함수 이름 중 일부만 작성해도 원하는 함수를 쉽게 찾을 수 있습니다. 이외에도 도움말이나 검색(ctrl-x)도 좀 더 쓰기 편하게 쓸 수 있습니다.

잡다한 ivy 팁들

alt-x 함수 이름 중간부터 검색하기

alt-x를 누르면 ^키가 미리 눌러져 있습니다. ^는 정규표현식에서 사용하는 기호로 단어의 시작을 의미합니다. 따라서 ^ 이후에 글자를 입력하면 항상 함수 이름의 시작 글자부터 검색하게 됩니다. ^theme를 검색하면 theme로 시작하는 함수들을 검색합니다. theme를 검색하면 theme가 들어간 모든 함수를 검색합니다.

띄어쓰기를 사용해서 여러 단어 검색

theme를 검색하면 "theme"가 정확히 들어간 함수만 검색합니다. the me를 검색하면 함수 이름에 "the"와 "me"가 포함된 함수를 검색합니다.