Skip to content

bbingju/literate-emacs-configuration

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

92 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

My Literate Emacs Configuration

https://melpa.org/packages/literate-elisp-badge.svg https://stable.melpa.org/packages/literate-elisp-badge.svg

First of All

Speed-up at startup

(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))))

Increase the amount of data which emacs reads from the process

(setq read-process-output-max (* 1024 1024))

Add load-path

(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))

ELPA configuration

(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

패키지 관리에 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)

My own fuctions & macros

(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)))

Sync a path to Environment Variable

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))

Input method & coding system

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)))

File-related tweaks

(use-package files
  :ensure nil
  :config
  (setq confirm-kill-processes nil
        make-backup-files nil))

Automatically refreshes the buffer for changes outside of emacs

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))

Load a custom file

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))

Helm

(use-package helm
  :ensure t
  :diminish helm-mode
  :init
  (progn
    (setq helm-M-x-requires-pattern nil
          helm-split-window-inside-p t ; open helm buffer inside
                                        ; current window, not occupy
                                        ; whole other window
          helm-move-to-line-cycle-in-source  t ; move to end or
                                        ; beginning of source
                                        ; when reaching top or
                                        ; bottom of source.
          helm-ff-search-library-in-sexp t ; search for library in
                                        ; `require' and
                                        ; `declare-function' sexp.
          helm-scroll-amount 8 ; scroll 8 lines other window using
                                        ; M-<next>/M-<prior>
          helm-ff-file-name-history-use-recentf t)
    (helm-mode))
  :bind (("C-c h" . helm-command-prefix)
         ("C-x C-f" . helm-find-files)
         ("C-x b" . helm-buffers-list)
         ("C-x C-b" . helm-buffers-list)
         ("C-x c y" . helm-yas-complete)
         ("C-x c Y" . helm-yas-create-snippet-on-region)
         ("M-y" . helm-show-kill-ring)
         ("M-x" . helm-M-x)
         ;; ("C-i" . helm-execute-persistent-action)
         ;; ("C-z" . helm-select-action)
         ))

(use-package helm-descbinds
  :ensure t
  :defer 7
  :bind (("C-h b" . helm-descbinds)))
(use-package helm-swoop
  :ensure t
  :bind (("C-S-s" . helm-swoop)
         ("M-i" . helm-swoop)
         ("M-s s" . helm-swoop)
         ("M-s M-s" . helm-swoop)
         ("M-I" . helm-swoop-back-to-last-point)
         ("C-c M-i" . helm-multi-swoop)
         ("C-x M-i" . helm-multi-swoop-all)
         ("M-i" . helm-multi-swoop-all-from-helm-swoop)
         :map isearch-mode-map
         ("M-i" . helm-swoop-from-isearch)))

The default C-x c is quite close to C-x C-c, which quits Emacs. Changed to C-c h. Note: We must set C-c h globally, because we cannot change `helm-command-prefix-key’ once `helm-config’ is loaded.

(global-set-key (kbd "C-c h") 'helm-command-prefix)
(global-unset-key (kbd "C-x c"))

Others

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))

Appearance

Basic appearance

Hide tool-bar and scroll-bar.

(mapc
 (lambda (mode)
   (if (fboundp mode)
       (funcall mode -1)))
 '(tool-bar-mode scroll-bar-mode))

doom-themes

(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))

doom-modeline

아이콘 폰트를 쓰기 위해서는 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))

Font setting

;; (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 line-spacing 6)

;; (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)))

line numbers

라인번호를 특정 모드에 붙인다.

(use-package display-line-numbers-mode
  :ensure nil
  :hook (prog-mode text-mode conf-mode))

Org 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-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") "* %? %^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))))

Programming

Tree-Sitter

현재 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")
     (markdown "https://github.com/ikatyang/tree-sitter-markdown")
     (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

projectile-indexing-methodalien 으로 지정하여 Windows에서도 이 방법을 쓰도록 강제한다. 자세한 내용은 이슈에서 확인할 수 있다. 메뉴얼은 여기에서 볼 수 있다.

(use-package projectile
  :after
  (helm)
  :bind-keymap
  ("C-c p" . projectile-command-map)
  :init
  (projectile-mode +1)
  :config
  (use-package helm-projectile
    :config (helm-projectile-on))
  :custom
  (projectile-enable-caching t)
  (projectile-indexing-method 'alien)
  (projectile-completion-system 'helm))

magit

This is an awesome plugin as git client.

(use-package magit
  :commands (magit-init
             magit-status)
  :bind ("C-x g" . magit-status))

A hook for compilation buffer using ansi-color

“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)

Coding convention

(use-package editorconfig
  :ensure t
  :config (editorconfig-mode 1))

diff-hl

(use-package diff-hl
  :ensure t
  :init (global-diff-hl-mode)
  :config
  (add-hook 'magit-post-refresh-hook #'diff-hl-magit-post-refresh))

flycheck

(use-package flycheck
  :hook (after-init . global-flycheck-mode)
  :config
  (setq flycheck-check-syntax-automatically '(save idle-change mode-enabled)))

Yasnippet

(use-package yasnippet
  :defer 5
  :diminish yas-minor-mode
  :config (yas-global-mode 1))

(use-package yasnippet-snippets
  :ensure t
  :after yasnippet)

Eldoc

(use-package eldoc
  :hook (emacs-lisp-mode ielm-mode rust-mode rust-ts-mode))
(setq eldoc-echo-area-prefer-doc-buffer t)

C/C++

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)))

tree-sitter

(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))

Python

(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)

Rust

;; (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)

Arduino

(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")))

Emacs Lisp

(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)))

Configurations for Qt5

(use-package qml-mode)

YAML

(use-package yaml-mode)

Conf

(use-package conf-mode
  :config 
  (add-hook 'conf-mode-hook
            (lambda ()
              (setq indent-line-function #'insert-tab
                    indent-tabs-mode     t))))

Docker

(use-package dockerfile-mode
  :mode ("Dockerfile\\'" . dockerfile-mode))
(use-package docker-compose-mode)
(use-package docker
  :bind ("C-c d" . docker))

graphviz-dot-mode

(use-package graphviz-dot-mode
  :mode ("\\.dot\\'" . graphviz-dot-mode)
  :init
  (autoload 'graphviz-dot-mode "graphviz-dot-mode" "graphviz-dot Editing Mode" t))

gnuplot-mode

(use-package gnuplot-mode
  :mode ("\\.plt\\'" . gnuplot-mode)
  :config (when-windows (setq gnuplot-program "c:/pkg/gnuplot/bin/gnuplot.exe")))

markdown-mode

(use-package markdown-mode
  :mode ("\\.md\\'" . markdown-mode)
  :init
  (autoload 'markdown-mode "markdown-mode" "Major mode for editing Markdown files" t))
(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))

Tools

Google Translater

(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"))

rfc-mode

(use-package rfc-mode
  :ensure t
  :init (setq rfc-mode-directory (expand-file-name "~/Dropbox/resources/rfc/")))

Releases

No releases published

Packages

No packages published