(let* ((normal-gc-cons-threshold (* 20 1024 1024))
(init-gc-cons-threshold (* 128 1024 1024)))
(setq gc-cons-threshold init-gc-cons-threshold)
(add-hook 'emacs-startup-hook
(lambda () (setq gc-cons-threshold normal-gc-cons-threshold))))
(setq read-process-output-max (* 1024 1024))
(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))
(require 'package)
(let* ((no-ssl (and (memq system-type '(windows-nt ms-dos))
(not (gnutls-available-p))))
(proto (if no-ssl "http" "https")))
;; Comment/uncomment these two lines to enable/disable MELPA and MELPA Stable as desired
(add-to-list 'package-archives (cons "melpa" (concat proto "://melpa.org/packages/")) t)
;; (add-to-list 'package-archives (cons "melpa-stable" (concat proto "://stable.melpa.org/packages/")) t)
(when (< emacs-major-version 24)
;; For important compatibility libraries like cl-lib
(add-to-list 'package-archives '("gnu" . (concat proto "://elpa.gnu.org/packages/"))))
)
(unless package--initialized (package-initialize t))
패키지 관리에 use-package를 적극 이용한다. 하지만 아직도 개별 설정에 의문스러운 점이 많다.
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
use-package
가 편한 이유 중 하나는 필요한 패키지를 elpa에서 직접 가져오기 때문이다. 그런데 설정마다 :ensure t
를 설정해줘야 자동으로 진행하는데 번거로우므로 전역변수로 설정해둔다.
(setq use-package-always-ensure t)
(defmacro when-linux (&rest body)
(list 'if (string-match "linux" (prin1-to-string system-type))
(cons 'progn body)))
(defmacro when-windows (&rest body)
(list 'if (string-match "windows" (prin1-to-string system-type))
(cons 'progn body)))
(defmacro when-mac (&rest body)
(list 'if (string-match "darwin" (prin1-to-string system-type))
(cons 'progn body)))
GUI 모드나 맥 환경에서 emacs를 실행하면 설정되어 있던 PATH
환경변수가 emacs에 적용되지 않을 수 있다. exec-path-from-shell 패키지를 이용하여 싱크를 맞춘다.
(use-package exec-path-from-shell
:if (memq window-system '(darwin mac ns x))
:ensure t
:config
(exec-path-from-shell-initialize))
I need this configuration.
(when enable-multibyte-characters
(set-language-environment "Korean")
(setq-default file-name-coding-system 'utf-8)
(setq default-input-method "korean-hangul")
(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8))
(when-windows (set-file-name-coding-system 'euc-kr)
(global-set-key (kbd "S-SPC") 'toggle-input-method)
(global-set-key (kbd "<Hangul>") 'toggle-input-method)
(global-set-key (kbd "<Hangul_Hanja>") 'hangul-to-hanja-conversion))
MacOS 일 경우, 파일시스템에서 한글이 제대로 나오게 하기 위해서 아래와 같이 설정한다.
(when-mac (require 'ucs-normalize)
(set-file-name-coding-system 'utf-8-hfs)
(setq default-process-coding-system '(utf-8-hfs . utf-8-hfs)))
(use-package files
:ensure nil
:config
(setq confirm-kill-processes nil
make-backup-files nil))
Auto refreshes every 3 seconds.
(use-package autorevert
:ensure nil
:config
(global-auto-revert-mode +1)
(setq auto-revert-interval 3
auto-revert-check-vc-info t
auto-revert-non-file-buffers t
auto-revert-verbose nil))
If the file ~/.emacs.d/.custom.el
exist, load it.
(setq custom-file (expand-file-name ".custom.el" user-emacs-directory))
(when (file-exists-p custom-file)
(load custom-file))
(setq browse-url-browser-function 'browse-url-generic)
(setq browse-url-generic-program "google-chrome")
Helm이 유지보수되지 않는 것 같아 다른 대안을 써볼 계획이다. 우선 minibufer completion system으로 vertico.el을 사용한다.
(use-package vertico
:init
(vertico-mode))
completion 시스템 이용 시 찾고하 하는 아이템의 이름을 처음부터 입력하지 않아도 되게 Orderless를 사용한다.
(use-package orderless
:custom
(completion-styles '(orderless basic)))
consult.el도 사용한다.
(use-package consult
:bind
(("C-x b" . consult-buffer)
("M-g M-g" . consult-goto-line)))
minibuffer completion이 작동 중일 때 남은 영역에 추가 정보를 표시하게 하기 위해 marginalia.el을 사용한다.
(use-package marginalia
:init
(marginalia-mode))
text-mode를 사용할 경우 visual-line-mode를 활성화 한다.
(add-hook 'text-mode-hook #'visual-line-mode)
auto-fill-mode
에서 작성한 plain text 문서의 개행문자를 없애주는 함수를 정의한다. Emacs Wiki에서 가져왔다. 이게 왜 기본 코드로 추가되어 있지 않은지 모르겠다.
(defun unfill-region (beg end)
"Unfill the region, joining text paragraphs into a single
logical line. This is useful, e.g., for use with
`visual-line-mode'."
(interactive "*r")
(let ((fill-column (point-max)))
(fill-region beg end)))
전체적으로 쓰이는 단축키를 등록한다.
(global-set-key (kbd "C-M-Q") 'unfill-region)
(global-set-key (kbd "M-u") 'upcase-dwim)
(global-set-key (kbd "M-l") 'downcase-dwim)
(global-set-key (kbd "M-c") 'capitalize-dwim)
(use-package which-key
:config (which-key-mode))
Hide tool-bar
and scroll-bar
.
(mapc
(lambda (mode)
(if (fboundp mode)
(funcall mode -1)))
'(tool-bar-mode scroll-bar-mode))
(use-package doom-themes
:init (load-theme 'doom-one t)
:config
(setq doom-themes-enable-bold t
doom-themes-enable-italic t)
(doom-themes-visual-bell-config)
(doom-themes-neotree-config)
(doom-themes-org-config))
아이콘 폰트를 쓰기 위해서는 nerd-icons을 설치해야 한다. M-x nerd-icons-install-fonts
명령으로 설치하면 된다.
(use-package doom-modeline
:hook (after-init . doom-modeline-mode)
:config
(setq doom-modeline-height 68)
(setq doom-modeline-project-detection 'auto))
;; (setq doom-modeline-buffer-file-name-style 'auto)
;; (setq doom-modeline-icon t)
;; (setq doom-modeline-time-icon t))
;; (require 'fontutil)
(set-face-attribute 'default nil :font "Cascadia Code PL" :width 'condensed :weight 'semi-light)
;; (set-face-attribute 'default nil :font "Liberation Mono")
;; (set-face-attribute 'default nil :font "D2Coding ligature" :height 120)
;; (set-face-attribute 'default nil :font "Fira Code" :height 120)
;; (set-face-attribute 'default nil :font "Hack" :height 120)
;; (set-face-attribute 'default nil :font "Dejavu Sans Mono" :height 120)
(set-fontset-font t '(#X1200 . #Xa95f) '("D2Coding" . "unicode-bmp"))
(set-fontset-font t '(#Xac00 . #Xd7af) '("D2Coding" . "unicode-bmp"))
(set-fontset-font t '(#X1100 . #X11ff) '("함초롬돋움" . "unicode-bmp"))
(set-fontset-font t '(#Xa960 . #Xa97c) '("함초롬돋움" . "unicode-bmp"))
(set-fontset-font t '(#Xd7b0 . #Xd7fb) '("함초롬돋움" . "unicode-bmp"))
(set-fontset-font t '(#Xe0bc . #Xefff) '("함초롬돋움" . "unicode-bmp"))
(set-fontset-font t '(#Xf100 . #Xf66e) '("함초롬돋움" . "unicode-bmp"))
(set-fontset-font t 'han '("Noto Sans CJK KR" . "unicode-bmp"))
(setq-default line-spacing 5)
;; (when-linux (fontutil/set-font "cascadia-14")))
;; (when-mac (fontutil/set-font "firacode-14")
;; (setq-default line-spacing 3))
;; (when-windows (fontutil/set-font "d2coding-14")
;; (setq-default line-spacing 4)))
라인번호를 특정 모드에 붙인다.
(use-package display-line-numbers-mode
:ensure nil
:hook (prog-mode text-mode conf-mode))
(use-package ob-http)
(use-package ob-rust)
(defface org-block-begin-line
'((t (:underline "#A7A6AA" :foreground "#008ED1" :background "#EAEAFF")))
"Face used for the line delimiting the begin of source blocks.")
(defface org-block-background
'((t (:background "#FFFFEA")))
"Face used for the source block background.")
(defface org-block-end-line
'((t (:overline "#A7A6AA" :foreground "#008ED1" :background "#EAEAFF")))
"Face used for the line delimiting the end of source blocks.")
(setq org-return-follow-link t
org-startup-indented 't
org-ditaa-jar-path "~/.emacs.d/ditaa.jar")
(org-babel-do-load-languages 'org-babel-load-languages '((shell . t)
(python . t)
(ditaa . t)
(emacs-lisp . t)
(http . t)
(rust . t)))
(setq org-agenda-files '("~/Dropbox/org/inbox.org"
"~/Dropbox/org/projects.org"
"~/Dropbox/org/repeaters.org"))
(setq org-refile-targets
'(("~/Dropbox/org/todo.org" :maxlevel . 3)
("~/Dropbox/org/projects.org" :maxlevel . 2)))
(setq org-refile-use-outline-path 'file)
(setq org-outline-path-complete-in-steps nil)
(setq org-refile-allow-creating-parent-nodes 'confirm)
(setq org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)")
(sequence "WAIT(w@/!)" "HOLD(h@/!)" "|" "CANCELED(c@/!)")))
(setq org-capture-templates
'(("t" "📥 Todo" entry (file+headline "~/Dropbox/org/inbox.org" "Todos")
"* TODO %?\n %i\n %a")
("b" "📑 Bookmark" entry (file "~/Dropbox/org/bookmarks.org")
"* [[%^{링크 URL}][%^{링크 이름}]] %^g\n %i\n" :prepend t)
("r" "To Read Item" entry (file+headline "~/Dropbox/org/inbox.org" "To Read Items")
"* %?\n %T" :prepend t)))
(setq org-agenda-custom-commands
'((" " "Agenda"
((agenda ""
((org-agenda-span 'day)))
(todo "TODO"
((org-agenda-overriding-header "Unscheduled tasks")
(org-agenda-files '("~/Dropbox/org/inbox.org"))
(org-agenda-skip-function '(org-agenda-skip-entry-if 'scheduled 'deadline))))
(todo "TODO"
((org-agenda-overriding-header "Unscheduled projects tasks")
(org-agenda-files '("~/Dropbox/org/projects.org"))
(org-agenda-skip-function '(org-agenda-skip-entry-if 'scheduled 'deadline))))))))
(global-set-key (kbd "C-c c") #'org-capture)
(global-set-key (kbd "C-c a") #'org-agenda)
(defmacro func-ignore (fnc)
"Return function that ignore its arguments and invokes FNC"
`(lambda (&rest _rest)
(funcall ,fnc)))
(advice-add 'org-deadline :after (func-ignore #'org-save-all-org-buffers))
(advice-add 'org-schedule :after (func-ignore #'org-save-all-org-buffers))
(advice-add 'org-store-log-note :after (func-ignore #'org-save-all-org-buffers))
(advice-add 'org-todo :after (func-ignore #'org-save-all-org-buffers))
(require 'color)
(set-face-attribute 'org-block nil :background
(color-darken-name
(face-attribute 'default :background) 3))
(use-package org-bullets
:requires org
:hook (org-mode . (lambda () (org-bullets-mode 1))))
현재 emacs 최신 버전(emacs-29) 공식 릴리즈에서는 tree-siter를 기본적으로 포함하고 있지 않다. 그래서 --with-tree-sitter
옵션을 추가하여 소스 빌드해야 이 기능을 사용할 수 있다(더불어 소스 빌드 하는 김에 실행 속도를 높이기 위해 --with-native-compilation=
옵션도 추가하는 것이 좋음).
특정 언어 코딩 시에 tree-sitter를 이용하기 위해서는 해당 언어의 lagnuage grammer가 별도로 필요한데, M-x treesit-install-language-grammer
명령을 이용하여 필요한 패키지를 설치할 수 있다. 설치 위치는 ~/.emacs.d/tree-sitter
를 이용한다. 이것들은 소스로 부터 동적 라이브러리로 빌드하여 사용하므로 시스템에 빌드툴이 미리 설치되어 있어야 한다.
현재 사용하는 주요 언어는 아래와 같다.
(setq treesit-language-source-alist
'((bash "https://github.com/tree-sitter/tree-sitter-bash")
(cmake "https://github.com/uyha/tree-sitter-cmake")
(css "https://github.com/tree-sitter/tree-sitter-css")
(elisp "https://github.com/Wilfred/tree-sitter-elisp")
(go "https://github.com/tree-sitter/tree-sitter-go")
(html "https://github.com/tree-sitter/tree-sitter-html")
(javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src")
(json "https://github.com/tree-sitter/tree-sitter-json")
(make "https://github.com/alemuller/tree-sitter-make")
(python "https://github.com/tree-sitter/tree-sitter-python")
(toml "https://github.com/tree-sitter/tree-sitter-toml")
(tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")
(typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
(yaml "https://github.com/ikatyang/tree-sitter-yaml")))
ielm에서 (mapc #'treesit-install-language-grammar (mapcar #'car treesit-language-source-alist))
와 같은 명령으로 이 목록에 있는 모듈들을 한번에 설치할 수 있다.
projectile-indexing-method
를 alien
으로 지정하여 Windows에서도 이 방법을 쓰도록 강제한다. 자세한 내용은 이슈에서 확인할 수 있다. 메뉴얼은 여기에서 볼 수 있다.
(use-package projectile
:bind-keymap
("C-c p" . projectile-command-map)
:init
(projectile-mode +1)
:custom
(projectile-enable-caching t)
(projectile-indexing-method 'alien)
(projectile-completion-system 'default))
This is an awesome plugin as git client.
(use-package magit
:commands (magit-init
magit-status)
:bind ("C-x g" . magit-status))
“Why does compilation buffer show control characters?” 참조함.
Note: ansi-color-compilation-filter
is built in since emacs 28.1.
(require 'ansi-color)
(add-hook 'compilation-filter-hook 'ansi-color-compilation-filter)
(use-package editorconfig
:ensure t
:config (editorconfig-mode 1))
(use-package diff-hl
:ensure t
:init (global-diff-hl-mode)
:config
(add-hook 'magit-post-refresh-hook #'diff-hl-magit-post-refresh))
(use-package flycheck
:hook (after-init . global-flycheck-mode)
:config
(setq flycheck-check-syntax-automatically '(save idle-change mode-enabled)))
(use-package yasnippet
:defer 5
:diminish yas-minor-mode
:config (yas-global-mode 1))
(use-package yasnippet-snippets
:ensure t
:after yasnippet)
(use-package eldoc
:hook (emacs-lisp-mode ielm-mode rust-mode rust-ts-mode))
(setq eldoc-echo-area-prefer-doc-buffer t)
c-mode나 c++-mode 에서 lsp 서버로 ccls를 사용한다. clangd도 괜찮은 것 같으나 임베디드 소스트리에서 작업할 때 네비게이션 문제가 있다.
(use-package ccls
:hook ((c-mode c++-mode objc-mode sh-mode) .
(lambda () (require 'ccls) (eglot-ensure)))
:config (setq ccls-executable "~/.local/bin/ccls"))
(c-add-style "my-c-style"
'("linux"
(c-basic-offset . 4)))
(setq c-default-style "my-c-style")
먼저 llvm을 설치해야한다.
;; (use-package clang-format
;; :ensure t
;; :bind (:map c-mode-base-map
;; ("C-M-\\" . clang-format-region)))
(add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode))
(add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode))
(add-to-list 'major-mode-remap-alist
'(c-or-c++-mode . c-or-c++-ts-mode))
(use-package python
:mode ("\\.py\\'" . python-mode)
:interpreter ("python3" . python-mode)
:config
(add-hook 'python-mode-hook
(function (lambda ()
(setq indent-tabs-mode nil
tab-width 4
electric-indent-inhibit t)))))
(use-package elpy
:defer t
:init
(advice-add 'python-mode :before 'elpy-enable)
:config
(setq elpy-rpc-python-command "python3")
(setq python-shell-interpreter "python3")
(setq python-shell-interpreter-args "-i")
:bind (:map elpy-mode-map
("M-." . elpy-goto-definition)
("M-," . pop-tag-mark)))
(use-package pip-requirements
:config
(add-hook 'pip-requirements-mode-hook #'pip-requirements-auto-complete-setup))
(use-package py-autopep8)
;; (setq exec-path (append exec-path '("~/.cargo/bin")))
;; (use-package rust-mode
;; :init (add-hook 'rust-mode-hook (lambda () (setq indent-tabs-mode nil)))
;; :bind (:map rust-mode-map
;; ("C-c r" . rust-run)
;; ("C-c t" . rust-test)
;; ("C-c b" . cargo-process-build))
;; :config (setq rust-format-on-save t))
;; (use-package cargo
;; :hook (rust-mode . cargo-minor-mode))
(use-package rustic
:ensure
:bind (:map rustic-mode-map
("M-j" . lsp-ui-imenu)
("M-?" . lsp-find-references)
("C-c C-c l" . flycheck-list-errors)
("C-c C-c a" . lsp-execute-code-action)
("C-c C-c r" . lsp-rename)
("C-c C-c q" . lsp-workspace-restart)
("C-c C-c Q" . lsp-workspace-shutdown)
("C-c C-c s" . lsp-rust-analyzer-status)
("C-c C-c e" . lsp-rust-analyzer-expand-macro)
("C-c C-c d" . dap-hydra)
("C-c C-c h" . lsp-ui-doc-glance))
:config
;; uncomment for less flashiness
;; (setq lsp-eldoc-hook nil)
;; (setq lsp-enable-symbol-highlighting nil)
;; (setq lsp-signature-auto-activate nil)
;; comment to disable rustfmt on save
(setq rustic-format-on-save t)
(add-hook 'rustic-mode-hook 'rk/rustic-mode-hook))
(defun rk/rustic-mode-hook ()
;; so that run C-c C-c C-r works without having to confirm, but don't try to
;; save rust buffers that are not file visiting. Once
;; https://github.com/brotzeit/rustic/issues/253 has been resolved this should
;; no longer be necessary.
(when buffer-file-name
(setq-local buffer-save-without-query t)))
(use-package rust-playground)
(use-package toml-mode)
(use-package arduino-mode)
org-mode structure template에 python을 추가한다.
(if (boundp 'org-structure-template-alist)
(add-to-list 'org-structure-template-alist '("p" . "src python")))
(use-package elisp-mode
:ensure nil
:init
(add-hook 'emacs-lisp-mode-hook (lambda () (setq indent-tabs-mode nil)))
:bind (:map emacs-lisp-mode-map
("<f6>" . eval-buffer)
("M-<f6>" . emacs-lisp-byte-compile-and-load)
("<return>" . newline-and-indent)))
(use-package paredit
:hook ((lisp-mode emacs-lisp-mode)))
(use-package rainbow-delimiters
:hook ((lisp-mode emacs-lisp-mode)))
(use-package qml-mode)
(use-package yaml-mode)
(use-package conf-mode
:config
(add-hook 'conf-mode-hook
(lambda ()
(setq indent-line-function #'insert-tab
indent-tabs-mode t))))
(use-package dockerfile-mode
:mode ("Dockerfile\\'" . dockerfile-mode))
(use-package docker-compose-mode)
(use-package docker
:bind ("C-c d" . docker))
(use-package graphviz-dot-mode
:mode ("\\.dot\\'" . graphviz-dot-mode)
:init
(autoload 'graphviz-dot-mode "graphviz-dot-mode" "graphviz-dot Editing Mode" t))
(use-package gnuplot-mode
:mode ("\\.plt\\'" . gnuplot-mode)
:config (when-windows (setq gnuplot-program "c:/pkg/gnuplot/bin/gnuplot.exe")))
Markdown 문서 편집 시 markdown-mode를 사용한다. gfm-mode
는 같이 포함된 모드로 github flaved markdown을 의미한다.
(use-package markdown-mode
:mode
("README\\.md\\'" . gfm-mode)
:init
(setq markdown-command "cmark-gfm"))
(use-package deft
:ensure t
:bind ("<f9>" . deft)
:config (setq deft-extensions '("org" "md" "txt")
deft-directory "~/Dropbox/wiki"
deft-auto-save-interval 0
deft-text-mode 'org-mode))
(use-package google-translate
:ensure t
:bind ("M-o t" . google-translate-at-point)
("M-o T" . google-translate-at-point-reverse)
:custom
(google-translate-default-source-language "en")
(google-translate-default-target-language "ko"))
(use-package rfc-mode
:ensure t
:init (setq rfc-mode-directory (expand-file-name "~/Dropbox/resources/rfc/")))