-*- coding:utf-8 -*-
이 설정파일은 GNU Emacs를 빠르고 쉽게 사용하기 위하여 작성되었습니다.
Emacs는 매우 강력하고 훌륭한 프로그램이지만, 그 방대함은 사용자로 하여금 쉽게 길을 잃게 만듭니다. 따라서 인터넷에 공개된 수많은 Emacs 설정 파일은 그 헤메임의 기록이며, 사람들로 하여금 이정표 역할을 해줍니다. 이 파일도 그 기록 중 하나입니다.
특별히, 이 파일의 설명은 한국어로 쓰여졌습니다. 이는 공개된 Emacs 설정에 대한 정보를 찾아다니던 중, 한국어로 되어 있는 것이 거의 없으므로 발생하는 어려움에 대한 대응입니다. 물론 Emacs를 사용하는 많은 사람들은 영어로 정보를 습득하는 데 어려움이 없긴 할 것이나, 한편으로는 언어적 장벽이 주는 저변 확대는 무시할 수 없습니다. 더욱이, Emacs는 굳이 프로그래머가 아니더라도 글쓰는 사람들에게 좋은 도구가 되어줍니다. org-mode를 사용한 정리된 글쓰기, Deft의 강력한 파일 관리 기능, 혹은 Emacs 내부에 포함된 여러 기능들은 단지 프로그래머가 아니라 일상적으로 컴퓨터 앞에 앉는 모든 사람들에게 도움이 됩니다. 이 설정파일은, 그러한 사람들에게 도움이 되는 것을 의도하고 있습니다.
이 설정파일은 다음 사항을 목표로 작성됩니다.
- 한국어 사용자: Emacs는 자체적인 IME를 포함하고 있으며, 매우 훌륭하게 작동합니다. 그러나 바닐라 상태에서 한국어 사용에는 다소 어려움이 있으며, 편리하게 쓰기 위해서는 몇 가지 설정이 필요합니다.
- 속도: 많은 모던한 에디터들은 종종 많은 패키지를 설치했을 때 실행 속도의 희생을 가져오곤 합니다. Emacs도 그러한 위험성을 내포합니다. 특히 Emacs에서 파생된 Spacemacs 같은 경우에도, 많은 레이어들을 추가하면 금새 프로그램이 느려지고 꼬이게 됩니다. 바닐라 상태의 Emacs는 상당히 빠르고, 따라서 Emacs의 실행 속도를 확보하기 위한 여러 팁들이 공개되어 있습니다. 이 설정파일도 그러한 팁들을 적극적으로 반영합니다.
- 기능성: Emacs는 다양한 기능들이 있으며, 각자 필요한 기능들에 맞게 조합하는 방식으로 설정을 이루게 됩니다. 이 설정파일은 다소의 주관적인 사용 패턴이 반영되긴 했지만, 많은 사용자들이 공통적으로 사용하는 기능과 패키지들을 포함합니다. 또한, 얼마든지 원하는 패키지들을 추가해서 사용할 수 있도록 하였습니다.
- 투명성: 이 설정파일은 가능한 상세한 설명을 명시해 놓는 것을 원칙으로 합니다. 굳이 org 파일로 작성하는 이유도 여기에 있습니다. 이를 통해, 처음 이 파일을 읽는 사람들도(org 파일은 GitHub에서 렌더링되므로 편하게 읽을 수 있습니다) Emacs의 작동 원리에 대해 어느 정도 개괄할 수 있도록 의도하였습니다.
이 설정파일은 여러 곳에서 정보를 모아 쓰여졌습니다. 부분적인 코드의 출처는 각자 명시할 것입니다. 주요하게 참고한 설정들은 다음과 같습니다.
- Sacha Chua: Sacha Chua’s Emacs Configuration
- Terencio Agozzino: GNU Emacs Configuration
Emacs에 대한 한글 정보는 다음 사이트를 참고하기를 추천합니다. 다만 부분적인 정보만 담고 있다는 한계는 있습니다.
이 설정파일은 실제로 사용되고 있는 것이므로, 지속적으로 수정되고 기능이 추가되며 갱신될 것입니다. 갱신 내역은 커밋 내역에 적히며, 중요한 개선사항은 이 파일에도 명시됩니다. 기능의 추가는 상기한 목표를 헤치지 않는 선에서 이루어집니다.
설정파일을 사용하는 과정에서 발생하는 오류나 개선사항은 <clockoon@gmail.com> 또는 저장소의 issue에 알려주시기 바랍니다.
- 2018-06-02: 기존에 사용하던 설정 파일을 org 파일로 정리
설정을 로딩하는 시간을 절약하기 위해, 이 설정은 Emacs를 서버-클라이언트 형태로 실행하는 방식을 지원합니다(엄밀히 말해서 실행속도는 변하지 않지만, 서버-클라이언트 방식은 한번 로딩이 끝나면 클라이언트를 여러 개 실행해도 다시 로딩할 필요가 없다는 장점이 있습니다).
서버를 사용하려면 설정 경로에 하위 디렉토리 ./server 가 포함되어야 합니다. 이 때 Windows는 폴더 소유자 문제가 발생할 수 있으므로, 이를 해결해 줍니다.
참고:
- https://www.emacswiki.org/emacs/WThirtyTwoServerMode
- https://stackoverflow.com/questions/885793/emacs-error-when-calling-server-start
(setq server-directory (expand-file-name "server" user-emacs-directory))
(unless (file-directory-p server-directory)
(make-directory server-directory))
(if (eq system-type 'windows-nt)
(shell-command (concat "takeown /r /d y /f " (subst-char-in-string ?/ ?\\ server-directory)))
(shell-command (concat "chmod 700 " server-directory)))
;; This starts the Emacs server when .emacs gets loaded
;; REF: https://www.emacswiki.org/emacs/WThirtyTwoServerMode
(require 'server)
(if (not (server-running-p)) (server-start))
서버로 Emacs를 실행할 경우 기본적인 C-x C-c 단축키를 사용하면 서버 자체가 죽어버리기 위해, 이를 방지하기 위해 기본적으로 클라이언트 프레임만 닫고 서버를 죽이는 함수를 따로 생성합니다.
;; This changes C-x C-c to just hide Emacs until the next
;; time you use it. We rebind C-M-c to be the command to
;; really kill Emacs.
(defun my-done ()
"Exit server buffers and hide the main Emacs window"
(interactive)
(server-edit)
(make-frame-invisible nil t))
(global-set-key (kbd "C-x C-c") 'my-done)
(global-set-key (kbd "C-M-c") 'save-buffers-kill-emacs)Emacs는 기본 garbage collection threshold를 작게 잡고 있는데, 이를 개선하면 실행 속도를 높일 수 있습니다. 그 향상속도에 대해서는 논쟁의 여지가 많지만, 무거운 작업에서 일시적으로 값을 높이는 것 자체는 합리적으로 보입니다.
;; Faster startup: adjusting the frequency of garbage collection
;; REF: https://bling.github.io/blog/2016/01/18/why-are-you-changing-gc-cons-threshold/
(defun my-minibuffer-setup-hook ()
(setq gc-cons-threshold most-positive-fixnum))
(defun my-minibuffer-exit-hook ()
(setq gc-cons-threshold 800000))
(add-hook 'minibuffer-setup-hook #'my-minibuffer-setup-hook)
(add-hook 'minibuffer-exit-hook #'my-minibuffer-exit-hook)회사 환경 등 프록시를 필요로 하는 환경에 대해 설정을 진행합니다. 초기에 프록시 서버를 입력받으며, 이후에는 user-proxy.el 파일을 수정합니다.
;; set user file and open: storing user setting e.g. proxy
(setq proxy-file (expand-file-name "user-proxy.el" user-emacs-directory))
(unless (file-exists-p proxy-file)
(if (y-or-n-p "Do you need proxy setting?")
(progn
(setq my/http-proxy (read-string "Input http-proxy: "))
(setq my/https-proxy (read-string "Input https-proxy: "))
(write-region
(concat
";; proxy setting\n"
"(setq url-proxy-services \n"
" '((\"no_proxy\" . \"^\\\\(localhost\\\\|10\\\\..*\\\\|192\\\\.168\\\\..*\\\\)\")\n"
" (\"http\" . \"" my/http-proxy "\")\n"
" (\"https\" . \"" my/https-proxy "\")))") nil proxy-file))
(write-region "" nil proxy-file)))
(load proxy-file)이 설정파일에서는 패키지 관리를 위해 use-package 및 straight.el을 사용합니다. straight.el은 기존 패키지 관리자에 비해 github 등 다양한 출처에서 저장소를 clone하여 사용하기 때문에, 빠른 업데이트 및 유연한 설정이 가능합니다. use-package는 패키지를 불러오는 과정에서 의존성이나 단축키, 추가 설정 등을 할 수 있는 장점이 있습니다.
우선 straight.el을 bootstrapping합니다.
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
다음으로 패키지 설정을 초기화하고, 설치에 필요한 저장소를 추가합니다. 이 저장소에 포함되지 않는 패키지는 straight.el에서 따로 경로를 지정합니다.
참고:
(setq
;; 기본적으로 Emacs는 패키지를 설치할 때 관련 정보를 init.el에 기록합니다. 이를 방지하도록 설정합니다.
package--init-file-ensured 't
;; org 관련 프로세스가 자동으로 종료될 수 있도록 합니다.
kill-buffer-query-functions nil
;; 오래된 버전의 파일을 로드하지 않고 재컴파일하도록 합니다.
load-prefer-newer t
;; 패키지 저장소 추가
;; 저장소: MELPA, MARMALADE, ORG-MODE, GNU, user42
package-archives
'(("melpa-stable" . "http://stable.melpa.org/packages/")
("melpa" . "http://melpa.org/packages/")
("gnu" . "http://elpa.gnu.org/packages/")))
;; org 저장소 미러 추가
(condition-case nil
(add-to-list 'package-archives '("org"."http://orgmode.org/elpa/"))
(error
(add-to-list 'package-archives '("org"."https://raw.githubusercontent.com/d12frosted/elpa-mirror/master/org/"))))
;; 패키지 로딩 및 초기화
(eval-when-compile
(require 'package)
(package-initialize t))
;; 구 버전 패키지를 저장하지 않습니다.
(unless (boundp 'package-pinned-packages)
(setq package-pinned-packages ()))기본적인 방식에 비해 use-package는 더 강력하고 효율적이며 빠르게 패키지를 관리할 수 있습니다.
;; straight.el에 use-package를 연결하고 설치합니다.
(setq straight-use-package-by-default t)
(straight-use-package 'use-package)
;; 로딩 속도가 느린 패키지는 *message* 버퍼에 표시합니다.
(setq use-package-verbose t)
;; use-package에서 불러오는 패키지가 설치되었는지 항상 확인하고, 설치되어 있지 않으면 자동으로 다운받아 설치합니다.
(setq use-package-always-ensure t)Emacs는 기본적으로 한국어 사용을 위한 설정이 되어있지 않습니다. 우선, 한국어/유니코드로 프로그램 환경과 로케일을 맞춥니다.
참고:
- http://wiki.nacyot.com/documents/emacs/#.WVyTxGSPJhE
- https://stackoverflow.com/questions/2901541/which-coding-system-should-i-use-in-emacs
;; Emacs는 기본으로 CJK (한중일) 문자를 인코딩하지만, 이로 인해 유니코드 환경에서는 문제가 발생합니다. 이 옵션은 꺼주는 것이 좋습니다.
(setq utf-translate-cjk-mode nil)
;; UTF-8 설정 모음
(set-language-environment 'utf-8)
(set-keyboard-coding-system 'utf-8-mac) ;; For old Carbon emacs on OS X only
(setq locale-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
;; 윈도우 환경에서는 모든 텍스트가 UTF-8로 인코딩되지 않으므로, 클립보드 인코딩을 UTF-8로 하지 않습니다.
(unless (eq system-type 'windows-nt)
(set-selection-coding-system 'utf-8))
(prefer-coding-system 'utf-8)
;; 시간 표시 형식은 영어로 표시해서 호환성을 높입니다.
(setq system-time-locale "C")Emacs는 기본적으로 한글 IME를 내장하고 있지만, 바닐라 상태에서는 OS 내장 IME와 충돌하는 문제가 있습니다. 이 설정에서는 IME와 독립적으로 작동할 수 있도록, 다양한 한글 자판 - 2벌식, 390, 391 - 을 선택하여 쉽게 전환할 수 있는 함수를 내장합니다.
참고:
- https://kldp.org/node/109184
- https://stackoverflow.com/questions/34505209/lisp-cycle-through-functions/34505716#34505716
- OSX의 경우, 구름 등의 커스텀 입력기를 사용할 경우 Emacs와 충돌하는 경우가 있습니다. 아울러 Karabiner를 사용할 경우, 다음 링크를 참고하세요.
- Windows의 경우, 기본 IME에서는 문제없이 작동하지만 날개셋 등의 서드파티 IME에서는 잘 작동하지 않습니다. Emacs에서는 기본 IME로 전환하고 사용하세요.
;; IME 목록: 2벌식, 3벌식(390 / 391), 일본어
;; 다른 언어를 추가하는 것도 가능합니다.
(defconst *usr-input-method-list*
'("korean-hangul"
"korean-hangul390"
"korean-hangul3f"))
(setq default-input-method "korean-hangul") ;; 2벌식을 기본 입력 방식으로 설정
;; 단축키 설정:
;; Ctrl + \ 키를 누르면 IME 간의 전환을 수행합니다.
;; Shift + Space 또는 Ctrl + x Ctrl + \ 키를 누르면 IME와 영어 간의 전환을 수행합니다.
(global-set-key [?\C-\\] 'my/usr-input-index-cycle)
(global-set-key [?\S- ] 'my/usr-input-method-toggle)
(global-set-key [?\C-x ?\C-\\] [?\S- ])
;; 현재 IME 상태 변수 설정
(defvar *usr-input-method--index* 0 "Index of current input method. Default: 2벌식.")
;; IME 간의 전환 함수
(defun my/usr-input-index-cycle (&optional skip)
"Update `*use-input-method-inex*' by adding SKIP (default 0) and wrapping if necessary, then call the function at this index in `use-input-ethod-list'."
(interactive)
(setq *usr-input-method--index* (+ *usr-input-method--index* (or skip 1)))
;; BUG: skips with an absolute value bigger than 1 don't wrap properly.
(if (>= *usr-input-method--index* (length *usr-input-method-list*))
(setq *usr-input-method--index* 0)
(when (< *usr-input-method--index* 0)
(setq *usr-input-method--index* (1- (length *usr-input-method-list*))) ))
(set-input-method (nth *usr-input-method--index* *usr-input-method-list*))
(message "Current IME: %S" (nth *usr-input-method--index* *usr-input-method-list*)))
;; IME - 영어 간의 전환 함수
(defun my/usr-input-method-toggle ()
(interactive)
(if (eq current-input-method nil)
(set-input-method (nth *usr-input-method--index* *usr-input-method-list*))
(set-input-method nil)))가독성을 위해 전역적으로 줄바꿈이 이루어지도록 설정합니다.
(global-visual-line-mode t)모드 라인에 2018-06-03 16:06 형식으로 시간을 표시합니다.
(setq display-time-format "[%Y-%m-%d %H:%M]")
(display-time-mode 1)모든 문장이 단일 공백으로 끝을 맺도록 설정합니다.
(setq sentence-end-double-space nil)Emacs는 yes / no, y / n 중 하나의 방식을 사용해 명령의 실행 여부를 입력하도록 합니다. 이는 개발자가 임의로 설정한 것이지만, IME가 한글로 설정되어 있는 경우에는 yes든 y든 입력되지 않는 사태가 발생합니다. 따라서 quick-yes 패키지를 사용해 M-y, M-n 키에 각각 yes와 no를 할당합니다.
참고:
(use-package quick-yes)
Home 및 End 키가 줄의 처음과 끝으로 이동시키도록(각각 C-a, C-e에 해당) 키를 할당합니다.
(global-set-key [home] 'move-beginning-of-line)
(global-set-key [end] 'move-end-of-line)툴바, 메뉴바, 스크롤바를 비활성화합니다.
;; ref: https://git.sr.ht/~technomancy/better-defaults
(unless (eq window-system 'ns)
(menu-bar-mode -1))
(when (fboundp 'tool-bar-mode)
(tool-bar-mode -1))
(when (fboundp 'scroll-bar-mode)
(scroll-bar-mode -1))
(when (fboundp 'horizontal-scroll-bar-mode)
(horizontal-scroll-bar-mode -1))운영체제와 DPI 에 맞추어, 자동으로 텍스트 크기를 조정하는 함수를 설정합니다. 기본적인 폰트는 D2Coding이며, 가독성을 위해 기본 폰트보다 크게 설정되어 있습니다. 더 많은 텍스트를 화면에 표시하고 싶다면 x-font-height 값을 조절하면 됩니다.
;; select fonts
;;; refs: [1] https://github.com/syl20bnr/spacemacs/issues/9445
;;; [2] https://emacs.stackexchange.com/questions/28390/quickly-adjusting-text-to-dpi-changes
;;; [3] https://harfangk.github.io/2018/07/21/using-korean-in-spacemacs-ko.html (단 iso10646 대신 iso10646-1로 설정
;;; [4] https://github.com/rolandwalker/unicode-fonts
;; (defvar *unicode-font-block*
;; '(;; common
;; ("Currency Symbols" #x20A0 #x20CF)
;; ("CJK Symbols and Punctuation" #x3000 #x303F)
;; ("Enclosed CJK Letters and Months" #x3200 #x32FF)
;; ("Halfwidth and Fullwidth Forms" #xFF00 #xFFEF)
;; ;; Korean
;; ("Hangul Jamo" #x1100 #x11FF)
;; ("Hangul Compatibility Jamo" #x3130 #x318F)
;; ("Hangul Jamo Extended-A" #xA960 #xA97F)
;; ("Hangul Jamo Extended-B" #xD7B0 #xD7FF)
;; ("Hangul Syllables" #xAC00 #xD7AF)
;; ;; korean-specific
;; ("K Currency Symbols" #x20a9 #x20a9)
;; ("K CJK Symbols and Punctuation" #x302e #x302f)
;; ("KP Enclosed CJK Letters and Months" #x3200 #x321e)
;; ("KC Enclused CJK Letters and MOnths" #x3260 #x327f)
;; ("K Halfwidth and Fullwidth Forms" #xffa1 #xffdc)
;; ("KW Halfwidth and Fullwidth Forms" #xffe6 #xffe6)))
(defun my/select-kr-font (opt)
"화면의 해상도와 dpi에 맞게 폰트 크기를 조절합니다."
(when window-system
(let* ((attrs (car (display-monitor-attributes-list)))
(size (assoc 'mm-size attrs))
(sizex (cadr size))
(res (cdr (assoc 'geometry attrs)))
(resx (- (cadr (cdr res)) (car res)))
(dpi (* (/ (float resx) sizex) 25.4)))
(cond ((< dpi 110)
(setq x-font-height 14))
((< dpi 130)
(setq x-font-height 16))
((< dpi 160)
(setq x-font-height 18))
(t (setq x-font-height 20))))
(cond
((string= opt "c") ;; "c" means "codding"
(set-face-attribute 'default nil :font (format "%s:pixelsize=%d" "IBM Plex Mono" (- x-font-height 1)))
(set-fontset-font "fontset-default" '(#x1100 . #x11ff) (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height))
(set-fontset-font "fontset-default" '#x20a9 (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height))
(set-fontset-font "fontset-default" '(#x302e . #x302f) (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height))
(set-fontset-font "fontset-default" '(#x3130 . #x318f) (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height))
(set-fontset-font "fontset-default" '(#x3200 . #x321e) (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height))
(set-fontset-font "fontset-default" '(#x3260 . #x327f) (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height))
(set-fontset-font "fontset-default" '(#xa960 . #xa97f) (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height))
(set-fontset-font "fontset-default" '(#xac00 . #xd7a3) (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height))
(set-fontset-font "fontset-default" '(#xd7b0 . #xd7ff) (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height))
(set-fontset-font "fontset-default" '(#xffa1 . #xffdc) (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height))
(set-fontset-font "fontset-default" '#xffe6 (font-spec :family "D2Coding" :registry "iso10646-1" :size x-font-height)))
((string= opt "s") ;; "s" means serif
(set-face-attribute 'default nil :font (format "%s:pixelsize=%d" "Noto Serif KR" (- x-font-height 2))))
((string= opt "ss") ;; "ss" means san-serif
(set-face-attribute 'default nil :font (format "%s:pixelsize=%d" "Noto Sans CJK KR" (- x-font-height 2)))))
(set-face-attribute 'mode-line nil :font (format "%s:pixelsize=%d" "D2Coding" (- x-font-height 1)))))Emacs는 기본적으로 백업, 자동저장, 히스토리 파일을 소스 파일과 동일한 폴더에 저장합니다. 따라서 Emacs를 사용하다 보면 폴더가 지저분해지는 현상이 발생합니다. 이러한 임시 파일을 한데 모아 이를 방지합니다. 공간이 부족할 경우 해당 폴더들 (backup, auto-save-list, savehist)의 내용물을 비워서 디스크 용량을 확보할 수 있습니다.
;; 백업 디렉토리
(setq backup-directory-alist `((".*" . ,(concat user-emacs-directory "backup/"))))
;; 백업 / 버전관리 설정
(setq version-control t ;; enable VC
vc-make-backup-files t ;; generate backup files
kept-old-versions 0 ;; do not keep oldest versions
ketp-new-versions 10 ;; keep many newest versions
delete-old-versions t) ;; automatically delete outdated backups
;; 자동저장 디렉토리
(setq auto-save-file-name-transforms `((".*" ,(concat user-emacs-directory "auto-save-list/") t)))
;; 히스토리 설정
(savehist-mode 1)
(setq savehist-file (concat user-emacs-directory "savehist")) ;; 히스토리 파일
(setq history-length t) ;; 전체 히스토리 저장
(setq history-delete-duplicates t) ;; 중복된 히스토리 내역은 제거
(setq savehist-save-minibuffer-history 1) ;; 미니버퍼 히스토리 저장
(setq savehist-additional-variables
'(kill-ring
search-ring
regexp-search-ring)) ;; 추가적으로 저장할 히스토리 내역 설정윈도우 환경에서, 가끔 왼쪽 윈도우키를 super 키로 인식하지 않는 경우가 있습니다. 이를 설정합니다.
(setq w32-lwindow-modifier 'super)이 섹션에서는 패키지들을 설치하거나 설정합니다. 패키지의 효율적인 관리를 위해 use-package를 사용합니다. 또한, .org 형식의 파일을 읽어들이기 위해 org-mode도 설치되었다고 가정합니다. 처음 이 설정파일을 적용하면, freshstart.el 파일을 실행해 org-mode를 설치하도록 합니다.
use-package를 설치하는 방법에 관한 내용은 use-package 설치를 참조하세요.
아래 코드들에 포함된 옵션들에 대한 간단한 설명입니다.
:defer: Emacs 로드 시 동시에 실행하는 것이 아니라, 필요할 때에만 로드하도록 하여 초기 기동 시간을 절약합니다.
org-mode는 설정 파일을 불러오는 데에도 쓸 수 있지만, 그 외에도 수많은 기능을 수행할 수 있습니다. 블로그를 작성하는 데에도, 노트를 작성하는 데에도, 스케쥴을 관리하는 데에도, 할일을 정리하는 데에도 쓸 수 있습니다.
앞에서 썼듯이 org-mode는 초기에 이미 설치되어 있습니다. 다만 최신 버전이 아니므로, 업데이트 및 추가 설정을 진행합니다.
;; org 공식 저장소가 작동하지 않을 경우를 대비하여 깃헙 저장소를 추가합니다.
(condition-case nil
(use-package org-plus-contrib
:mode (("\\.org$" . org-mode))
:config (my/org-setting))
(error
(use-package org-plus-contrib
:straight (org-plug-contrib :type git :host github :repo "bzg/org-mode"
:local-repo "org" :files (:defaults "contrib/lisp/*.el"))
:mode (("\\.org$" . org-mode))
:config (my/org-setting))))
(defun my/org-setting ()
"orgmode 설치 후 추가 설정을 진행합니다."
;; 기본적으로 org-mode는 shift + 방향키로 블록 선택하는 것을 막아놓고 있습니다. 이를 옵션을 통해 해제해 줍니다.
(setq org-support-shift-select t)
;; org-mode 문서를, 항목의 깊이에 따라 들여쓰기된 상태로 보이도록 설정합니다. 단, heading의 star는 숨기지 않습니다.
(progn
(setq org-startup-indented t)
(setq org-hide-leading-stars nil)
(setq org-adapt-indentation n)
(setq org-src-preserve-indentation t)
(setq org-indent-mode-turns-on-hiding-stars nil)
)
;; org-mode는 기본적으로 강조문(굵게, 이탤릭 등)을 하나의 단어에 대해서만 적용하도록 하고 있습니다. 예컨대 *이렇게*는 굵게 글씨를 쓸 수 없습니다. 조사가 들어가는 한중일 언어에 쓰기에는 부적절한 정책입니다. 따라서 강조문자 양 옆에 (알파벳이 아닌) 멀티바이트 문자가 오더라도 작동하도록 설정을 변경합니다(물론 이는 완전한 해결책은 아니며, 더 합리적인 방법에 대해서는 고민이 필요합니다.
(setcar org-emphasis-regexp-components " \t('\"{[:multibyte:]")
(setcar (nthcdr 1 org-emphasis-regexp-components) "[:multibyte:]- \t.,:!?;'\")}\\")
(org-set-emph-re 'org-emphasis-regexp-components org-emphasis-regexp-components)
; my/org-setting continues beloworg-mode는 기본적으로 많은 모듈을 포함하고 있으므로, 필요한 모듈만 포함시켜 실행 속도를 높입니다.
- 어떤 모듈이 있는지는 다음을 참고하세요.
- 참고: Sacha Chua
;; continued in my/org-setting
(setq org-modules `(org-bibtex
org-docview
org-info
org-mouse
org-eval
org-tempo
org-screen))
(org-load-modules-maybe t)) ;;use-package org Ends외부 모듈들은 use-package를 사용해 불러옵니다.
(use-package ox-mediawiki)(use-package org-journal
:config
(setq org-journal-dir "~/Dropbox/Texts/orgs/journal/")
)org-mode는 여러 형식으로 org 파일을 출판할 수 있게 합니다. 이 섹션에서는 관련한 설정을 정리합니다.
우선 latex 관련 설정입니다.
;; latex에 export할 때 사용할 사용자 지정 class를 정의합니다.
;; 참고: https://superuser.com/questions/896741/how-do-i-configure-org-latex-classes-in-emacs
(with-eval-after-load 'ox-latex
;; ** <<Dissertation>>
(add-to-list 'org-latex-classes
'("dissertation"
"\\documentclass[12pt,a4paper]{report}"
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
;; ** <<APS journals>>
;; ref: https://github.com/jkitchin/jmax
(add-to-list 'org-latex-classes
'("revtex4-1"
"\\documentclass{revtex4-1}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
)
;; LaTeX 변환을 위해 필요한 PATH 설정을 추가합니다.
(getenv "PATH")
(cond
((eq system-type 'darwin)
(setenv "PATH"
(concat
"/Library/TeX/texbin" ":" (getenv "PATH")))))
;; pdf 변환 시 bibtex를 제대로 처리하기 위한 설정
(setq org-latex-pdf-process '("xelatex -interaction nonstopmode %f" "bibtex %b" "xelatex -interaction nonstopmode %f" "xelatex -interaction nonstopmode --synctex=-1 %f"))
;; LaTeX 수식을 미리볼 수 있도록 프로그램을 설정합니다.
(setq org-latex-create-formula-image-program 'dvipng)
;; orgmode에서 LaTeX로 export할 때에는 기본적으로 label을 자동으로 생성해서 사용하므로, \ref 등을 사용하는 데에 어려움이 있습니다. 사용자 지정 label을 사용할 수 있게 설정을 바꾸어 줍니다.
(setq org-latex-prefer-user-labels t)Hugo로 출판하는 데에 쓰이는 ox-hugo 관련 설정입니다.
(use-package ox-hugo
:after ox)org-roam은 org-mode에 second brain 및 Zettelkasten 방식 워크플로우를 추가시키는 패키지입니다.
(use-package org-roam
:ensure t
:hook
(after-init . org-roam-mode)
:custom
(org-roam-directory (file-truename "~/ROAM/"))
:bind (:map org-roam-mode-map
(("C-c n l" . org-roam)
("C-c n f" . org-roam-find-file)
("C-c n g" . org-roam-graph))
:map org-mode-map
(("C-c n i" . org-roam-insert))
(("C-c n I" . org-roam-insert-immediate))))org-roam-ui를 통해 org-roam의 graph 기능을 좀 더 동적으로 확장시킵니다.
(use-package org-roam-ui
:straight
(:host github :repo "org-roam/org-roam-ui" :branch "main" :files ("*.el" "out"))
:after org-roam
;; normally we'd recommend hooking orui after org-roam, but since org-roam does not have
;; a hookable mode anymore, you're advised to pick something yourself
;; if you don't care about startup time, use
;; :hook (after-init . org-roam-ui-mode)
:config
(setq org-roam-ui-sync-theme t
org-roam-ui-follow t
org-roam-ui-update-on-save t
org-roam-ui-open-on-start t))Emacs 29부터는 native comp를 지원합니다. 컴파일 과정에서 발생하는 많은 warning은 대부분 사용자가 어떻게 할 수 없는 것이므로, 끄는 것이 간편합니다.
(setq native-comp-async-report-warnings-errors 'silent)Emacs Lisp 컴파일러는 인간이 해독할 수 있는 소스 코드(.el) 파일을 바이트 컴파일(byte-compile, .elc) 파일로 변환하는 기능을 포함하고 있습니다. 유의해야 할 점은, 바이트 컴파일 파일 자체는 인터프리터가 해석하고 실행하며, 단지 사람이 아닌 기계가 해석할 수 있도록 변환한다는 것입니다. 따라서 바이트 컴파일은 일반적인 인터프리터보다는 빠르지만, 네이티브 컴파일보다는 느립니다. 자세한 사항은 Emacs 메뉴얼을 참고하세요.
Emacs에는 Lisp 라이브러리를 전부 바이트 컴파일시켜주는 패키지가 있으므로, 그것을 사용합니다.
;; load-prefer-newer 옵션은 파일 첫 부분으로 올립니다.
(use-package auto-compile
:init
(setq auto-compile-display-buffer nil)
(setq auto-compile-mode-line-counter t)
(setq auto-compile-source-recreate-deletes-dest t)
(setq auto-compile-toggle-deletes-nonlib-dest t)
(setq auto-compile-update-autoloads t)
:hook (auto-compile-inhibit-compile . auto-compile-inhibit-compile-detached-git-head)
:config
(auto-compile-on-load-mode)
(auto-compile-on-save-mode)) winner-mode는 윈도우 레이아웃 상태를 저장하고, 레이아웃 간의 undo / redo를 지원하는 모드입니다. 예컨대 윈도우를 세로로 분할해 다른 버퍼의 내용을 확인한 다음 C-c <left> 키를 눌러 되돌아갈 수 있습니다.
(use-package winner
:config (winner-mode))Emacs를 편하게 사용하기 위한 인터페이스 관련 패키지들의 모음입니다.
ivy는 Emacs의 자동완성 기능을 확장시켜 주는 패키지입니다. 기존에 쓰이던 Helm은 다양한 기능을 제공하고 있지만, 그 반대급부로 구동이 무거워지는 단점이 있어서 많은 사람들이 선택하는 대안입니다(참고: From helm, to ivy, Hello Ivy-mode, bye Helm 등).
(use-package ivy
:diminish (ivy-mode . "")
:init (ivy-mode 1) ;;global setup
(setq ivy-use-virtual-buffers t)
(setq enable-recursive-minibuffers t)
(setq ivy-count-format "%d/%d "))
(use-package swiper
:config
;; enable this if you want `swiper' to use it
(setq search-default-mode #'char-fold-to-regexp))
(use-package counsel
:config
(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> 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))Emacs를 전체화면으로 표시하고, 불필요한 요소들은 숨겨서 글쓰기에 집중할 수 있도록 하는 모드입니다.
(use-package writeroom-mode)wc-mode는 모드 라인에 단어수를 표시하는 패키지입니다.
(use-package wc-mode
:config
(setq wc-modeline-format
(concat "[%tw" (if wc-word-goal "/%gw") "w %tc" (if wc-char-goal
"/%gc") "c]"))
:bind ("C-c w" . wc-mode)) undo-tree는 버퍼의 변경사항 내역을 저장하고 시각적으로 보여주는 패키지입니다.
(use-package undo-tree
:diminish undo-tree-mode
:config
(progn
(global-undo-tree-mode 1) ;; 모든 버퍼에서 실행 가능하도록
;; undo-redo 단축키 설정
;; ref: http://pragmaticemacs.com/emacs/advanced-undoredo-with-undo-tree/
(defalias 'redo 'undo-tree-redo)
(cond
((eq system-type 'darwin)
(global-set-key (kbd "s-z") 'undo)
(global-set-key (kbd "s-S-z") 'redo))
(
(global-set-key (kbd "C-z") 'undo)
(global-set-key (kbd "C-S-z") 'redo)))
(setq undo-tree-visualizer-timestamps t)
(setq undo-tree-visualizer-diff t)))많은 모던 에디터, 예컨대 sublime text나 atom, vscode처럼 사이드바에 트리 기능을 지원하도록 하는 패키지입니다. 이전에는 neotree를 사용했으나, treemacs가 여러 모로 더 낫다고 알려져 있습니다.
(use-package treemacs
:requires (f s dash ace-window pfuture ht hydra)
:bind
(:map global-map
("M-0" . treemacs-select-window)
("C-x t 1" . treemacs-delete-other-windows)
("C-x t t" . treemacs)
("C-x t B" . treemacs-bookmark)
("C-x t C-t" . treemacs-find-file)
("C-x t M-t" . treemacs-find-tag)))
;; magit과 연동되는 treemacs-magit 패키지 설치
(use-package treemacs-magit
:after treemacs magit)
;; 아이콘 설치
(use-package treemacs-icons-dired
:after treemacs dired
:config (treemacs-icons-dired-mode))
eyebrowse는 Emacs에서 기본으로 제공하는 윈도우 배열 관리를 더 쉽게 해 주는 패키지입니다. 모드 라인에 현재 윈도우 설정을 표시하며, 레이아웃 간의 전환을 위한 명령을 추가해 줍니다.
(condition-case nil
(use-package eyebrowse
:init
(add-to-list 'window-persistent-parameters '(window-side . writable))
(add-to-list 'window-persistent-parameters '(window-slot . writable))
:config
(eyebrowse-mode t)
)
(error
; if error use github version; archived repo from May 2020
(use-package eyebrowse
:straight (eyebrowse :type git :host github :repo "wasamasa/eyebrowse")
:init
(add-to-list 'window-persistent-parameters '(window-side . writable))
(add-to-list 'window-persistent-parameters '(window-slot . writable))
:config
(eyebrowse-mode t)
)))magit은 Emacs 상에서 Git 파일을 관리하는 솔루션입니다.
(use-package magit
:defer 2
)여러 문서를 작성하는 데에 필요한 마크업에 대한 패키지들입니다.
(use-package markdown-mode
:commands (markdown-mode gfm-mode)
:mode (("README\\.md\\'" . gfm-mode)
("\\.md\\'" . markdown-mode)
("\\.markdown\\'" . markdown-mode))
:init (setq markdown-command "multimarkdown")) ;; 기본적인 마크다운 렌더링 엔진으로 multimarkdown을 설정합니다.AUCTeX는 Emacs에서 더 편하게 LaTeX 파일을 편집하도록 도와주는 패키지입니다.
(use-package tex
:straight auctex ;; auctex.el이 자동으로 로드되지 않는 문제 해결
:config
(setq TeX-auto-save t))asciidoc을 지원하기 위한 패키지를 추가합니다.
(use-package adoc-mode
:requires markup-faces
:mode "\\.adoc?\\'")
(use-package markup-faces
:config
(set-face-attribute 'markup-meta-face nil
:height 1.0
:foreground (face-attribute 'font-lock-comment-face :foreground)))miniedit 패키지는 미니버퍼의 편집을 더 빠르게 할 수 있도록 합니다.
(use-package miniedit
:commands minibuffer-edit
:init (miniedit-install))guide-key는 복잡한 키 바인딩을 다 외울 필요 없이, 특정 조합의 키를 누르면 그에 해당하는 바인딩의 목록을 나타냅니다.
(use-package guide-key
:diminish guide-key-mode
:config
(progn
(setq guide-key/guide-key-sequence '("C-x r" "C-x 4" "C-c"))
(guide-key-mode 1))) ; Enable guide-key-modeDeft는 텍스트 파일들을 쉽게 탐색하고, 읽고, 작성할 수 있도록 도와주는 패키지입니다. Notational Velocity와 비슷한 역할을 한다고 이해하면 될 것입니다.
(use-package deft
:bind ("<f8>" . deft)
:commands (deft)
:config
(setq deft-extensions '("txt" "org" "md")
deft-directory "~/Dropbox/Texts"
deft-recursive t ; indexing subdirectories
deft-use-filename-as-title t))(use-package mediawiki
:defer 2
)괄호를 자동완성시키는 기능을 제공합니다.
(use-package smartparens
:config
(progn
(require 'smartparens-config))) ;; 기본 설정. M-x smartparens-mode를 통해서 언제든지 실해할 수 있습니다.(use-package php-mode)Emacs 내부에서 자체적으로 pdf 파일을 읽는 기능을 제공합니다. 외부 라이브러리의 설치를 필요로 합니다. 다만, 설정에 번거로운 부분이 있기 때문에 기본적인 설정의 경우 안정화될 때까지는 구현만 해놓고 실제로 설치하지는 않습니다. 설치를 원하면 org 소스 파일의 :tangle no 부분을 :tangle yes 로 수정하면 됩니다.
(use-package pdf-tools
:config
(pdf-tools-install)
(cond ;;; OS check: setting epdfinfo setting depends on OS
((eq system-type 'windows-nt)
(setenv "PATH" (concat "C:\\msys64\\mingw64\\bin;" (getenv "PATH"))))
)
)현재 설정에서 선택 가능한 테마는 gruvbox, seoul256입니다.
(use-package gruvbox-theme
:init
(load-theme 'gruvbox t))(use-package seoul256-theme
:init
(setq seoul256-background 233
seoul256-alternate-background 252)
(load-theme 'seoul256 t))(use-package smart-mode-line
:config
(setq sml/no-confirm-load-theme t)
(setq sml/theme 'respectful)
(setq sml/name-width 20)
(setq sml/mode-width 'full)
(setq sml/shorten-directory t)
(setq sml/shorten-modes t)
(sml/setup)
(my/select-kr-font "c"))마치 바이트 컴파일처럼, org 파일(그러니까 현재 파일)을 바로 읽어들이는 것보다는 포함된 소스 코드를 따로 정리해 로드하는 것이 더 실행속도가 빠릅니다. 이를 위해, 다음과 같이 async 패키지를 사용해 org 파일을 변경할 때마다 config.el 파일을 업데이트합니다.
(use-package async)
(defvar *config-file* (expand-file-name "config.org" user-emacs-directory)
"설정을 기록한 org 파일입니다.")
(defvar *config-last-change* (nth 5 (file-attributes *config-file*))
"가장 최근에 설정을 변경한 시간입니다.")
(defvar *show-async-tangle-results* nil
"비동기 작업 버퍼를 보존해 이후에도 쓸 수 있도록 합니다.")
(defun my/config-updated ()
"마지막으로 업데이트한 시간 이후에 설정 파일이 변경되었는지 확인합니다."
(time-less-p *config-last-change*
(nth 5 (file-attributes *config-file*))))
(defun my/config-tangle ()
"org 파일을 비동기적으로 변환합니다."
(when (my/config-updated)
(setq *config-last-change*
(nth 5 (file-attributes *config-file*)))
(my/async-babel-tangle *config-file*)))
(defun my/async-babel-tangle (org-file)
"org 파일을 비동기적으로 변환합니다."
(let ((init-tangle-start-time (current-time))
(file (buffer-file-name))
(async-quiet-switch "-q"))
(async-start
`(lambda ()
(require 'org)
(org-babel-tangle-file ,org-file))
(unless *show-async-tangle-results*
`(lambda (result)
(if result
(message "성공: %s을(를) 성공적으로 변환했습니다 (%.2fs)."
,org-file
(float-time (time-subtract (current-time)
',init-tangle-start-time)))
(message "오류: %s을(를) 변환하는 데 실패했습니다." ,org-file)))))))
(add-hook 'after-save-hook 'my/config-tangle) ;; 파일을 저장하면 파일을 변환하도록 지정합니다.이 설정파일은 비주기적으로 업데이트됩니다. 매번 git 저장소에서 수동으로 업데이트하는 불편함을 줄이기 위해, 자동으로 git pull 및 설정 파일 업데이트를 수행하는 함수를 제공합니다.
(defun my/config-pull ()
"설정 파일을 git 저장소에서 pull하여 업데이트 후, 받은 파일을 실행합니다."
(interactive)
(message "Pull from git repository...")
(shell-command "git -C ~/.emacs.d pull")
(my/config-tangle)
(load "~/.emacs.d/init.el")
)