Emacs: 用一个 Org 文件管理所有配置
Table of Contents
Darksun 在 这篇文章 里介绍了如何通过一个 org file 管理自己的各种配置文件. 思路简单来说, 就是通过 tangle 文件中的 org 代码块(执行 org-babel-tangle-file 命令)的代码块, 将配置代码插入到它们应该在的地方.
Spacemacs 就是 Emacs 的一套配置。它对 evil 的支持,它的文档完善程度,极大的减少了 Emacs 的使用门槛, 让你可以将更多精力花在如何使用 Emacs/Org mode 上面.
首先确保你电脑上已经:
- 安装了 Emacs
- 将 Spacemacs 默认配置下载到本地
然后就可以开始你的个性化定制了, 这里分为两种定制, 一种是 小修
你通过修改 Spacemacs 变量配置来定制, 另一种是 大改
你通过 Spacemacs 的 layer 机制, 定制自己的使用场景.
小修: 修改 init.el
init.el 中一共有四个函数:
- dotspacemacs/layers 启动 Emacs 时被调用的函数, 在这里配置想要使用的 layer 和 package
- dotspacemacs/init 最早被调用的函数, 在这里不要添加任何自定义代码, 只修改变量值即可
- dotspacemacs/user-init 在 2 之后, 在 layer 之前被调用, 在这里配置 package 的变量
- dotspacemacs/user-config 在 layer 之后被调用, 绝大部分个人配置应该在这里, 除非有些变量明确要求在 package 加载之前配置.
前三个函数只是微调一些参数, 按自己需求来简单搞下即可.
;; 出厂自带的基础 layer, 默认选择 spacemacs 就好. dotspacemacs-distribution 'spacemacs ;; 使用到了某些 layer 再安装就行 dotspacemacs-enable-lazy-installation 'unused dotspacemacs-ask-for-lazy-installation t ;; 查找其它 layer 配置的路径列表, 末尾需以"/"结尾 dotspacemacs-configuration-layer-path '() ;; 需要加载的配置 layers dotspacemacs-configuration-layers '( yaml plantuml python html helm (auto-completion :variables auto-completion-enable-sort-by-usage t :disabled-for org markdown) better-defaults emacs-lisp osx git lijigang (org :variables org-enable-reveal-js-support t org-download-screenshot-method "screencapture" org-download-image-dir "./images" org-download-heading-lvl nil org-download-timestamp "") ) ;; 如果有些 package, 不想加到 layer 中, 但又想使用, 可以加到这里 ;; 如果这些 package 还需要一些配置项, 可以把配置项放在 dotspace/user-config dotspacemacs-additional-packages '() ;; 如果有些 package 不想升级, 可以放到这里 dotspacemacs-frozen-packages '() ;; 如果有些 packages 不想安装或加载, 可以放到这里 dotspacemacs-excluded-packages '(org-projectile) ;; 只有在使用的 package(in dotspacemacs-configuration-layers or dotspacemacs-additional-packages) 才会安装, 其它的删除掉. dotspacemacs-install-packages 'used-only
;; 使用 https 连接服务器下载 packages dotspacemacs-elpa-https t ;; 连接超时时间设置为 5 秒 dotspacemacs-elpa-timeout 5 ;; 默认不要升级 spacemacs dotspacemacs-check-for-update nil ;; 如果电脑上有不同版本的 emacs, 可以配置这个变量来区分 dotspacemacs-elpa-subdirectory nil ;; 编辑模式,三个可选项: vim emacs hybrid dotspacemacs-editing-style 'vim ;; 不需要将启动过程信息打印到 *Messages* buffer dotspacemacs-verbose-loading nil ;; 在这里修改你的启动显示图片 dotspacemacs-startup-banner "~/Library/Mobile Documents/com~apple~CloudDocs/1-参考/8-Personal/head.png" ;; 设置 *scratch* buffer 为 emacs-lisp 模式 dotspacemacs-scratch-mode 'emacs-lisp-mode ;; 在这里设置你想的主题配色, 启动时加载的是第一个主題 dotspacemacs-themes '( doom-peacock srcery tao-yin tao-yang material solarized-light monokai spacemacs-light zenburn dracula ) ;; 光标颜色与当前编辑状态保持一致 dotspacemacs-colorize-cursor-according-to-state t ;; The leader key dotspacemacs-leader-key "SPC" ;; The key used for Emacs commands (M-x) (after pressing on the leader key). dotspacemacs-emacs-command-key "SPC" ;; The key used for Vim Ex commands (default ":") dotspacemacs-ex-command-key ":" ;; Major mode leader key is a shortcut key which is the equivalent of ;; pressing `<leader> m`. Set it to `nil` to disable it. (default ",") dotspacemacs-major-mode-leader-key "," ;; 设置大文件的定义标准(MB), 如果超过标准, 不激活 major/minor mode, 提升效能 dotspacemacs-large-file-size 5 ;; 默认开启时全屏 dotspacemacs-fullscreen-at-startup t ;; 保存文件时删除每行尾部空白符(space/tab) dotspacemacs-whitespace-cleanup 'trailing
;; 默认源太慢了, 建议使用子龙山人的国内镜像源 (setq configuration-layer--elpa-archives '(("melpai-cn" . "http://elpa.zilongshanren.com/melpa/") ("org-cn" . "http://elpa.zilongshanren.com/org/") ("gnu-cn" . "http://elpa.zilongshanren.com/gnu/"))) ;; 指定自己的 layer 路径 (setq dotspacemacs-configuration-layer-path "~/.spacemacs.d/layers/") ;; https://stackoverflow.com/questions/35286203/exec-path-from-shell-message-when-starting-emacs ;; 解决启动 warning (setq exec-path-from-shell-check-startup-files nil)
;; 设置 todo keywords (setq org-todo-keywords '((sequence "TODO" "HACK" "|" "DONE"))) ;; 设置 bullet list, 让 headline 变漂亮 (setq org-bullets-bullet-list '("☰" "☷" "☯" "☭")) ;; 打开 org-indent mode (setq org-startup-indented t) (setq org-remember-clock-out-on-exit t) ;; 折叠时不再显示「...」, 换个你喜欢的符号 (setq org-ellipsis "▼") ;; inline image 不用展示实际大小,可以自定义大小显示 (setq org-image-actual-width '(450)) (setq org-hierarchical-todo-statistics nil) (setq org-html-validation-link nil) ;; Let's have pretty source code blocks (setq org-edit-src-content-indentation 0 org-src-tab-acts-natively t org-src-fontify-natively t org-confirm-babel-evaluate nil org-support-shift-select 'always) (setq org-default-notes-file "~/Library/Mobile Documents/com~apple~CloudDocs/org/gtd/gtd.org") (setq org-refile-targets '("~/Library/Mobile Documents/com~apple~CloudDocs/org/gtd/gtd.org" :maxlevel . 3))
;; stop emacs asking for confirmation when eval source code (setq org-confirm-babel-evaluate nil) ;; active Org-babel languages (org-babel-do-load-languages 'org-babel-load-languages '(;; other Babel languages (emacs-lisp . t) (ditaa . t) (python . t) (shell . t) (plantuml . t)))
;; 调试好久的颜色,效果超赞!todo keywords 增加背景色 (setf org-todo-keyword-faces '(("TODO" . (:foreground "white" :background "#95A5A6" :weight bold)) ("HACK" . (:foreground "white" :background "#2E8B57" :weight bold)) ("DONE" . (:foreground "white" :background "#3498DB" :weight bold))))
;; Org archive (setq org-archive-location "%s_archive::date-tree") (defadvice org-archive-subtree (around org-archive-subtree-to-data-tree activate) "org-archive-subtree to date-tree" (if (string= "date-tree" (org-extract-archive-heading (org-get-local-archive-location))) (let* ((dct (decode-time (org-current-time))) (y (nth 5 dct)) (m (nth 4 dct)) (d (nth 3 dct)) (this-buffer (current-buffer)) (location (org-get-local-archive-location)) (afile (org-extract-archive-file location)) (org-archive-location (format "%s::*** %04d-%02d-%02d %s" afile y m d (format-time-string "%A" (encode-time 0 0 0 d m y))))) (message "afile=%s" afile) (unless afile (error "Invalid `org-archive-location'")) (save-excursion (switch-to-buffer (find-file-noselect afile)) ;; (org-datetree-find-year-create y) ;; (org-datetree-find-month-create y m) ;; (org-datetree-find-day-create y m d) (widen) (switch-to-buffer this-buffer)) ad-do-it) ad-do-it)) ;; 把 org_archive 文件设置为 org-mode (add-to-list 'auto-mode-alist '("\\.org_archive\\'" . org-mode))
;; agenda 里面时间块彩色显示 ;; From: https://emacs-china.org/t/org-agenda/8679/3 (defun ljg/org-agenda-time-grid-spacing () "Set different line spacing w.r.t. time duration." (save-excursion (let* ((background (alist-get 'background-mode (frame-parameters))) (background-dark-p (string= background "dark")) (colors (list "#1ABC9C" "#2ECC71" "#3498DB" "#9966ff")) pos duration) (nconc colors colors) (goto-char (point-min)) (while (setq pos (next-single-property-change (point) 'duration)) (goto-char pos) (when (and (not (equal pos (point-at-eol))) (setq duration (org-get-at-bol 'duration))) (let ((line-height (if (< duration 30) 1.0 (+ 0.5 (/ duration 60)))) (ov (make-overlay (point-at-bol) (1+ (point-at-eol))))) (overlay-put ov 'face `(:background ,(car colors) :foreground ,(if background-dark-p "black" "white"))) (setq colors (cdr colors)) (overlay-put ov 'line-height line-height) (overlay-put ov 'line-spacing (1- line-height)))))))) (add-hook 'org-agenda-finalize-hook #'ljg/org-agenda-time-grid-spacing) (setq org-agenda-prefix-format '((agenda . "%t %s "))) (setq org-agenda-clockreport-parameter-plist '(:link t :maxlevel 6 :fileskip0 t :compact t :narrow 60 :score 0)) (setq org-agenda-start-on-weekday nil) (setq org-agenda-log-mode-items '(clock)) (setq org-agenda-include-all-todo t) (setq org-agenda-time-leading-zero t) (setq org-agenda-use-time-grid nil) (setq org-agenda-include-diary nil) (setq org-agenda-files (list "~/Library/Mobile Documents/com~apple~CloudDocs/org/gtd/gtd.org" "~/Library/Mobile Documents/com~apple~CloudDocs/org/gtd/gtd.org_archive"))
;; 使用 reveal.js 来生成 html 版本的 ppt ;; https://opensource.com/article/18/2/how-create-slides-emacs-org-mode-and-revealjs (require 'ox-reveal) (setq org-reveal-root (concat (expand-file-name "~/Library/Mobile Documents/com~apple~CloudDocs/org/reveal.js"))) ;; 可选主题在 reveal.js 安装目录的 css/theme/ ;; beige/black/white/blood/league/moon/night/serif/simple/sky/solarized (setq org-reveal-theme "simple") (setq org-reveal-control t) (setq org-reveal-center t) (setq org-reveal-progress t)
;; 设置快捷键 (evil-leader/set-key "op" 'org-pomodoro) (evil-leader/set-key "oc" 'org-capture) (evil-leader/set-key "oa" 'org-agenda) (evil-leader/set-key "ol" 'org-store-link) (evil-leader/set-key "el" 'eval-print-last-sexp) (evil-leader/set-key "od" 'org-archive-subtree) (evil-leader/set-key "oip" 'org-set-property) (evil-leader/set-key "oil" 'org-insert-link) (evil-leader/set-key "ois" 'org-time-stamp) (evil-leader/set-key "oid" 'org-insert-drawer) (evil-leader/set-key "oif" 'org-footnote-action) (evil-leader/set-key "ood" (lambda () (interactive) (find-file "~/spacemacs-config/spacemacs-config.org"))) (evil-leader/set-key "oog" (lambda () (interactive) (find-file "~/Library/Mobile Documents/com~apple~CloudDocs/org/gtd/gtd.org"))) (evil-leader/set-key "ool" (lambda () (interactive) (find-file "~/.spacemacs.d/layers/lijigang/packages.el"))) ;; 插入 easy template (evil-leader/set-key "ds" 'org-insert-structure-template) (global-set-key (kbd "C--") 'org-table-insert-hline)
再来显示相关的:
;;;;;;;;;;;;;;;;;;;;;; ;; 外观展示相关配置 ;; ;;;;;;;;;;;;;;;;;;;;;; ;; 在状态栏显示时间 (display-time-mode 1) (global-hl-line-mode -1) (global-visual-line-mode 1) ;; 换行宽度 (setq-default fill-column 80) ;; 打开黄金比例模式, 当前使用的窗口所占比例为 0.618 (golden-ratio-mode) ;; 默认把新开的 Window 显示在右侧 (setq split-height-threshold nil) (setq split-width-threshold 0) ;; Remove the markup characters, i.e., "/text/" becomes (italized) "text" (setq org-hide-emphasis-markers t) ;; more useful frame title, that show either a file or a ;; buffer name (if the buffer isn't visiting a file) (setq frame-title-format '("" " 為學日益, 為道日損 - " (:eval (if (buffer-file-name) (abbreviate-file-name (buffer-file-name)) "%b"))))
配置下 LaTeX 相关内容:
;; LaTeX 配置 (setq Tex-command-default "XeLaTeX") ;; latex 支持中文 (require 'ox) (require 'ox-html) (require 'ox-publish) (add-to-list 'org-latex-classes '("pdf" "\\documentclass[fontset = mac]{ctexart} [NO-DEFAULT-PACKAGES] \\usepackage[colorlinks,linkcolor=black,anchorcolor=black, citecolor=black]{hyperref} \\usepackage[top=3truecm,bottom=2.5truecm, left=1.1truecm,right=1.1truecm, bindingoffset=1.0truecm, headsep=1.6truecm, footskip=1.5truecm, headheight=15pt % 标准中没有要求页眉的高度,这里设置成 % 15pt 了 ]{geometry} \\setCJKmainfont[BoldFont={Microsoft YaHei},ItalicFont={Microsoft YaHei}]{Microsoft YaHei} " ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))) (setq org-latex-default-class "pdf") (setq org-latex-pdf-process '( "xelatex -interaction nonstopmode -output-directory %o %f" "xelatex -interaction nonstopmode -output-directory %o %f" "xelatex -interaction nonstopmode -output-directory %o %f" "rm -fr %b.out %b.log %b.tex auto" )) (defun peng-use-xelatex () (interactive) (let* ((tempfile (file-name-base))) (progn (shell-command (concat "rm -rf " tempfile ".bbl " tempfile ".blg " tempfile ".out " tempfile ".log " tempfile ".aux " tempfile ".toc" tempfile ".pdf")) (compile (concat "xelatex " (concat tempfile ".tex") (concat ";rm -rf " tempfile ".bbl " tempfile ".blg " tempfile ".out " tempfile ".log " tempfile ".aux " tempfile ".toc" ";open " tempfile ".pdf"))))))
其它配置项:
;; Tangle Org files when we save them ;; 一保存文件直接 tangle 代码 ;; (defun tangle-on-save-org-mode-file() ;; (when (string= (message "%s" major-mode) "org-mode") ;; (org-babel-tangle))) ;; (add-hook 'after-save-hook 'tangle-on-save-org-mode-file) ;; 文件有更新, buffer 自动更新 (global-auto-revert-mode) ;; 编码选用 UTF-8 (prefer-coding-system 'utf-8) (set-default-coding-systems 'utf-8) (setq default-buffer-file-coding-system 'utf-8) ;; gpg related (setq epg-gpg-program "gpg2") (setq epa-pinentry-mode 'loopback) (setq user-full-name "lijigang" user-mail-address "i@lijigang.com") ;; 插入今年的时间进度条 (defun make-progress (width percent has-number?) (let* ((done (/ percent 100.0)) (done-width (floor (* width done)))) (concat "[" (make-string done-width ?/) (make-string (- width done-width) ? ) "]" (if has-number? (concat " " (number-to-string percent) "%")) ))) (defun insert-day-progress () (interactive) (let* ((today (time-to-day-in-year (current-time))) (percent (floor (* 100 (/ today 365.0))))) (insert (make-progress 30 percent t)) )) (evil-leader/set-key "oit" 'insert-day-progress) (add-to-list 'org-src-lang-modes '("plantuml" . plantuml)) ;; 时间戳使用英文星期 (setq system-time-locale "C") (global-company-mode) (setq org-ditaa-jar-path "~/Library/Mobile Documents/com~apple~CloudDocs/org/org-mode/contrib/scripts/ditaa.jar") (setq plantuml-default-exec-mode 'jar) (setq org-plantuml-jar-path (expand-file-name "~/Library/Mobile Documents/com~apple~CloudDocs/org/org-resources/plantuml.jar")) (setq yas-snippet-dirs (list "~/.spacemacs.d/snippets/")) (setq dired-use-ls-dired nil)
全部梳理完毕, 现在可以生成配置文件 init.el 了:
#+BEGIN_SRC emacs-lisp :tangle ~/.spacemacs.d/init.el :exports none :noweb yes :mkdirp yes (defun dotspacemacs/layers () (setq-default <<spacemacs-layers>> )) (defun dotspacemacs/init () (setq-default <<spacemacs-init>> )) (defun dotspacemacs/user-init () <<spacemacs-user-init>> ) (defun dotspacemacs/user-config () (with-eval-after-load 'org <<spacemacs-user-config-org-base>> <<spacemacs-user-config-org-babel>> <<spacemacs-user-config-org-appearance>> <<spacemacs-user-config-org-archive>> <<spacemacs-user-config-org-agenda>> <<spacemacs-user-config-org-reveal>> <<spacemacs-user-config-org-keyboard>> ) <<spacemacs-user-config-display>> <<spacemacs-user-config-latex>> <<spacemacs-user-config-others>> ) #+END_SRC
大改: 定义 private layer
除了配置一个个 package 这个笨办法以外, Spacemacs 引入了 layer 的概念, 即将一个场景(比如使用 org-mode 或者 python)常用的一些 package 给打包放一起, 统称为一个 layer.
Spacemacs 出厂自带了很多常用的 layer, 但同时也支持你自定义. 我会把日常使用到的一些 package 放到自己的 layer 中.
(defconst lijigang-packages '(org-page dired-icon cnfonts swiper wttrin beacon pangu-spacing pyim posframe org-kanban visual-fill-column all-the-icons doom-modeline org-analyzer org-brain ) )
(defun lijigang/init-org-page() "Initialize org-page to publish blog." (use-package org-page :ensure t :config (progn (setq op/site-main-title "常识") (setq op/personal-github-link "https://github.com/lijigang") (setq op/repository-directory "~/lijigang") (setq op/site-domain "http://lijigang.github.io/") (setq op/theme-root-directory (car (file-expand-wildcards "~/.emacs.d/elpa/org-page-*/themes" t))) (setq op/theme 'ljg) (setq op/highlight-render 'js) (setq op/category-ignore-list '("themes" "assets" "images")) (setq op/category-config-alist '(("blog" :show-meta t :show-comment t :uri-generator op/generate-uri :uri-template "/blog/%y/%m/%d/%t/" :sort-by :date ;; how to sort the posts :category-index nil) ;; generate category index or not ("index" :show-meta nil :show-comment nil :uri-generator op/generate-uri :uri-template "/" :sort-by :date :category-index nil) ("about" :show-meta nil :show-comment nil :uri-generator op/generate-uri :uri-template "/about/" :sort-by :date :category-index nil))) (bind-key "C-c M-p" 'op/do-publication-and-preview-site))) ) (defun lijigang/init-dired-icon () "Initialize dired-icon" (add-hook 'dired-mode-hook 'dired-icon-mode) (add-hook 'dired-mode-hook (lambda () (highlight-lines-matching-regexp "\.org$" 'hi-yellow)))) (defun lijigang/init-cnfonts() "Initialize cnfonts" (use-package cnfonts :init (cnfonts-enable) (cnfonts-set-spacemacs-fallback-fonts))) (defun lijigang/init-swiper() "Initialize swiper" (use-package swiper :init (define-key global-map (kbd "C-s") 'swiper))) (defun lijigang/init-wttrin() (use-package wttrin :ensure t :commands (wttrin) :init (setq wttrin-default-cities '("Beijing" "Bristol"))) ) (defun lijigang/init-beacon() "Initialize beacon" (use-package beacon :init (beacon-mode 1) (setq beacon-color "#666600"))) (defun lijigang/init-pangu-spacing() "Initialize pangu-spacing" (use-package pangu-spacing :init (global-pangu-spacing-mode 1) (setq pangu-spacing-real-insert-separtor t))) (defun lijigang/init-pyim() "Initialize pyim" (use-package pyim :ensure nil :demand t :init (setq pyim-punctuation-translate-p '(no yes auto)) :config (setq default-input-method "pyim") (setq pyim-default-scheme 'wubi) ;; 让 Emacs 启动时自动加载 pyim 词库 (add-hook 'emacs-startup-hook #'(lambda () (pyim-restart-1 t))) (setq pyim-page-tooltip 'posframe) (setq pyim-dicts '((:name "基础词库" :file "~/Library/Mobile Documents/com~apple~CloudDocs/3-config/wbdict.pyim"))) (global-set-key (kbd "C-9") 'toggle-input-method) )) (defun lijigang/init-posframe () (use-package posframe)) (defun lijigang/init-org-kanban () (use-package org-kanban)) (defun lijigang/init-visual-fill-column () (use-package visual-fill-column :ensure t :defer t :init (dolist (hook '(visual-line-mode-hook org-mode-hook text-mode-hook )) (add-hook hook #'visual-fill-column-mode)) :config (setq-default visual-fill-column-width 90 ;; visual-fill-column-center-text t visual-fill-column-fringes-outside-margins nil))) (defun lijigang/init-all-the-icons () (use-package all-the-icons)) (defun lijigang/init-doom-modeline () (use-package doom-modeline :ensure t :hook (after-init . doom-modeline-mode) :config (setq doom-modeline-major-mode-color-icon t) (setq doom-modeline-buffer-state-icon t) (setq doom-modeline-buffer-modification-icon t) (setq doom-modeline-enable-word-count t) (setq doom-modeline-vcs-max-length 12) )) (defun lijigang/init-org-analyzer () (use-package org-analyzer)) ;; see https://github.com/Kungsgeten/org-brain#setup-and-requirements (defun lijigang/init-org-brain () (use-package org-brain :ensure t :init (setq org-brain-path "~/Library/Mobile Documents/com~apple~CloudDocs/org/brain/") ;; For Evil users (with-eval-after-load 'evil (evil-set-initial-state 'org-brain-visualize-mode 'emacs)) :config (setq org-id-track-globally t) (setq org-id-locations-file "~/library/Mobile Documents/com~apple~CloudDocs/org/.org-id-locations") (push '("b" "Brain" plain (function org-brain-goto-end) "* %i%?" :empty-lines 1) org-capture-templates) (setq org-brain-visualize-default-choices 'all) (setq org-brain-title-max-length 12) (setq org-brain-include-file-entries nil org-brain-file-entries-use-title nil) ) )
把上面配置生成文件即可:
#+BEGIN_SRC emacs-lisp :tangle ~/.spacemacs.d/layers/lijigang/packages.el :exports none :noweb yes :mkdirp yes <<private-layer-lijigang-packages>> <<private-layer-lijigang-init>> #+END_SRC