让我们改变对程序构建的传统态度: 与其想象我们的主要任务是指导计算机做什么, 不如专注于向人们解释我们想让计算机做什么。 @@latex:\mbox{@@— 高德纳@@latex:}@@
创建词法绑定可以 (稍微) 加速配置文件的运行。 (更多内容可以查看 这篇博客)
;;; config.el -*- lexical-binding: t; -*-
配置有用且基础的个人信息
(setq user-full-name "GinShio"
user-mail-address "[email protected]"
org-directory "~/cyberlive"
)
显然这可以被 GPG 或其他程序使用。
尝试一下别人的默认值,比如 angrybacon/dotemacs
(setq-default
delete-by-moving-to-trash t ; 将文件删除到回收站
window-combination-resize t ; 从其他窗口获取新窗口的大小
x-stretch-cursor t ; 将光标拉伸到字形宽度
)
(setq! undo-limit 104857600 ; 重置撤销限制到 100 MiB
auto-save-default t ; 没有人喜欢丢失工作,我也是如此
truncate-string-ellipsis "…" ; Unicode 省略号相比 ascii 更好
; 同时节省 /宝贵的/ 空间
password-cache-expiry nil ; 我能信任我的电脑 ... 或不能?
; scroll-preserve-screen-position 'always
; 不要让 `点' (光标) 跳来跳去
scroll-margin 2 ; 适当保持一点点边距
gc-cons-threshold 1073741824
read-process-output-max 1048576
which-func-unknown ""
)
(remove-hook! text-mode #'visual-line-mode)
(add-hook! text-mode #'auto-fill-mode)
(add-hook! window-setup #'toggle-frame-maximized)
; 设置最大化启动
(global-subword-mode 1) ; 识别驼峰,而不是傻瓜前进
(global-unset-key (kbd "C-z")) ; 关闭 "C-z" 最小化
(global-unset-key (kbd "C-s")) ; 关闭 "C-s" 搜索功能,该功能由 "C-c s s" 替代
(when IS-WINDOWS
(setq-default buffer-file-coding-system 'utf-8-unix)
(set-default-coding-systems 'utf-8-unix)
(prefer-coding-system 'utf-8-unix))
; 将 Windows 上的编码改为 UTF-8 Unix 换行
(custom-set-variables '(delete-selection-mode t) ;; delete when you select region and modify
'(delete-by-moving-to-trash t) ;; delete && move to transh
'(inhibit-compacting-font-caches t) ;; don’t compact font caches during GC.
'(gc-cons-percentage 1))
(add-hook! prog-mode (lambda () (setq show-trailing-whitespace 1)))
; 编程模式下让结尾的空白符亮起
(add-hook! prog-mode #'which-function-mode)
定义一个自己的 key leader,或许没什么用
(after! general
(general-create-definer ginshio/leader :prefix "s-y"))
默认情况下通过自定义界面所做的修改会被添加到 init.el
中。
不过正常的方法是将它们放在 .custom.el
中。
(setq-default custom-file (expand-file-name ".custom.el" doom-user-dir))
(when (file-exists-p custom-file) (load custom-file))
设置一个方便的在 window 之间进行切换的快捷键,我选择与 kDE 的 konsole 保持一致。
(map! :map override-global-map
"C-S-<left>" #'windmove-left
"C-S-<down>" #'windmove-down
"C-S-<up>" #'windmove-up
"C-S-<right>" #'windmove-right
)
拉取 doom-emacs 仓库的分支
- emacs-version: 29.1
- git commit: 03d692f
;;; init.el -*- lexical-binding: t; -*-
;; This file controls what Doom modules are enabled and what order they load
;; in. Remember to run 'doom sync' after modifying it!
;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's
;; documentation. There you'll find a link to Doom's Module Index where all
;; of our modules are listed, including what flags they support.
;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or
;; 'C-c c k' for non-vim users) to view its documentation. This works on
;; flags as well (those symbols that start with a plus).
;;
;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its
;; directory (for easy access to its source code).
(doom! :input
<<doom-input>>
:completion
<<doom-completion>>
:ui
<<doom-ui>>
:editor
<<doom-editor>>
:emacs
<<doom-emacs>>
:term
<<doom-term>>
:checkers
<<doom-checkers>>
:tools
<<doom-tools>>
:os
<<doom-os>>
:lang
<<doom-lang>>
:email
<<doom-email>>
:app
<<doom-app>>
:config
<<doom-config>>
)
这是一篇文学编程,同时也是 Doom Emacs 的配置文件。Doom 对其支持良好,更多详情
可以通过 literate
(文学) 模块了解。
literate
(default +bindings +smartparens)
可以做很多事来增强 Emacs 的功能,。
- 输入
-
中日文输入与键盘布局
;;bidi ; (tfel ot) thgir etirw uoy gnipleh ;;chinese ;;japanese ;;layout ; auie,ctsrnm is the superior home row
- 补全
-
或许叫补全有点不合适,不过也就这样了。另外说一下,
helm
、ido
、ivy
以 及vertico
是功能一致的,生态不同的四个包。(company ; the ultimate code completion backend +childframe) ;;helm ; the *other* search engine for love and life ;;ido ; the other *other* search engine... ;;(ivy ; a search engine for love and life ;; +icons ; ... icons are nice ;; +prescient) ; ... I know what I want(ed) (vertico +icons) ; the search engine of the future
- UI
- 好不好看就看你这么配置了
;;deft ; notational velocity for Emacs doom ; what makes DOOM look the way it does doom-dashboard ; a nifty splash screen for Emacs ;;doom-quit ; DOOM quit-message prompts when you quit Emacs ;;(emoji ;; +unicode +github); 🙂 hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW ;;hydra ;;indent-guides ; highlighted indent columns ;;(ligatures +extra); ligatures and symbols to make your code pretty again ;;minimap ; show a map of the code on the side modeline ; snazzy, Atom-inspired modeline, plus API ;;nav-flash ; blink cursor line after big motions ;;neotree ; a project drawer, like NERDTree for vim ophints ; highlight the region an operation acts on ;;(popup ; tame sudden yet inevitable temporary windows ;; +all ; catch all popups that start with an asterix ;; +defaults) ; default popup rules ;;tabs ; a tab bar for Emacs treemacs ; a project drawer, like neotree but cooler ;;unicode ; extended unicode support for various languages (vc-gutter +pretty) ; vcs diff in the fringe vi-tilde-fringe ; fringe tildes to mark beyond EOB ;;window-selec ; visually switch windows workspaces ; tab emulation, persistence & separate workspaces ;; zen ; distraction-free coding or writing
- 编辑器
- VI VI VI Editor of the Beast
;;(evil +everywhere); come to the dark side, we have cookies file-templates ; auto-snippets for empty files fold ; (nigh) universal code folding format ; automated prettiness ;;god ; run Emacs commands without modifier keys ;;lispy ; vim for lisp, for people who don't like vim multiple-cursors ; editing in many places at once ;;objed ; text object editing for the innocent ;;parinfer ; turn lisp into python, sort of ;;rotate-text ; cycle region at point between text candidates snippets ; my elves. They type so I don't have to ;;word-wrap ; soft wrapping with language-aware indent
- Emacs
- 增强一下吧,不然真的是笔记本了 (其实不是
(dired +icons) ; making dired pretty [functional] electric ; smarter, keyword-based electric-indent (ibuffer +icons) ; interactive buffer management undo ; persistent, smarter undo for your inevitable mistakes vc ; version-control and Emacs, sitting in a tree
- 终端
- 也许我应该卸载掉我的
Konsole
;;eshell ; the elisp shell that works everywhere ;;shell ; simple shell REPL for Emacs ;;term ; basic terminal emulator for Emacs vterm ; the best terminal emulation in Emacs
- 检测
- 可以告诉我哪里不对,但我觉得我应该先好好背背单词或者看看 PEP8
syntax ; tasing you for every semicolon you forget ;;(spell +flyspell) ; tasing you for misspelling mispelling ;;grammar ; tasing grammar mistake every you make
- 工具
- Workflow in Emacs!
;;ansible biblio ; Writes a PhD for you (citation needed) ;;collab ; buffers with friends (debugger +lsp) ; FIXME stepping through code, to help you add bugs ;;direnv ;;docker editorconfig ; let someone else argue about tabs vs spaces ;;ein ; tame Jupyter notebooks with emacs (eval +overlay) ; run code, run (also, repls) ;;gist ; interacting with github gists lookup ; helps you navigate your code and documentation (lsp +peek) ; M-x vscode (magit ; a git porcelain for Emacs +forge) ; interface with git forges make ; run make tasks from Emacs ;;pass ; password manager for nerds ;;pdf ; pdf enhancements ;;prodigy ; FIXME managing external services & code builders rgb ; creating color strings ;;taskrunner ; taskrunner for all your projects ;;terraform ; infrastructure as code ;;tmux ; an API for interacting with tmux tree-sitter ; syntax and parsing, sitting in a tree... ;;upload ; map local to remote projects via ssh/ftp
- OS
- 有个问题,我会用 MAC 吗
(:if IS-MAC macos) ; improve compatibility with macOS tty ; improve the terminal Emacs experience
最爽的事情就是,我可以在 Emacs 中编写任何语言 (的 Hello World
)
;;agda ; types of types of types of types...
;;beancount ; mind the GAAP
(cc ; C > C++ == 1
+lsp ; smart C but still memory leak
+tree-sitter)
;;clojure ; java with a lisp
;;common-lisp ; if you've seen one lisp, you've seen them all
;;coq ; proofs-as-programs
;;crystal ; ruby at the speed of c
;;csharp ; unity, .NET, and mono shenanigans
data ; config/data formats
;;(dart +flutter) ; paint ui and not much else
;;dhall
;;elixir ; erlang done right
;;elm ; care for a cup of TEA?
emacs-lisp ; drown in parentheses
;;erlang ; an elegant language for a more civilized age
;;ess ; emacs speaks statistics
;;factor
;;faust ; dsp, but you get to keep your soul
;;fortran ; in FORTRAN, GOD is REAL (unless declared INTEGER)
;;fsharp ; ML stands for Microsoft's Language
;;fstar ; (dependent) types and (monadic) effects and Z3
;;gdscript ; the language you waited for
;;(go +lsp) ; the hipster dialect
;;(graphql +lsp) ; Give queries a REST
;;(haskell +lsp) ; a language that's lazier than I am
;;hy ; readability of scheme w/ speed of python
;;idris ; a language you can depend on
;;json ; At least it ain't XML
;;(java +lsp) ; the poster child for carpal tunnel syndrome
;;(javascript +lsp) ; all(hope(abandon(ye(who(enter(here))))))
;;julia ; a better, faster MATLAB
;;kotlin ; a better, slicker Java(Script)
(latex ; writing papers in Emacs has never been so fun
+latexmk ; what else would you use?
+cdlatex ; quick maths symbols
+fold) ; fold the clutter away nicities
;;lean ; for folks with too much to prove
;;ledger ; be audit you can be
;;lua ; one-based indices? one-based indices
markdown ; writing docs for people to ignore
;;nim ; python + lisp at the speed of c
;;nix ; I hereby declare "nix geht mehr!"
;;ocaml ; an objective camel
(org ; organize your plain life in plain text
+dragndrop ; drag & drop files/images into org buffers
+hugo ; use Emacs for hugo blogging
+pandoc) ; export-with-pandoc support
;;php ; perl's insecure younger brother
;;plantuml ; diagrams for confusing people more
;;purescript ; javascript, but functional
(python ; beautiful is better than ugly
+cython
+lsp
+pyenv
+pyright
+tree-sitter)
;;qt ; the 'cutest' gui framework ever
;;racket ; a DSL for DSLs
;;raku ; the artist formerly known as perl6
;;rest ; Emacs as a REST client
;;rst ; ReST in peace
;;(ruby +tree-sitter) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
(rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
+lsp
+tree-sitter)
;;scala ; java, but good
(scheme +guile) ; a fully conniving family of lisps
sh ; she sells {ba,z,fi}sh shells on the C xor
;;sml
;;solidity ; do you need a blockchain? No.
;;swift ; who asked for emoji variables?
;;terra ; Earth and Moon in alignment for performance.
;;web ; the tubes
;;yaml ; JSON, but readable
;;zig ; C, but simpler
leave Emacs
- 邮件
- 说实话,我想用
Thunderbird
;;(mu4e +org +gmail) ;;notmuch ;;(wanderlust +gmail)
- 应用
- 可以在 Emacs 中上网看新闻。或许我可以用 irc 聊天
;;calendar ;;emms ;;everywhere ; *leave* Emacs!? You must be joking ;;irc ; how neckbeards socialize ;;(rss +org) ; emacs as an RSS reader ;;twitter ; twitter client https://twitter.com/vnought
‘Source Code Pro’ 和 ‘Fira Code’ 的效果都很不错,’JetBrains Mono’ 和 ‘IBM Plex Mono’ 或许也不错。还是比较推荐 Mono 字体,等宽看代码舒服。
Unicode 字体为什么不试试 ‘JuliaMono’ 呢?
(setq doom-font (font-spec :family "Source Code Pro" :size 15)
doom-big-font (font-spec :family "Source Code Pro" :size 30)
doom-variable-pitch-font (font-spec :family "Source Code Variable" :size 15)
doom-unicode-font (font-spec :family "JuliaMono")
doom-serif-font (font-spec :family "Source Serif 4")
)
不过这都是西文字体,没有考虑过 CJK 用户的感受吗!!在后面的 杂项 中,将详细说一下 CJK 字体的配置。
除了这些字体外,字体 Merriweather 还被用于 nov.el
中,字体 Alegreya 作为衬线比
例字体被用于 Org 文件的 writeroom-mode
中的 =mixed-pitch-mode=。
doom-one
是 Doom 自带的大而全的主题,里面实在太多好看的主题了,干嘛还要自己找。
这里我想在众多我喜欢的主题中,启动时随机选取一款。
(setq doom-theme (let ((themes '(doom-vibrant
doom-fairy-floss
doom-dracula
doom-Iosvkem
doom-moonlight
doom-monokai-pro
doom-tokyo-night)))
(elt themes (random (length themes)))))
当然你不喜欢这样,可以直接指定一款。另外,你可以采用快捷键 C-h t
来预览并选择
各个主题(当然是一次性的)。
(setq doom-theme 'doom-vibrant)
设置一下 modeline,比如说图标、文件名称以及彩虹猫 (Nyan cat)!
(after! doom-modeline
(custom-set-variables '(doom-modeline-buffer-file-name-style 'relative-to-project)
'(doom-modeline-major-mode-icon t)
'(doom-modeline-modal-icon nil))
(nyan-mode t))
相对行号可以很好的知道距离目标行有多远,然后用快捷键 C-u num <UP>
或
ESC num <UP>
到达你想去的行。
(setq display-line-numbers-type 'relative)
我想设置一下更好看的默认缓冲区名称
(setq doom-fallback-buffer-name "► Doom"
+doom-dashboard-name "► Doom")
再来说说初始化 doom 时,UI 上其实还有很多能做的,比如说关闭丑的不行的 ~menu-bar~, 设置光标模式,以及 CJK 字体等。
需要说明一下,字体在 GUI 下是有效的,TUI 下使用的应该是终端设置。另外,使用 mono
字体时,CJK 一般是西文字号的 1.2
倍,这样一个 CJK 符号将是西文符号的 2
倍。
比较建议西文字体设置为 5
的倍数,这样得到的 CJK 字符都能是一个整数值。
(defun ginshio/doom-init-ui-misc()
(menu-bar-mode -1) ;; disable menu-bar
(tab-bar-mode -1) ;; disable tab-bar
(setq-default cursor-type 'box) ;; set box style cursor
(blink-cursor-mode -1) ;; cursor not blink
<<doom-dashboard-layout>>
(if (display-graphic-p)
(progn
;; NOTE: ONLY GUI
;; set font
(dolist (charset '(kana han bopomofo))
(set-fontset-font (frame-parameter nil 'font) charset
(font-spec :family "Source Han Mono SC")))
(appendq! face-font-rescale-alist
'(("Source Han Mono SC" . 1.2)))
<<doom-image-banner>>
;; random banner image from bing.com, NOTE: https://emacs-china.org/t/topic/264/33
)
(progn
;; NOTE: ONLY TUI
<<doom-ascii-banner>>
)))
(add-hook! doom-init-ui #'ginshio/doom-init-ui-misc)
这些是 doom 添加的一些非常有用的宏
load!
可以相对于本文件进行外部.el
文件的加载use-package!
用于配置包add-load-path!
将指定目录添加到load-path
中,可以让 Emacs 在使用require
和use-package
时在load-path
中进行查找map!
用于绑定新的快捷键
在 Org 中有时会写一点代码,Org-Babel 就是各个语言在 Org-mode 中的巴别塔。大家都 可以通过它来直接运行。
但是在配置文件也会有一些代码,如果在 CLI 中执行 doom sync
之类的操作,大量的
代码块输出会直接污染输出。这不能忍!
好在 DOOM 提供了每次运行 CLI 前读取 $DOOMDIR/cli.el
的特性,我们可以不再手动
确认是否运行某个代码块 (org-confirm-babel-evaluate
),并且用
org-babel-execute-src-block
来沉默这些代码块,避免污染输出。
;;; cli.el -*- lexical-binding: t; -*-
(setq! org-confirm-babel-evaluate nil)
(advice-add 'org-babel-execute-src-block
:around #'(lambda (orig-fn &rest args)
(quiet! (apply orig-fn args))))
Dashboard 是打开 Emacs 的主页,展示命令并不是很有用,移除掉它们!
(remove-hook! '+doom-dashboard-functions #'doom-dashboard-widget-shortmenu)
(add-hook! +doom-dashboard-mode (hide-mode-line-mode 1) (hl-line-mode 1))
我更喜欢窗口展示缓冲区的名字,然后是项目文件夹 (如果可用)。
(setq! frame-title-format
'("%b – Doom Emacs"
(:eval
(let ((project-name (projectile-project-name)))
(unless (string= "-" project-name)
(format " - [%s]" project-name))))))
tecosaur 做了一个相当棒的启动画面,心动!但是太复杂了。我只是想简单的在每次重启时 更换 banner,仅此而已。
(setq! fancy-splash-image
(let ((banners (directory-files (expand-file-name "banners" doom-user-dir)
'full (rx ".png" eos))))
(elt banners (random (length banners)))))
当然,不要忘记 ASCII banner
(setq! ginshio/+doom-dashbord-ascii-banner
(split-string (with-output-to-string
(call-process "cat" nil standard-output nil
(let ((banners (directory-files (expand-file-name "banners" doom-user-dir)
'full (rx ".txt" eos))))
(elt banners (random (length banners))))))
"\n" t))
(setq! +doom-dashboard-ascii-banner-fn
#'(lambda ()
(mapc (lambda (line)
(insert (propertize (+doom-dashboard--center +doom-dashboard--width line)
'face 'doom-dashboard-banner) " ")
(insert "\n"))
ginshio/+doom-dashbord-ascii-banner)))
在此配置中,有几处需要以字符串形式抓取源代码块的内容的字符串。我们可以使用
noweb <<replacement>>
表单,但该表单无法使用字符串转义。
我们可以使用 noweb 执行来解决这个问题,并编写一个名为(未导出的) babel 代码块, 以字符串形式抓取另一个命名源代码块的内容。需要注意的是,这种方法目前不能扩展 嵌套的 noweb 引用。
;; (if-let ((block-pos (org-babel-find-named-block name))
;; (block (org-element-at-point block-pos)))
;; (format "%S" (string-trim (org-element-property :value block)))
;; ;; look for :noweb-ref matches
;; (let (block-contents)
;; (org-element-cache-map
;; (lambda (src)
;; (when (and (not (org-in-commented-heading-p nil src))
;; (not (org-in-archived-heading-p nil src))
;; (let* ((lang (org-element-property :language src))
;; (params
;; (apply
;; #'org-babel-merge-params
;; (append
;; (org-with-point-at (org-element-property :begin src)
;; (org-babel-params-from-properties lang t))
;; (mapcar
;; (lambda (h)
;; (org-babel-parse-header-arguments h t))
;; (cons (org-element-property :parameters src)
;; (org-element-property :header src))))))
;; (ref (alist-get :noweb-ref params)))
;; (equal ref name)))
;; (push (org-babel--normalize-body src)
;; block-contents)))
;; :granularity 'element
;; :restrict-elements '(src-block))
;; (and block-contents
;; (format "%S"
;; (mapconcat
;; #'identity
;; (nreverse block-contents)
;; "\n\n")))))
There we go, that’s all it takes! This can be used via the form <<grab("block-name")>>
.
守护进程是个好东西,但我不太会用,不过 EmacsWiki 中还是列出了各种方法
Doom 通过 packages.el
来安装包,非常简单,只需要 package!
就可以安装。
需要注意,不应该将该文件编译为字节码。
;; -*- no-byte-compile: t; -*-
;;; $DOOMDIR/packages.el
警告: 不要禁用 ~/.emacs.d/core/packages.el
中列出的包。Doom 依赖这些,禁用它们
可能出现严重问题。
- 从官方的源 MELPA / GNU ELPA / emacsmirror 安装
(package! some-package)
- 关闭某些包
(package! some-package :disable t)
- 从 Git Repo 安装
;; github (package! github-package :recipe (:host github :repo "username/repo")) ;; gitlab (package! gitlab-package :recipe (:host gitlab :repo "username/repo")) ;; other (package! other-package :recipe (:host nil :repo "https://example.com/repo"))
如果 repo 仅中只有某个 / 某些文件是你需要的
(package! some-package :recipe (:host github :repo "username/repo" :files ("some-file.el" "src/elisp/*.el")))
如果需要指定某个
commit
或某个branch
;; commit (package! some-package :pin "abcdefghijk") ;; branch (package! some-package :recipe (:branch "stable"))
- 使用本地的 repo
(package! some-package :recipe (:local-repo "/path/to/repo"))
让快捷键提示变得更快!
(setq which-key-idle-delay 0.5)
变形汽车人! 变形字符串!
(package! string-inflection)
(use-package! string-inflection
:defer t
:init
(map! :leader :prefix ("cS" . "naming convention")
:desc "cycle" "~" #'string-inflection-all-cycle
:desc "toggle" "t" #'string-inflection-toggle
:desc "CamelCase" "c" #'string-inflection-camelcase
:desc "downCase" "d" #'string-inflection-lower-camelcase
:desc "kebab-case" "k" #'string-inflection-kebab-case
:desc "under_score" "u" #'string-inflection-underscore
:desc "Upper_Score" "_" #'string-inflection-capital-underscore
:desc "UP_CASE" "U" #'string-inflection-upcase))
一次 backspace
吃掉所有空白符 (当前光标限定)
(package! hungry-delete :recipe (:host github :repo "nflath/hungry-delete"))
只让它应用在编程模式是最好的
(use-package! hungry-delete
:config
(setq-default hungry-delete-chars-to-skip " \t\v")
(add-hook! prog-mode #'hungry-delete-mode))
emacs 自带的强大文件管理器,和之后提到的 Magit、TRAMP 都是 Emacs 的杀手级应用。 还出现了很多增强性的包来增加其能力,不过对我来说,稍微修改一下也就够了。
(after! dired
(require 'dired-async)
(define-key! dired-mode-map "RET" #'dired-find-alternate-file)
(define-key! dired-mode-map "C" #'dired-async-do-copy)
(define-key! dired-mode-map "H" #'dired-async-do-hardlink)
(define-key! dired-mode-map "R" #'dired-async-do-rename)
(define-key! dired-mode-map "S" #'dired-async-do-symlink)
(define-key! dired-mode-map "n" #'dired-next-marked-file)
(define-key! dired-mode-map "p" #'dired-prev-marked-file)
(define-key! dired-mode-map "=" #'ginshio/dired-ediff-files)
(define-key! dired-mode-map "<mouse-2>" #'dired-mouse-find-file)
(defun ginshio/dired-ediff-files ()
"Mark files and ediff in dired mode, you can mark 1, 2 or 3 files and diff.
see: https://oremacs.com/2017/03/18/dired-ediff/"
(let ((files (dired-get-marked-files)))
(cond ((= (length files) 0))
((= (length files) 1)
(let ((file1 (nth 0 files))
(file2 (read-file-name "file: " (dired-dwim-target-directory))))
(ediff-files file1 file2)))
((= (length files) 2)
(let ((file1 (nth 0 files)) (file2 (nth 1 files)))
(ediff-files file1 file2)))
((= (length files) 3)
(let ((file1 (car files)) (file2 (nth 1 files)) (file3 (nth 2 files)))
(ediff-files3 file1 file2 file3)))
(t (error "no more than 3 files should be marked")))))
(define-advice dired-do-print (:override (&optional _))
"show/hide dotfiles in current dired
see: https://www.emacswiki.org/emacs/DiredOmitMode"
(cond ((or (not (boundp 'dired-dotfiles-show-p)) dired-dotfiles-show-p)
(setq-local dired-dotfiles-show-p nil)
(dired-mark-files-regexp "^\\.")
(dired-do-kill-lines))
(t (revert-buffer)
(setq-local dired-dotfiles-show-p t))))
(define-advice dired-up-directory (:override (&optional _))
"goto up directory in this buffer"
(find-alternate-file ".."))
(define-advice dired-do-compress-to (:override (&optional _))
"Compress selected files and directories to an archive."
(let* ((output (read-file-name "Compress to: "))
(command-assoc (assoc output dired-compress-files-alist 'string-match))
(files-str (mapconcat 'identity (dired-get-marked-files t) " ")))
(when (and command-assoc (not (string= "" files-str)))
(let ((command (format-spec (cdr command-assoc)
`((?o . ,output)
(?i . ,files-str)))))
(async-start (lambda () (shell-command command)) nil))))))
这应该是 Emacs 的杀手应用之一了,感谢 Jonas 及其他贡献者。
(after! magit
<<magit-tweaks>>)
Delta 是用 rust 实现的 git diff 语法高亮的工具。该作者还将其挂接到了 magit 的
diff 视图上 (默认不会有语法高亮)。不过这需要 delta
二进制文件,在 cargo 安装
显得简单些,不过你也可以选择 GitHub Release。
cargo install git-delta
简单地配置它就行
(package! magit-delta :recipe (:host github :repo "dandavison/magit-delta"))
(use-package! magit-delta
:after magit
:hook (magit-mode . magit-delta-mode))
但是它现在似乎不太好用。
在 Emacs 中处理冲突也是不错的体验,或许可以尝试自己制造一点
(defun smerge-repeatedly ()
"Perform smerge actions again and again"
(interactive)
(smerge-mode 1)
(smerge-transient))
(after! transient
(transient-define-prefix smerge-transient ()
[["Move"
("n" "next" (lambda () (interactive) (ignore-errors (smerge-next)) (smerge-repeatedly)))
("p" "previous" (lambda () (interactive) (ignore-errors (smerge-prev)) (smerge-repeatedly)))]
["Keep"
("b" "base" (lambda () (interactive) (ignore-errors (smerge-keep-base)) (smerge-repeatedly)))
("u" "upper" (lambda () (interactive) (ignore-errors (smerge-keep-upper)) (smerge-repeatedly)))
("l" "lower" (lambda () (interactive) (ignore-errors (smerge-keep-lower)) (smerge-repeatedly)))
("a" "all" (lambda () (interactive) (ignore-errors (smerge-keep-all)) (smerge-repeatedly)))
("RET" "current" (lambda () (interactive) (ignore-errors (smerge-keep-current)) (smerge-repeatedly)))]
["Diff"
("<" "upper/base" (lambda () (interactive) (ignore-errors (smerge-diff-base-upper)) (smerge-repeatedly)))
("=" "upper/lower" (lambda () (interactive) (ignore-errors (smerge-diff-upper-lower)) (smerge-repeatedly)))
(">" "base/lower" (lambda () (interactive) (ignore-errors (smerge-diff-base-lower)) (smerge-repeatedly)))
("R" "refine" (lambda () (interactive) (ignore-errors (smerge-refine)) (smerge-repeatedly)))
("E" "ediff" (lambda () (interactive) (ignore-errors (smerge-ediff)) (smerge-repeatedly)))]
["Other"
("c" "combine" (lambda () (interactive) (ignore-errors (smerge-combine-with-next)) (smerge-repeatedly)))
("r" "resolve" (lambda () (interactive) (ignore-errors (smerge-resolve)) (smerge-repeatedly)))
("k" "kill current" (lambda () (interactive) (ignore-errors (smerge-kill-current)) (smerge-repeatedly)))
("q" "quit" (lambda () (interactive) (smerge-auto-leave)))]]))
没有补全怎么写代码,尤其是 =Java=!!!
(after! company
(setq! company-idle-delay 0.3
company-minimum-prefix-length 2
company-show-numbers t)
) ;; make aborting less annoying.
现在改进大多来自 先前选项
的历史记录,所以我们改进以下历史记录。
(setq-default history-length 1024
prescient-history-length 1024)
还有最要紧的事,让待选选项有数字提示,方便直接 M-<num>
选择
(custom-set-variables '(company-show-numbers t))
(after! consult
(set-face-attribute 'consult-file nil :inherit 'consult-buffer)
(setf (plist-get (alist-get 'perl consult-async-split-styles-alist) :initial) ";"))
这不是老色批!自从 lsp 普及开始,无论配置什么编辑器都不再复杂了。看了一圈 lsp-mode tutorial 甚至觉得不需要配置什么,估计 doom 也有相应的配置。问题就是,熟 悉配置、操作的问题。
(after! lsp-ui
(setq lsp-ui-sideline-enable t
lsp-ui-sideline-show-diagnostics t
lsp-ui-sideline-show-hover nil
lsp-ui-sideline-show-code-actions t
lsp-ui-sideline-update-mode 'line
lsp-ui-peek-enable t
lsp-ui-peek-always-show t
lsp-ui-doc-enable t
lsp-ui-doc-use-childframe t
lsp-ui-doc-position 'at-point
lsp-ui-doc-delay 0.5
))
由于使用 tree-sitter 进行上色,那我们就不再需要 lsp 进行代码上色了
(setq! lsp-enable-semantic-highlighting t)
结构化编辑似乎成为了主流,不过 combobulate 支持的太少了。
(package! combobulate :recipe (:host github :repo "mickeynp/combobulate"))
默认启用 tree-sitter,不要忘记打开折叠功能
(setq! +tree-sitter-hl-enabled-modes '(python-mode rust-mode))
但是 tree-sitter 的高亮似乎有些问题,在这样的 C++ 代码中,会错误的高亮变量中的 关键字。
int main(int argc, char* /* argv */[]) {
int is_static_test = 10;
int test_class = 20;
for (int i = 0; i < argc; ++i) {
if ( test_class + is_static_test < argc ) {
return 2;
}
}
if ( is_static_test < argc ) {
return 1;
}
}
格式化代码是一个很重要的事情,但是,我希望还是不要再保存的时候格式化了!这会让代
码变得奇怪,尤其是合作的项目上。当然你可以手动用 +format/buffer
在需要的时候格式
化代码。但我不知道为什么这没什么用。
(appendq! +format-on-save-disabled-modes
'(c-mode
c++-mode
python-mode))
另外,不要让 lsp 污染 format!
(setq +format-with-lsp nil)
关于其他很有用的功能,TRAMP 算一个,它是多协议透明远程访问 (Transparent Remote Access, Multiple Protocol) 工具。简单说这是简单访问其他主机文件系统的方法。
如果你想使用 =ssh-key=,建议开始使用 ssh config~,并用 ~sshx:
进行 tramp 连接。
不幸的是,TRAMP 对远程连接时 SHELL 的提示格式很挑剔,尝试使用 bash 并放宽松提示 区域的识别。
(after! tramp
(setenv "SHELL" "/bin/bash")
(setq tramp-shell-prompt-pattern
"\\(?:^\\|
\\)[^]#$%>\n]*#?[]#$%>] *\\(�\\[[0-9;]*[a-zA-Z] *\\)*")) ;; default +
As good as terminal emulation gets in Emacs
VTerm 的安装相对麻烦一些,需要编译一些依赖。当然对于 Unix 用户,用系统库更加方便!
(setq! vterm-module-cmake-args "-DUSE_SYSTEM_LIBVTERM=yes")
snippets 套娃谁用谁知道!
(setq yas-triggers-in-field t)
让截图变得轻而易举!
(package! screenshot
:recipe (:host github :repo "tecosaur/screenshot")
)
(use-package! screenshot
:defer t
:config (setq screenshot-upload-fn "upload %s 2>/dev/null"))
作者并没有打算添加 TUI 支持。
首先添加一下彩虹猫,这不能忘!
(package! nyan-mode :recipe (:host github :repo "TeMPOraL/nyan-mode"))
(use-package! nyan-mode
:config
(setq nyan-animate-nyancat t
nyan-wavy-trail t
nyan-cat-face-number 4
nyan-bar-length 16
nyan-minimum-window-width 64)
(add-hook! doom-modeline #'nyan-mode))
这个包可以修改 emacs lisp 内联执行的视觉效果,让这个结果的前缀更好看一点。
(setq eros-eval-result-prefix "⟹ ") ; default =>
你可以用 C-x C-e
来对比一下前后变化
(+ 1 1 (* 2 2) 1)
return 2 ** 4
非常神奇的是你可以在 Emacs 中用现有的 Theme,改变终端的 Theme,且 GUI 和 TUI 都
可用!作者说 Linux 和 Mac 可用,=Windows Terminal= + WSL
同样适用,压力来到了
纯 Windows 下的 Emacs。
(package! theme-magic)
这个操作使用 =pywal=,你可以通过仓库安装它,不过最简单的方式就是 =pip=。
sudo python3 -m pip install pywal
Theme Magic 提供了一个数字界面,尝试从饱和度、色彩差异来有效的选取八个颜色。然而,它 可能会为 light 选择相同的颜色,并不总能够选取最佳颜色。我们可以用 Doom themes 提供的色彩工具来轻松获取合理的配色来生成 light 版本 — 现在就开始!
(use-package! theme-magic
:defer t
:after +doom-dashboard
:config
(defadvice! theme-magic--auto-extract-16-doom-colors ()
:override #'theme-magic--auto-extract-16-colors
(list
(face-attribute 'default :background)
(doom-color 'error)
(doom-color 'success)
(doom-color 'type)
(doom-color 'keywords)
(doom-color 'constants)
(doom-color 'functions)
(face-attribute 'default :foreground)
(face-attribute 'shadow :foreground)
(doom-blend 'base8 'error 0.1)
(doom-blend 'base8 'success 0.1)
(doom-blend 'base8 'type 0.1)
(doom-blend 'base8 'keywords 0.1)
(doom-blend 'base8 'constants 0.1)
(doom-blend 'base8 'functions 0.1)
(face-attribute 'default :foreground))))
让 info 变得更加绚丽夺目。
(package! info-colors)
(use-package! info-colors
:after info
:commands (info-colors-fontify-node)
:hook (Info-selection . info-colors-fontify-node))
如果你想像现代编辑器一样拥有 tabs,或许你可以考虑一下。如果想要 tabs 底下显示
=bar=,需要开启 x-underline-at-descent-line
(after! centaur-tabs
(setq! centaur-tabs-style "bar"
centaur-tabs-set-icons t
centaur-tabs-plain-icons nil
centaur-tabs-set-modified-marker t
centaur-tabs-show-navigation-buttons nil
centaur-tabs-gray-out-icons 'buffer
centaur-tabs-set-bar 'under
x-underline-at-descent-line t
centaur-tabs-label-fixed-length 9)
(defun centaur-tabs-hide-tab (x)
"Do no to show buffer X in tabs."
(let ((name (format "%s" x)))
(or
;; Current window is not dedicated window.
(window-dedicated-p (selected-window))
;; Buffer name not match below blacklist.
(string-prefix-p "*epc" name)
(string-prefix-p "*helm" name)
(string-prefix-p "*Helm" name)
(string-prefix-p "*Compile-Log*" name)
(string-prefix-p "*lsp" name)
(string-prefix-p "*company" name)
(string-prefix-p "*Flycheck" name)
(string-prefix-p "*tramp" name)
(string-prefix-p " *Mini" name)
(string-prefix-p "*help" name)
(string-prefix-p "*straight" name)
(string-prefix-p " *temp" name)
(string-prefix-p "*Help" name)
(string-prefix-p "*mybuf" name)
(string-prefix-p "► Doom" name)
;; Is not magit buffer.
(and (string-prefix-p "magit" name)
(not (file-name-extension name)))
)))
(centaur-tabs-group-by-projectile-project)
(centaur-tabs-mode t))
但是别忘了,需要在配置文件接口中开启 tabs
选项。还不能忘记添加快捷键
(map! :map ctl-x-map
:prefix ("t" . "Tab and Treemacs")
"a" #'centaur-tabs-select-beg-tab
"e" #'centaur-tabs-select-end-tab
"f" #'centaur-tabs-forward-tab
"F" #'centaur-tabs-forward-group
"b" #'centaur-tabs-backward-tab
"B" #'centaur-tabs-backward-group
"g" #'centaur-tabs-switch-group
"G" #'centaur-tabs-toggle-groups
"l" #'centaur-tabs-move-current-tab-to-left
"r" #'centaur-tabs-move-current-tab-to-right
"k" #'centaur-tabs-kill-other-buffers-in-current-group
"K" #'centaur-tabs-kill-unmodified-buffers-in-current-group
"C-5" #'centaur-tabs-extract-window-to-new-frame
"C-o" #'centaur-tabs-open-in-external-application
"C-d" #'centaur-tabs-open-directory-in-external-application
)
现在 Doom emacs 使用 =nerd-icons=。
(after! nerd-icons
(setcdr (assoc "m" nerd-icons-extension-icon-alist)
(cdr (assoc "matlab" nerd-icons-extension-icon-alist))))
开启 git-mode=、=follow-mode
和 =indent-guide-mode=,体验还是不错
(after! treemacs
(setq! doom-themes-treemacs-theme "doom-colors"
treemacs-deferred-git-apply-delay 0.5
treemacs-directory-name-transformer #'identity
treemacs-display-in-side-window t
treemacs-file-event-delay 1000
treemacs-file-follow-delay 0.1
treemacs-file-name-transformer #'identity
treemacs-hide-dot-git-directory t
treemacs-indent-guide-style 'block
treemacs-show-hidden-files t)
(treemacs-indent-guide-mode t)
(treemacs-follow-mode t)
(treemacs-filewatch-mode t)
(treemacs-fringe-indicator-mode 'always)
(treemacs-git-mode 'deferred)
(treemacs-hide-gitignored-files-mode t)
)
hl-todo
允许你设置一些关键字,这些关键字将高亮并且便于查找。往往用于代码注释中
强调某些内容。
(custom-set-variables
'(hl-todo-keyword-faces '(("NOTE" font-lock-builtin-face bold) ;; needs discussion or further investigation.
("REVIEW" font-lock-keyword-face bold) ;; review was conducted.
("HACK" font-lock-variable-name-face bold) ;; workaround a known problem.
("DEPRECATED" region bold) ;; why it was deprecated and to suggest an alternative.
("XXX+" font-lock-constant-face bold) ;; warn other programmers of problematic or misguiding code.
("TODO" font-lock-function-name-face bold) ;; tasks/features to be done.
("FIXME" font-lock-warning-face bold) ;; problematic or ugly code needing refactoring or cleanup.
("KLUDGE" font-lock-preprocessor-face bold )
("BUG" error bold) ;; a known bug that should be corrected.
)))
Snippet 可以很好的帮助我们初始化一些文件。
;;(set-file-template! "\\.org$" :trigger "__" :mode 'org-mode)
(set-file-template! "/LICEN[CS]E$" :trigger '+file-templates/insert-license)
我不介意左侧没有任何边距的 buffer,但是一旦剥离行号,buffer 就会感觉有点不对劲。
(defvar +text-mode-left-margin-width 1
"The `left-margin-width' to be used in `text-mode' buffers.")
(defun +setup-text-mode-left-margin ()
(when (and (derived-mode-p 'text-mode)
(eq (current-buffer) ; Check current buffer is active.
(window-buffer (frame-selected-window))))
(setq left-margin-width (if display-line-numbers
0 +text-mode-left-margin-width))
(set-window-buffer (get-buffer-window (current-buffer))
(current-buffer))))
现在我们只需要将它连接到所有可能表明条件发生变化或需要重新应用设置的事件。
(add-hook! (window-configuration-change display-line-numbers-mode)
#'+setup-text-mode-left-margin)
(add-hook! text-mode #'+setup-text-mode-left-margin)
Doom 有一个小问题,因为 doom/toggle-line-numbers
不运行 ~display-line-numbers-mode-hook~,所以需要一些设置。
(defadvice! +doom/toggle-line-numbers--call-hook-a ()
:after #'doom/toggle-line-numbers
(run-hooks 'display-line-numbers-mode-hook))
最后,我想我真的很喜欢这个,我会继续在文本模式下删除行号。
(remove-hook! text-mode #'display-line-numbers-mode)
因为这部分初始化时相当费时,我们需要将其放在 src_elisp{(after! …)} 中。
(after! org
<<org-conf>>
)
(setq! org-use-property-inheritance t ; it's convenient to have properties inherited
org-log-done 'time ; having the time a item is done sounds convenient
org-list-allow-alphabetical t ; have a. A. a) A) list bullets
;; org-export-in-background t ; run export processes in external emacs process
org-catch-invisible-edits 'smart ; try not to accidently do weird stuff in invisible regions
org-export-with-sub-superscripts '{} ; don't treat lone _ / ^ as sub/superscripts, require _{} / ^{}
org-export-allow-bind-keywords t ; Bind keywords can be handy
org-image-actual-width '(0.9) ; Make the in-buffer display closer to the exported result..
)
I also like the src_elisp{:comments} header-argument, so let’s make that a default.
(setq org-babel-default-header-args
'((:session . "none")
(:results . "replace")
(:exports . "code")
(:cache . "no")
(:noweb . "no")
(:hlines . "no")
(:tangle . "no")
(:comments . "link")))
偶尔在用 Org 是你希望将两个分开的块放在一起,这点有点烦人。比如将加*重*一个单词 的一部分,或者说在内联源码块之前放一些符号。有一个可以解决的方法 — 零宽空格。 由于这是 Emacs,我们可以为 org-mode 做一个很小的改动将其添加到快捷键上 🙂。
(map! :map org-mode-map
:leader
:desc "zero-width-space" "SPC" (cmd! (insert "\u200B")))
生成目录的需求并不大,但是像 GitHub
的环境下 TOC 可能成为必要,采用 toc-org
来生成。
(use-package! toc-org
:defer t
:after (:any org markdown)
:config
(toc-org-mode t)
(add-hook! (org-mode markdown-mode) #'toc-org-mode)
(define-key! org-mode-map "C-c C-i" #'toc-org-insert-toc)
(define-key! markdown-mode-map "C-c M-t" #'toc-org-insert-toc))
toc-org
会清空带有 TOC
标签的 heading,并生成目录。
我不确定真的需要它嘛,因此我将它关闭了。
org-crypt
可以用 GPG
加密 Org Mode 的某些 heading,当然是带有 crypt
标签的。
现在来设置一下。
(use-package! org-crypt
:custom
(org-crypt-key "0xA173AD0063A4E2DFAB4F9EAE65F09D172E677525")
(org-tags-exclude-from-inheritance '("crypt")) ;; avoid repeated encryption
:config
(org-crypt-use-before-save-magic) ;; encrypt when writing back to the hard disk
(map! :map org-mode-map
:localleader
:desc "org-encrypt" "C" nil
:desc "encrypt current" "C e" #'org-encrypt-entry
:desc "encrypt all" "C E" #'org-encrypt-entries
:desc "decrypt current" "C d" #'org-decrypt-entry
:desc "decrypt all" "C D" #'org-decrypt-entries))
如果想用其他密钥加密,可以设置 cryptkey
属性。
* Totally secret :crypt:
:properties:
:cryptkey: 0x0123456789012345678901234567890123456789
:end:
(setq org-list-demote-modify-bullet '(("+" . "-") ("-" . "+") ("*" . "+") ("1." . "a.")))
;;; (org-cite-global-bibliography '("~/library/ebooks/catalog.bib" "~/library/papers/catalog.bib"))
(after! citar
(setq! citar-symbol-separator " "
citar-bibliography org-cite-global-bibliography
citar-symbols
`((file ,(nerd-icons-faicon "nf-fa-file_o" :face 'nerd-icons-green :v-adjust -0.1) . " ")
(note ,(nerd-icons-octicon "nf-oct-note" :face 'nerd-icons-blue :v-adjust -0.3) . " ")
(link ,(nerd-icons-octicon "nf-oct-link" :face 'nerd-icons-orange :v-adjust 0.01) . " ")))
(org-cite-follow-processor 'citar)
(org-cite-activate-processor 'citar)
(add-to-list 'citar-major-mode-functions
'((gfm-mode)
(insert-keys . citar-markdown-insert-keys)
(insert-citation . citar-markdown-insert-citation)
(insert-edit . citar-markdown-insert-edit)
(key-at-point . citar-markdown-key-at-point)
(citation-at-point . citar-markdown-citation-at-point)
(list-keys . citar-markdown-list-keys))))
主要为了引用的灵活性,这里并没有设置全局 bib,如果想在 Org 里引用某些 bib 文件可 以采用以下方法。
#+bibliography: ~/library/ebooks/catalog.bib
#+bibliography: ~/library/papers/catalog.bib
当然这配置很简单,只不过功能很强大,关于 org-cite
和 citar
要学的还有很多。
可以看看 这篇。
默认情况下,lsp 并不支持应用在 src 块中。
;; Enable LSP in org babel
;; need to add `:file test.xx' in the header
;; https://github.com/emacs-lsp/lsp-mode/issues/377
(cl-defmacro lsp-org-babel-enable (lang)
"Support LANG in org source code block."
(setq centaur-lsp 'lsp-mode)
(cl-check-type lang string)
(let* ((edit-pre (intern (format "org-babel-edit-prep:%s" lang)))
(intern-pre (intern (format "lsp--%s" (symbol-name edit-pre)))))
`(progn
(defun ,intern-pre (info)
(let ((file-name (->> info caddr (alist-get :file))))
(unless file-name
(setq file-name (make-temp-file "babel-lsp-")))
(setq buffer-file-name file-name)
(lsp-deferred)))
(put ',intern-pre 'function-documentation
(format "Enable lsp-mode in the buffer of org source block (%s)."
(upcase ,lang)))
(if (fboundp ',edit-pre)
(advice-add ',edit-pre :after ',intern-pre)
(progn
(defun ,edit-pre (info)
(,intern-pre info))
(put ',edit-pre 'function-documentation
(format "Prepare local buffer environment for org source block (%s)."
(upcase ,lang))))))))
(defvar org-babel-lang-list
'("python"))
(dolist (lang org-babel-lang-list)
(eval `(lsp-org-babel-enable ,lang)))
(defvar org-agenda-dir (concat org-directory "/" "agenda"))
(defvar org-agenda-todo-file (expand-file-name "todo.org" org-agenda-dir))
(defvar org-agenda-project-file (expand-file-name "project.org" org-agenda-dir))
(after! org-agenda
;;urgancy|soon|as soon as possible|at some point|eventually
;;
(setq! org-agenda-files `(,org-agenda-todo-file
,org-agenda-project-file)
org-agenda-skip-scheduled-if-done t
org-agenda-skip-deadline-if-done t
org-agenda-include-deadlines t
org-agenda-block-separator nil
org-agenda-tags-column 100 ;; from testing this seems to be a good value
org-agenda-compact-blocks t))
开始设置 Org-capture 模板吧,快速记录!
(after! org-capture
(defun ginshio/find-project-tree(priority)
"find or create project headline
https://www.zmonster.me/2018/02/28/org-mode-capture.html"
(let* ((hl (let ((headlines (org-element-map (org-element-parse-buffer 'headline) 'headline
(lambda (hl) (and (= (org-element-property :level hl) 1)
(org-element-property :title hl))))))
(completing-read "Project Name: " headlines))))
(goto-char (point-min))
(if (re-search-forward
(format org-complex-heading-regexp-format (regexp-quote hl)) nil t)
(goto-char (point-at-bol))
(progn
(or (bolp) (insert "\n"))
(if (/= (point) (point-min)) (org-end-of-subtree))
(insert (format "* %s :project:%s:\n:properties:\n:homepage: %s\n:repo: \
%s\n:end:\n\n** urgancy :urgancy:\n\n** soon :soon:\n\n** as soon as\
possible :asap:\n\n** at some point :asp:\n\n** eventually :eventually:\n"
hl hl (read-string "homepage: ") (read-string "repo: ")))
(beginning-of-line 0)
(org-up-heading-safe))))
(re-search-forward
(format org-complex-heading-regexp-format
(regexp-quote priority))
(save-excursion (org-end-of-subtree t t)) t)
(org-end-of-subtree))
(setq! org-capture-dir (expand-file-name "capture" org-directory)
org-capture-snippet-file (expand-file-name "snippets.org" org-capture-dir)
org-capture-comment-file (expand-file-name "comments.org" org-capture-dir)
org-capture-note-file (expand-file-name "notes.org" org-capture-dir)
org-capture-blog-file (expand-file-name "blogs.org" org-capture-dir)
)
;; http://www.howardism.org/Technical/Emacs/journaling-org.html
;; https://www.zmonster.me/2018/02/28/org-mode-capture.html
(setq org-capture-templates
`(("B" "Blog TODO List" entry (file ,org-capture-blog-file)
"* TODO [#%^{priority|D|A|B|C|E}] %^{blog_title}\n:properties:\n:categories: %^{categories}\n:tags: %^{tags}\n:title: %\\1\n:file_name: %^{file_name}\n:end:\n%?"
:empty-lines 1)
("c" "Comment")
("cb" "Book" entry (file+weektree ,org-capture-comment-file)
"* %^{book} :book:%\\1:\n%?" :empty-lines 1)
("cm" "Movie" entry (file+weektree ,org-capture-comment-file)
"* %^{movie} :movie:%\\1:\n%?" :empty-lines 1)
("g" "GTD")
("gt" "Todo" entry (file+headline org-agenda-todo-file "Personal")
"* TODO [#%^{priority|A|B|C|D|E}] %^{task}\n SCHEDULED: %^T DEADLINE: %^T\n:properties:\n:end:\n%?"
:empty-lines 1)
("gi" "Interview" entry (file+headline ,org-agenda-todo-file "Interview")
"* WAIT [#%^{priority|B|A|C|D}] %^{company} - %^{position}\t:%\\2:\nSCHEDULED: %^T DEADLINE: %^T\n:properties:\n:url: %^{link}\n:end:\n%?"
:prepend t :empty-lines 1)
("gd" "Daily" entry (file+headline ,org-agenda-todo-file "Daily")
"* TODO [#%^{priority|C|A|B|D|E}] %^{task}\n SCHEDULED: %<<%Y-%m-%d %a %H:%M ++1d>>\n:properties:\n:end:\n%?"
:empty-lines 1)
("gw" "Weekly" entry (file+headline ,org-agenda-todo-file "Weekly")
"* TODO [#%^{priority|B|A|C|D|E}] %^{task}\n SCHEDULED: %<<%Y-%m-%d %a %H:%M ++1w>>\n:properties:\n:end:\n%?"
:empty-lines 1)
("gm" "Monthly" entry (file+headline ,org-agenda-todo-file "Monthly")
"* TODO [#%^{priority|C|A|B|D|E}] %^{task}\n SCHEDULED: %<<%Y-%m-%d %a %H:%M ++1m>>\n:properties:\n:end:\n%?"
:empty-lines 1)
("n" "Note")
("nc" "Computer" entry (file+headline ,org-capture-note-file "Computer")
"* %^{heading} %^g\n%?\n" :empty-lines 1)
("ne" "Emacs" entry (file+headline ,org-capture-note-file "Emacs")
"* %^{heading} %^g\n%?\n" :empty-lines 1)
("ng" "Game" entry (file+headline ,org-capture-note-file "Game")
"* %^{heading} %^g\n%?\n" :empty-lines 1)
;; ("p" "Project")
;; ("pa" "Urgance" entry (file+function ,org-agenda-project-file
;; (lambda () (ginshio/find-project-tree "urgancy")))
;; "*** TODO [#A] %^{task}\n SCHEDULED: %<<%Y-%m-%d %a %H:%M>> DEADLINE: %^T\n :properties:\n :end:\n%?"
;; :empty-lines 1)
;; ("pb" "Soon" entry (file+function ,org-agenda-project-file
;; (lambda () (ginshio/find-project-tree "soon")))
;; "*** TODO [#B] %^{task}\n SCHEDULED: %<<%Y-%m-%d %a %H:%M>> DEADLINE: %^T\n :properties:\n :end:\n%?"
;; :empty-lines 1)
;; ("pc" "As Soon As Possiple" entry (file+function ,org-agenda-project-file
;; (lambda () (ginshio/find-project-tree "as soon as possiple")))
;; "*** TODO [#C] %^{task}\n SCHEDULED: %<<%Y-%m-%d %a %H:%M>> DEADLINE: %^T\n :properties:\n :end:\n%?"
;; :empty-lines 1)
;; ("pd" "At Some Point" entry (file+function ,org-agenda-project-file
;; (lambda () (ginshio/find-project-tree "at some point")))
;; "*** TODO [#D] %^{task}\n SCHEDULED: %<<%Y-%m-%d %a %H:%M>> DEADLINE: %^T\n :properties:\n :end:\n%?"
;; :empty-lines 1)
;; ("pe" "Eventually" entry (file+function ,org-agenda-project-file
;; (lambda () (ginshio/find-project-tree "eventually")))
;; "*** TODO [#E] %^{task}\n SCHEDULED: %<<%Y-%m-%d %a %H:%M>> DEADLINE: %^T\n :properties:\n :end:\n%?"
;; :empty-lines 1)
("s" "Code Snippet" entry (file ,org-capture-snippet-file)
"* %^{heading} :code:%\\2:\n:properties:\n:language: %^{language}\n:end:\n\n#+begin_src %\\2\n%?\n#+end_src"
:empty-lines 1)
)))
使 org-mode
buffer 尽可能漂亮是很重要的,Minad 的 org-modern
在这方面大有帮助。
(package! org-modern)
(use-package! org-modern
:hook
(org-mode . org-modern-mode)
(org-agenda-finalize . org-modern-agenda)
:config
(setq org-modern-star 'replace
org-modern-replace-stars "♇♆♅♄♃♂♀☿" ;; "◉○✸✿✤✜◆▶"
org-modern-table-vertical 1
org-modern-table-horizontal 0.2
org-modern-list '((43 . "➤")
(45 . "–")
(42 . "•"))
org-modern-todo-faces '(("TODO" . (:inherit org-verbatim :weight semi-bold :foreground "white" :background "goldenrod"))
("NEXT" . (:inherit org-verbatim :weight semi-bold :foreground "white" :background "IndianRed1"))
("STRT" . (:inherit org-verbatim :weight semi-bold :foreground "white" :background "OrangeRed"))
("WAIT" . (:inherit org-verbatim :weight semi-bold :foreground "white" :background "coral"))
("KILL" . (:inherit org-verbatim :weight semi-bold :foreground "white" :background "DarkGreen"))
("PROJ" . (:inherit org-verbatim :weight semi-bold :foreground "white" :background "LimeGreen"))
("HOLD" . (:inherit org-verbatim :weight semi-bold :foreground "white" :background "orange"))
("DONE" . (:inherit org-verbatim :weight semi-bold :foreground "black" :background "LightGray")))
org-modern-footnote (cons nil (cadr org-script-display))
org-modern-block-fringe nil
org-modern-block-name '((t . t)
("src" "»" "«")
("example" "»–" "–«")
("quote" "❝" "❞")
("export" "⏩" "⏪"))
org-modern-progress nil
org-modern-priority nil
org-modern-horizontal-rule (make-string 36 ?─)
org-modern-keyword '((t . t)
("title" . "𝙏")
("subtitle" . "𝙩")
("author" . "𝘼")
("email" . "")
("date" . "𝘿")
("property" . "")
("options" . #("" 0 1 (display (height 0.75))))
("startup" . "⏻")
("macro" . "𝓜")
("bind" . "")
("bibliography" . "")
("print_bibliography" . "")
("cite_export" . "⮭")
("print_glossary" . "ᴬᶻ")
("glossary_sources" . "")
("include" . "⇤")
("setupfile" . "⇚")
("html_head" . "🅷")
("html" . "🅗")
("latex_class" . "🄻")
("latex_class_options" . "🄻")
("latex_header" . "🅻")
("latex_header_extra" . "🅻⁺")
("latex" . "🅛")
("beamer_theme" . "🄱")
("beamer_color_theme" . "🄱")
("beamer_font_theme" . "🄱𝐀")
("beamer_header" . "🅱")
("beamer" . "🅑")
("attr_latex" . "🄛")
("attr_html" . "🄗")
("attr_org" . "⒪")
("call" . "")
("name" . "⁍")
("header" . "›")
("caption" . "☰")
("results" . "🠶"))
org-auto-align-tags nil
org-tags-column 0
org-catch-invisible-edits 'show-and-error
org-special-ctrl-a/e t
org-hide-emphasis-markers t
org-agenda-tags-column 0
org-agenda-block-separator ?─
org-agenda-time-grid '((daily today require-timed)
(800 1000 1200 1400 1600 1800 2000)
" ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
org-agenda-current-time-string "⭠ now ─────────────────────────────────────────────────"
)
(custom-set-variables '(org-modern-statistics :inherit org-checkbox-statistics-todo)))
虽然 org-hide-emphasis-markers
非常好,但有时它会使边界处的编辑变得更加繁琐。
我们可以使用 org-appear
包在不牺牲视觉便利的情况下改善这种情况。
(package! org-appear
:recipe (:host github :repo "awth13/org-appear"))
(use-package! org-appear
:hook (org-mode . org-appear-mode)
:config
(setq! org-appear-autoemphasis t
org-appear-autosubmarkers t
org-appear-autolinks nil)
;; for proper first-time setup, `org-appear--set-elements'
;; needs to be run after other hooks have acted.
(run-at-time nil nil #'org-appear--set-elements))
本身不用加这个包的,不过移除了 doom 配置里的 `(org +pretty)` 的选项,只好自己手 动来做这件事了。
(package! org-fancy-priorities
:recipe (:host github :repo "harrybournis/org-fancy-priorities"))
更改用于折叠项目的字符也很好 (默认情况下 …
),我认为用 ▾
更适合指示 「折叠部
分」。并在默认的四个列表中添加一个额外的 org-bullet
。对了,别忘记优先级也要修
改。
(use-package! org-fancy-priorities
:ensure t
:hook (org-mode . org-fancy-priorities-mode)
:custom (org-lowest-priority ?E)
:config (setq! org-fancy-priorities-list '("⚡" "↑" "↓" "☕" "❓")))
(setq! org-ellipsis " ▾ "
org-hide-leading-stars t
org-priority-highest ?A
org-priority-lowest ?E
org-priority-faces
'((?A . 'nerd-icons-red)
(?B . 'nerd-icons-orange)
(?C . 'nerd-icons-yellow)
(?D . 'nerd-icons-green)
(?E . 'nerd-icons-blue)))
(setq! +ligatures-extra-symbols
(list :list_property "∷"
:em_dash "—"
:ellipses "…"
:arrow_right "→"
:arrow_left "←"
:arrow_lr "↔"
:properties "⚙"
:end "∎"
:priority_a #("⚑" 0 1 (face nerd-icons-red))
:priority_b #("⬆" 0 1 (face nerd-icons-orange))
:priority_c #("■" 0 1 (face nerd-icons-yellow))
:priority_d #("⬇" 0 1 (face nerd-icons-green))
:priority_e #("❓" 0 1 (face nerd-icons-blue))))
(defadvice! +org-init-appearance-h--no-ligatures-a ()
:after #'+org-init-appearance-h
(set-ligatures! 'org-mode nil)
(set-ligatures! 'org-mode
:list_property "::"
:em_dash "---"
:ellipsis "..."
:arrow_right "->"
:arrow_left "<-"
:arrow_lr "<->"
:properties ":PROPERTIES:"
:end ":END:"
:priority_a "[#A]"
:priority_b "[#B]"
:priority_c "[#C]"
:priority_d "[#D]"
:priority_e "[#E]"))
让公式稍稍好看一点点
(setq! org-highlight-latex-and-related '(native script entities))
理想情况下 org-src-font-lock-fontify-block
不会添加 org-block
,但我
们可以通过添加带有 :inherit default
面来避免整个功能,这将覆盖背景颜色。
检查 org-do-latex-and-related
显示 "latex"
是传递的语言参数,因此我们
可以如上所述覆盖背景。
(require 'org-src)
(add-to-list 'org-src-block-faces '("latex" (:inherit default :extend t)))
比语法高亮的 LaTeX 更好的是 呈现 LaTeX。我们可以使用 org-fragtog
自动执
行此操作。
(package! org-fragtog)
(use-package! org-fragtog :hook (org-mode . org-fragtog-mode))
自定义 LaTeX 片段的外观很舒适,这样它们就更适合文本了 — 比如这个 $\sqrt{β^2+3}-∑φ=1^∞ \frac{x^φ-1}{Γ(a)}$。
(setq! org-preview-latex-default-process 'dvisvgm
org-preview-latex-process-alist
'((dvipng :programs ("latex" "dvipng")
:description "dvi --> png"
:message "you need to install the programs: latex and dvipng."
:image-input-type "dvi"
:image-output-type "png"
:image-size-adjust (1.0 . 1.0)
:latex-compiler ("lualatex --shell-escape --output-format=dvi --interaction=nonstopmode --output-directory=%o %f")
:image-converter ("dvipng -D %D -T tight -bg Transparent -o %O %f"))
(dvisvgm :programs ("latex" "dvisvgm")
:description "dvi --> svg"
:message "you need to install the programs: latex and dvisvgm."
:use-xcolor t
:image-input-type "dvi"
:image-output-type "svg"
:image-size-adjust (1.7 . 1.5)
:latex-compiler ("lualatex --shell-escape --output-format=dvi --interaction=nonstopmode --output-directory=%o %f")
:image-converter ("dvisvgm %f --no-specials=bgcolor -n -b min -c %S -o %O"))
(imagemagick :programs ("latex" "convert")
:description "pdf --> png"
:message "you need to install the programs: latex and imagemagick."
:use-xcolor t
:image-input-type "pdf"
:image-output-type "png"
:image-size-adjust (1.0 . 1.0)
:latex-compiler ("lualatex --shell-escape --output-format=pdf --interaction=nonstopmode --output-directory=%o %f")
:image-converter ("convert -density %D -trim -antialias %f -quality 100 %O")))
org-format-latex-header "
\\documentclass{standalone}
[DEFAULT-PACKAGES]
[PACKAGES]
% Custom font
\\usepackage{arev}
<<latex-maths-conveniences>>
")
(plist-put org-format-latex-options :background "Transparent")
(plist-put org-format-latex-options :zoom 0.93) ; Calibrated based on the TeX font and org-buffer font.
顺便设置下背景
(defun +org-refresh-latex-images-previews-h ()
(dolist (buffer (doom-buffers-in-mode 'org-mode (buffer-list)))
(with-current-buffer buffer
(+org--toggle-inline-images-in-subtree (point-min) (point-max) 'refresh)
(unless (eq org-latex-preview-default-process 'dvisvgm)
(org-clear-latex-preview (point-min) (point-max))
(org--latex-preview-region (point-min) (point-max))))))
(add-hook! doom-load-theme #'+org-refresh-latex-images-previews-h)
Org 使用 #+begin_src
块做了一些事情,比如在幕后使用 font-lock 作为语言的主要模
式并拉出良好的彩色结果。相比之下,内联 src_
块在某种程度上被忽略了。
我不是第一个有这种感觉的人, 幸好他们已经开始在 stackexchange 上开始讨论了。 我打
算直接使用他们的结果,但不幸的是,他们没有执行 true 源代码字体化,而只是将
org-code
应用在内容上。
我们可以做得比这更好!使用 org-src-font-lock-fontify-block
我们可以应用适合语
言的语法高亮。然后,继续到 {{{results(...)}}}=,它可以将 =org-block
应用相应的
规则,然后通过模仿 prettify-symbols-mode
的行为隐藏值包围结构。
(setq! org-inline-src-prettify-results '("⟨" . "⟩"))
Doom 主题的额外字体化问题多于帮助。
(setq! doom-themes-org-fontify-special-tags nil)
我们需要建立一个通天的巴别塔,以便我们可以在 org-mode 的任意位置编写以及运行任何 编程语言!
<<org-babel-conf>>
如果导出到文件,我们使用定制化的 LaTeX 导出,也就是应用所有关于我们对于 org-mode latex 的定制化设置。(HTML 除外?)
(defadvice! org-babel-execute-latex-export-file (orig-fn body params)
"Like `org-babel-execute:latex', support org-format-latex-header for all"
:around #'org-babel-execute:latex
(if (string-suffix-p ".html" (cdr (assq :file params)))
(funcall orig-fn body params)
(let ((expanded-body (org-babel-expand-body:latex body params))
(latex-compiler
(list :latex-compiler (or (cadar (org-collect-keywords '("latex_compiler"))) org-latex-compiler))))
(if (cdr (assq :file params))
(ginshio/org-babel-execute-latex-export-file latex-compiler expanded-body params)
expanded-body))))
(defun ginshio/org-babel-execute-latex-export-file (latex-compiler body params)
(let* ((out-file (cdr (assq :file params)))
(extension (file-name-extension out-file))
(tex-file (org-babel-temp-file "latex-" ".tex"))
(border (cdr (assq :border params)))
(imagemagick (cdr (assq :imagemagick params)))
(fit (or (cdr (assq :fit params)) border))
(headers (cdr (assq :headers params))))
(stringp nil)
(with-temp-file tex-file
(require 'ox-latex)
(insert
(org-latex--insert-compiler latex-compiler)
(org-latex-guess-inputenc
(org-splice-latex-header
org-format-latex-header
(delq nil
(mapcar
(lambda (el)
(unless (and (listp el) (string= "hyperref" (cadr el))) el))
org-latex-default-packages-alist))
(append (cdr (assq :packages params)) org-latex-packages-alist)
nil))
(if (string= "png" extension)
(format "%s%s%s%s"
(if fit "\n\\usepackage[active,tightpage]{preview}\n" "")
(if border (format "\\setlength{\\PreviewBorder}{%s}\n" border) "")
(let ((height (and fit (cdr (assq :pdfheight params)))))
(if height (format "\\pdfpageheight %s\n" height) ""))
(let ((width (and fit (cdr (assq :pdfwidth params)))))
(if width (format "\\pdfpageheight %s\n" width) "")))
"")
(if headers
(concat "\n"
(if (listp headers)
(mapconcat #'identity headers "\n")
headers) "\n")
"")
(if (and fit (string= "png" extension))
(concat "\n\\begin{document}\n\\begin{preview}\n" body
"\n\\end{preview}\n\\end{document}\n")
(concat "\n\\begin{document}\n" body "\n\\end{document}\n"))))
(when (file-exists-p out-file) (delete-file out-file))
(if (string= "tex" extension)
(rename-file tex-file out-file)
(let* ((transient-pdf-file (org-babel-latex-tex-to-pdf tex-file)))
(cond
((string= "pdf" extension)
(rename-file transient-pdf-file out-file))
((and (string= "png" extension) imagemagick)
(org-babel-latex-convert-pdf
transient-pdf-file out-file (cdr (assq :iminoptions params)) (cdr (assq :imoutoptions params))))
((string= "svg" extension)
(let* ((log-buf (get-buffer-create "*Org Babel LaTeX Output*"))
(err-msg "org babel latex failed")
(img-out (org-compile-file
transient-pdf-file
(list org-babel-latex-pdf-svg-process)
extension err-msg log-buf)))
(rename-file img-out out-file)))
(t
(error "Can not create %s files, please specify a .svg, .png or .pdf file or try the :imagemagick header argument"
extension)))))))
默认情况下,Org 仅将前三个级别的标题导出为标题。当使用 article
时,LaTeX 标题
从 \section=、
\subsection=、=\subsubsection= 和 \paragraph=、
=\subgraph
— 五 个级别。HTML5 有六级标题 (<h1>
到 <h6>
),但第一级 Org
标题被导出为 <h2>
元素 — 剩下 五 个可用级别。
(setq! org-export-headline-levels 5)
(after! ox
<<org-export-conf>>
)
我还将使用 ox-extra
中的一个项目,以便我可以在标题中添加一个 :ignore:
标记以
保留内容,但标题本身会被忽略(=:noexport:= 它忽略了标题和内容)。当我想使用标题
来提供未出现在最终文档中的写作结构时,这很有用。
(require 'ox-extra)
(ox-extras-activate '(ignore-headlines))
由于我(大致)跟踪 Org ~HEAD~,因此在创建者字符串中包含 git 版本是有意义的。
(setq! org-export-creator-string
(format "Emacs %s (Org mode %s–%s)" emacs-version (org-release) (org-git-version)))
在导出时,我并不想要零宽度空格,加一个简单的过滤器将其过滤掉。
(defun +org-export-remove-zero-width-space (text _backend _info)
"Remove zero width spaces from TEXT."
(unless (org-export-derived-backend-p 'org)
(replace-regexp-in-string "\u200B" "" text)))
(add-to-list 'org-export-filter-final-output-functions #'+org-export-remove-zero-width-space t)
(setq! org-html-style-plain org-html-style-default
org-html-htmlize-output-type 'css
org-html-doctype "html5"
org-html-html5-fancy t)
(after! ox-html
<<ox-html-conf>>
)
(define-minor-mode org-fancy-html-export-mode
"Toggle my fabulous org export tweaks. While this mode itself does a little bit,
the vast majority of the change in behaviour comes from switch statements in:
- `org-html-template-fancier'
- `org-html--build-meta-info-extended'
- `org-html-src-block-collapsable'
- `org-html-block-collapsable'
- `org-html-table-wrapped'
- `org-html--format-toc-headline-colapseable'
- `org-html--toc-text-stripped-leaves'
- `org-export-html-headline-anchor'"
:global t
:init-value t
(if org-fancy-html-export-mode
(setq org-html-style-default org-html-style-fancy
org-html-meta-tags #'org-html-meta-tags-fancy
org-html-checkbox-type 'html-span)
(setq org-html-style-default org-html-style-plain
org-html-meta-tags #'org-html-meta-tags-default
org-html-checkbox-type 'html)))
在主体的开头添加更多信息,在页眉中添加日期和作者,实现仅 CSS 的亮/暗主题切换,以及一些 Open Graph 元数据。
(defadvice! org-html-template-fancier (orig-fn contents info)
"Return complete document string after HTML conversion.
CONTENTS is the transcoded contents string. INFO is a plist
holding export options. Adds a few extra things to the body
compared to the default implementation."
:around #'org-html-template
(if (or (not org-fancy-html-export-mode) (bound-and-true-p org-msg-export-in-progress))
(funcall orig-fn contents info)
(concat
(when (and (not (org-html-html5-p info)) (org-html-xhtml-p info))
(let* ((xml-declaration (plist-get info :html-xml-declaration))
(decl (or (and (stringp xml-declaration) xml-declaration)
(cdr (assoc (plist-get info :html-extension)
xml-declaration))
(cdr (assoc "html" xml-declaration))
"")))
(when (not (or (not decl) (string= "" decl)))
(format "%s\n"
(format decl
(or (and org-html-coding-system
(fboundp 'coding-system-get)
(coding-system-get org-html-coding-system 'mime-charset))
"iso-8859-1"))))))
(org-html-doctype info)
"\n"
(concat "<html"
(cond ((org-html-xhtml-p info)
(format
" xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"%s\" xml:lang=\"%s\""
(plist-get info :language) (plist-get info :language)))
((org-html-html5-p info)
(format " lang=\"%s\"" (plist-get info :language))))
">\n")
"<head>\n"
(org-html--build-meta-info info)
(org-html--build-head info)
(org-html--build-mathjax-config info)
"</head>\n"
"<body>\n<input type='checkbox' id='theme-switch'><div id='page'><label id='switch-label' for='theme-switch'></label>"
(let ((link-up (org-trim (plist-get info :html-link-up)))
(link-home (org-trim (plist-get info :html-link-home))))
(unless (and (string= link-up "") (string= link-home ""))
(format (plist-get info :html-home/up-format)
(or link-up link-home)
(or link-home link-up))))
;; Preamble.
(org-html--build-pre/postamble 'preamble info)
;; Document contents.
(let ((div (assq 'content (plist-get info :html-divs))))
(format "<%s id=\"%s\">\n" (nth 1 div) (nth 2 div)))
;; Document title.
(when (plist-get info :with-title)
(let ((title (and (plist-get info :with-title)
(plist-get info :title)))
(subtitle (plist-get info :subtitle))
(html5-fancy (org-html--html5-fancy-p info)))
(when title
(format
(if html5-fancy
"<header class=\"page-header\">%s\n<h1 class=\"title\">%s</h1>\n%s</header>"
"<h1 class=\"title\">%s%s</h1>\n")
(if (or (plist-get info :with-date)
(plist-get info :with-author))
(concat "<div class=\"page-meta\">"
(when (plist-get info :with-date)
(org-export-data (plist-get info :date) info))
(when (and (plist-get info :with-date) (plist-get info :with-author)) ", ")
(when (plist-get info :with-author)
(org-export-data (plist-get info :author) info))
"</div>\n")
"")
(org-export-data title info)
(if subtitle
(format
(if html5-fancy
"<p class=\"subtitle\" role=\"doc-subtitle\">%s</p>\n"
(concat "\n" (org-html-close-tag "br" nil info) "\n"
"<span class=\"subtitle\">%s</span>\n"))
(org-export-data subtitle info))
"")))))
contents
(format "</%s>\n" (nth 1 (assq 'content (plist-get info :html-divs))))
;; Postamble.
(org-html--build-pre/postamble 'postamble info)
;; Possibly use the Klipse library live code blocks.
(when (plist-get info :html-klipsify-src)
(concat "<script>" (plist-get info :html-klipse-selection-script)
"</script><script src=\""
org-html-klipse-js
"\"></script><link rel=\"stylesheet\" type=\"text/css\" href=\""
org-html-klipse-css "\"/>"))
;; Closing document.
"</div>\n</body>\n</html>")))
lepisma.xyz 所做的导出风格非常讨喜。
<link rel="icon" href="https://tecosaur.com/resources/org/nib.ico" type="image/ico" />
<link rel="preload" as="font" crossorigin="anonymous" type="font/woff2" href="https://tecosaur.com/resources/org/etbookot-roman-webfont.woff2">
<link rel="preload" as="font" crossorigin="anonymous" type="font/woff2" href="https://tecosaur.com/resources/org/etbookot-italic-webfont.woff2">
<link rel="preload" as="font" crossorigin="anonymous" type="font/woff2" href="https://tecosaur.com/resources/org/Merriweather-TextRegular.woff2">
<link rel="preload" as="font" crossorigin="anonymous" type="font/woff2" href="https://tecosaur.com/resources/org/Merriweather-TextItalic.woff2">
<link rel="preload" as="font" crossorigin="anonymous" type="font/woff2" href="https://tecosaur.com/resources/org/Merriweather-TextBold.woff2">
(defun org-html-reload-fancy-style ()
(interactive)
(setq org-html-style-fancy
(with-temp-buffer
(insert-file-contents (expand-file-name "misc/org-export-header.html" doom-user-dir))
(goto-char (point-max))
(insert "<script>\n")
(insert-file-contents (expand-file-name "misc/org-css/main.js" doom-user-dir))
(goto-char (point-max))
(insert "</script>\n<style>\n")
(insert-file-contents (expand-file-name "misc/org-css/main.min.css" doom-user-dir))
(goto-char (point-max))
(insert "</style>")
(buffer-string)))
(when org-fancy-html-export-mode
(setq org-html-style-default org-html-style-fancy)))
(org-html-reload-fancy-style)
通过将 <pre>
元素包装在 <details>
块中,我们可以得到没有 CSS 的可折叠块,
尽管我们会稍微折腾一下,让这看起来有点漂亮。
由于默认情况下对某些代码块启用可折叠性似乎很有用,因此如果您可以使用
#+attr_html: :collapsed t
设置它会更好。
如果有一个相应的全局/会话本地方式来设置它会很好,但我还没能让它正常工作。
(defvar org-html-export-collapsed nil)
(eval '(cl-pushnew '(:collapsed "COLLAPSED" "collapsed" org-html-export-collapsed t)
(org-export-backend-options (org-export-get-backend 'html))))
(add-to-list 'org-default-properties "EXPORT_COLLAPSED")
我们可以进一步修改 src 块,并在 src 块的一侧添加一个块,其中包含引用当前块的锚点和 复制块内容的按钮。
(defadvice! org-html-src-block-collapsable (orig-fn src-block contents info)
"Wrap the usual <pre> block in a <details>"
:around #'org-html-src-block
(if (or (not org-fancy-html-export-mode) (bound-and-true-p org-msg-export-in-progress))
(funcall orig-fn src-block contents info)
(let* ((properties (cadr src-block))
(lang (mode-name-to-lang-name
(plist-get properties :language)))
(name (plist-get properties :name))
(ref (org-export-get-reference src-block info))
(collapsed-p (member (or (org-export-read-attribute :attr_html src-block :collapsed)
(plist-get info :collapsed))
'("y" "yes" "t" t "true" "all"))))
(format
"<details id='%s' class='code'%s><summary%s>%s</summary>
<div class='gutter'>
<a href='#%s'>#</a>
<button title='Copy to clipboard' onclick='copyPreToClipbord(this)'>⎘</button>\
</div>
%s
</details>"
ref
(if collapsed-p "" " open")
(if name " class='named'" "")
(concat
(when name (concat "<span class=\"name\">" name "</span>"))
"<span class=\"lang\">" lang "</span>")
ref
(if name
(replace-regexp-in-string (format "<pre\\( class=\"[^\"]+\"\\)? id=\"%s\">" ref) "<pre\\1>"
(funcall orig-fn src-block contents info))
(funcall orig-fn src-block contents info))))))
(defun mode-name-to-lang-name (mode)
(or (cadr (assoc mode
'(("asymptote" "Asymptote")
("awk" "Awk")
("C" "C")
("clojure" "Clojure")
("css" "CSS")
("D" "D")
("ditaa" "ditaa")
("dot" "Graphviz")
("calc" "Emacs Calc")
("emacs-lisp" "Emacs Lisp")
("fortran" "Fortran")
("gnuplot" "gnuplot")
("haskell" "Haskell")
("hledger" "hledger")
("java" "Java")
("js" "Javascript")
("latex" "LaTeX")
("ledger" "Ledger")
("lisp" "Lisp")
("lilypond" "Lilypond")
("lua" "Lua")
("matlab" "MATLAB")
("mscgen" "Mscgen")
("ocaml" "Objective Caml")
("octave" "Octave")
("org" "Org mode")
("oz" "OZ")
("plantuml" "Plantuml")
("processing" "Processing.js")
("python" "Python")
("R" "R")
("ruby" "Ruby")
("sass" "Sass")
("scheme" "Scheme")
("screen" "Gnu Screen")
("sed" "Sed")
("sh" "shell")
("sql" "SQL")
("sqlite" "SQLite")
("forth" "Forth")
("io" "IO")
("J" "J")
("makefile" "Makefile")
("maxima" "Maxima")
("perl" "Perl")
("picolisp" "Pico Lisp")
("scala" "Scala")
("shell" "Shell Script")
("ebnf2ps" "ebfn2ps")
("cpp" "C++")
("abc" "ABC")
("coq" "Coq")
("groovy" "Groovy")
("bash" "bash")
("csh" "csh")
("ash" "ash")
("dash" "dash")
("ksh" "ksh")
("mksh" "mksh")
("posh" "posh")
("ada" "Ada")
("asm" "Assembler")
("caml" "Caml")
("delphi" "Delphi")
("html" "HTML")
("idl" "IDL")
("mercury" "Mercury")
("metapost" "MetaPost")
("modula-2" "Modula-2")
("pascal" "Pascal")
("ps" "PostScript")
("prolog" "Prolog")
("simula" "Simula")
("tcl" "tcl")
("tex" "LaTeX")
("plain-tex" "TeX")
("verilog" "Verilog")
("vhdl" "VHDL")
("xml" "XML")
("nxml" "XML")
("conf" "Configuration File"))))
mode))
(defun org-html-block-collapsable (orig-fn block contents info)
"Wrap the usual block in a <details>"
(if (or (not org-fancy-html-export-mode) (bound-and-true-p org-msg-export-in-progress))
(funcall orig-fn block contents info)
(let ((ref (org-export-get-reference block info))
(type (pcase (car block)
('property-drawer "Properties")))
(collapsed-default (pcase (car block)
('property-drawer t)
(_ nil)))
(collapsed-value (org-export-read-attribute :attr_html block :collapsed))
(collapsed-p (or (member (org-export-read-attribute :attr_html block :collapsed)
'("y" "yes" "t" t "true"))
(member (plist-get info :collapsed) '("all")))))
(format
"<details id='%s' class='code'%s>
<summary%s>%s</summary>
<div class='gutter'>\
<a href='#%s'>#</a>
<button title='Copy to clipboard' onclick='copyPreToClipbord(this)'>⎘</button>\
</div>
%s\n
</details>"
ref
(if (or collapsed-p collapsed-default) "" " open")
(if type " class='named'" "")
(if type (format "<span class='type'>%s</span>" type) "")
ref
(funcall orig-fn block contents info)))))
(advice-add 'org-html-example-block :around #'org-html-block-collapsable)
(advice-add 'org-html-fixed-width :around #'org-html-block-collapsable)
(advice-add 'org-html-property-drawer :around #'org-html-block-collapsable)
Org 使用 htmlize.el 导出带有语法高亮的缓冲区。
在大多数情况下这些格式非常棒。不需要加载提供字体锁定的次要模式,因此不会影响结果。
通过在 htmlize-before-hook
中启用这些模式,我们可以纠正这种行为。
(require 'htmlize)
(add-hook! htmlize-before #'highlight-numbers--turn-on)
为了适应宽表 — 尤其是在移动设备上 — 我们想要设置最大宽度和滚动溢出。不幸的是,
这不能直接应用于 表格
元素,所以我们必须将它包装在一个 div
中。
当我们这样做时,我们可以像我们对 src 块所做的那样,设置一个链接块,并显示
#+name
(如果有的话)。
(defadvice! org-html-table-wrapped (orig-fn table contents info)
"Wrap the usual <table> in a <div>"
:around #'org-html-table
(if (or (not org-fancy-html-export-mode) (bound-and-true-p org-msg-export-in-progress))
(funcall orig-fn table contents info)
(let* ((name (plist-get (cadr table) :name))
(ref (org-export-get-reference table info)))
(format "<div id='%s' class='table'>
<div class='gutter'><a href='#%s'>#</a></div>
<div class='tabular'>
%s
</div>\
</div>"
ref ref
(if name
(replace-regexp-in-string (format "<table id=\"%s\"" ref) "<table"
(funcall orig-fn table contents info))
(funcall orig-fn table contents info))))))
TOC 作为可折叠树更易于导航。不幸的是,我们不能单独使用 CSS 来实现这一点。值得庆幸
的是,我们可以通过调整 TOC 生成代码来为每个项目使用一个 标签
,以及一个隐藏的
复选框
来跟踪状态,从而避免使用 JS。
要添加它,我们需要在 org-html--format-toc-headline
中更改一行。
因为我们实际上可以通过在函数周围添加建议来实现所需的效果,而无需覆盖它 — 让我们这 样做来减少这个配置的错误表面。
(defadvice! org-html--format-toc-headline-colapseable (orig-fn headline info)
"Add a label and checkbox to `org-html--format-toc-headline's usual output,
to allow the TOC to be a collapseable tree."
:around #'org-html--format-toc-headline
(if (or (not org-fancy-html-export-mode) (bound-and-true-p org-msg-export-in-progress))
(funcall orig-fn headline info)
(let ((id (or (org-element-property :CUSTOM_ID headline)
(org-export-get-reference headline info))))
(format "<input type='checkbox' id='toc--%s'/><label for='toc--%s'>%s</label>"
id id (funcall orig-fn headline info)))))
现在,叶子 (没有子标题的标题) 不应该有 标签项
。实现这一点的明显方法是在
org-html--format-toc-headline-colapseable
中包含一些 (如果没有子项) 逻辑
。不幸的是,我的 elisp 无法从 org 提供的大量信息中提取子标题的数量。
(defadvice! org-html--toc-text-stripped-leaves (orig-fn toc-entries)
"Remove label"
:around #'org-html--toc-text
(if (or (not org-fancy-html-export-mode) (bound-and-true-p org-msg-export-in-progress))
(funcall orig-fn toc-entries)
(replace-regexp-in-string "<input [^>]+><label [^>]+>\\(.+?\\)</label></li>" "\\1</li>"
(funcall orig-fn toc-entries))))
让我们为 varbatim
和 code
添加一些差异。
我们可以将 code
专门用于代码片段和命令,例如:在 Emacs 的批处理模式中调用
src_elisp{(message “Hello”)} 会像 echo
一样打印到标准输出。 可以对
verbatim
使用各种 ‘其他等宽’,例如键盘快捷键: C-c C-c
或 C-g
可能是
Emacs 中最有用的快捷键,或文件名:我将我的配置保存在 ~/.config/doom/
中,其他
情况则使用正常样式。
(setq org-html-text-markup-alist
'((bold . "<b>%s</b>")
(code . "<code>%s</code>")
(italic . "<i>%s</i>")
(strike-through . "<del>%s</del>")
(underline . "<span class=\"underline\">%s</span>")
(verbatim . "<kbd>%s</kbd>")))
我们也想使用 HTML 复选框,但是我们想比默认的更漂亮
(appendq! org-html-checkbox-types
'((html-span
(on . "<span class='checkbox'></span>")
(off . "<span class='checkbox'></span>")
(trans . "<span class='checkbox'></span>"))))
(setq! org-html-checkbox-type 'html-span)
- [ ] I’m yet to do this
- [-] Work in progress
- [X] This is done
org-html-special-string-regexps
变量定义了以下内容的替换:
\-
, shy 连字符---
, 增强的破折号--
, 破折号...
, (水平的) 省略号
但我认为如果还可以替换左/右箭头 (->
和 <-
) 那就更好了。 这是一个
defconst
,但正如你可以从这个配置中的大量建议中看出的那样,我并没有放弃我不 ‘应
该’ 做的事情。
唯一的小麻烦是在这个阶段的输出处理之前 <
和 >
被转换为 <
和 =>=。
(pushnew! org-html-special-string-regexps
'("->" . "→")
'("<-" . "←"))
一个 GitHub 风格的标题链接
(defun org-export-html-headline-anchor (text backend info)
(when (and (org-export-derived-backend-p backend 'html)
(not (org-export-derived-backend-p backend 're-reveal))
org-fancy-html-export-mode)
(unless (bound-and-true-p org-msg-export-in-progress)
(replace-regexp-in-string
"<h\\([0-9]\\) id=\"\\([a-z0-9-]+\\)\">\\(.*[^ ]\\)<\\/h[0-9]>" ; this is quite restrictive, but due to `org-reference-contraction' I can do this
"<h\\1 id=\"\\2\">\\3<a aria-hidden=\"true\" href=\"#\\2\">#</a> </h\\1>"
text))))
(add-to-list 'org-export-filter-headline-functions
'org-export-html-headline-anchor)
如果使用 MathJax,就用 3 而不是 2。通过对比我们发现它似乎快了 5 倍,而且它使用单
个文件而不是多个文件,就是有点大而已。值得庆幸的是,这可以通过添加 async
属性
来延迟加载来缓解。
\(D(N) = D(i) + D(N - i - 1) + \frac{1}{N}.\)
\[D(N) = \frac{2}{N}[∑j=0N-1{D(j)}] + N - 1.\]
(setcdr (assoc 'path org-html-mathjax-options)
(list "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"))
(setq! org-html-mathjax-template
"<script>
window.MathJax = {
loader: {
load: ['[tex]/ams', '[tex]/upgreek', '[tex]/mathtools'],
},
tex: {
ams: {
multlineWidth: '%MULTLINEWIDTH'
},
tags: '%TAGS',
tagSide: '%TAGSIDE',
tagIndent: '%TAGINDENT',
packages: {'[+]': ['ams', 'upgreek', 'mathtools']},
mathtools: {
pairedDelimiters: {
abs: ['\\\\lvert', '\\\\rvert'],
norm: ['\\\\lVert', '\\\\rVert'],
ceil: ['\\\\lceil', '\\\\rceil'],
floor: ['\\\\lfloor', '\\\\rfloor'],
round: ['\\\\lfloor', '\\\\rceil'],
}
}
},
chtml: {
scale: %SCALE,
displayAlign: '%ALIGN',
displayIndent: '%INDENT'
},
svg: {
scale: %SCALE,
displayAlign: '%ALIGN',
displayIndent: '%INDENT'
},
output: {
font: '%FONT',
displayOverflow: '%OVERFLOW'
}
};
</script>
<script id=\"MathJax-script\" async
src=\"%PATH\"></script>")
(defvar org-latex-maths-preamble
"
<<latex-maths-conveniences>>
"
"Preamble that sets up a bunch of mathematical conveniences.")
(defvar org-latex-caption-preamble
"
<<org-latex-caption-preamble>>
"
"Preamble that improves captions.")
(defvar org-latex-checkbox-preamble
"
<<org-latex-checkbox-preamble>>
"
"Preamble that improves checkboxes.")
(defvar org-latex-box-preamble
"
<<org-latex-box-preamble>>
"
"Preamble that provides a macro for custom boxes.")
(defvar org-latex-use-microtype nil
"Use the microtype pakage.")
(defvar org-latex-italic-quotes t
"Make \"quote\" environments italic.")
(defvar org-latex-par-sep t
"Vertically seperate paragraphs, and remove indentation.")
(defvar org-export-latex--preamble-info nil)
(defvar org-latex-conditional-features nil
"Org feature tests and associated LaTeX feature flags.
Alist where the car is a test for the presense of the feature,
and the cdr is either a single feature symbol or list of feature symbols.
When a string, it is used as a regex search in the buffer.
The feature is registered as present when there is a match.
The car can also be a
- symbol, the value of which is fetched
- function, which is called with info as an argument
- list, which is `eval'uated
If the symbol, function, or list produces a string: that is used as a regex
search in the buffer. Otherwise any non-nil return value will indicate the
existance of the feature.")
(defvar org-latex-feature-implementations nil
"LaTeX features and details required to implement them.
List where the car is the feature symbol, and the rest forms a plist with the
following keys:
- :snippet, which may be either
- a string which should be included in the preamble
- a symbol, the value of which is included in the preamble
- a function, which is evaluated with the list of feature flags as its
single argument. The result of which is included in the preamble
- a list, which is passed to `eval', with a list of feature flags available
as \"features\"
- :requires, a feature or list of features that must be available
- :when, a feature or list of features that when all available should cause this
to be automatically enabled.
- :prevents, a feature or list of features that should be masked
- :order, for when ordering is important. Lower values appear first.
The default is 0.
- :eager, when non-nil the feature will be eagerly loaded, i.e. without being detected.")
(after! ox-latex
<<ox-latex-conf>>
)
默认情况下,Org 使用 pdflatex
× 3 + bibtex=。 这在现代世界根本行不通。
=latexmk
+ biber
(自动与 latexmk
一起使用) 是一个简单且优越组合。
;; org-latex-compilers = ("pdflatex" "xelatex" "lualatex"), which are the possible values for %latex
(setq! org-latex-pdf-process '("LC_ALL=en_US.UTF-8 latexmk -f -pdf -%latex --shell-escape --interaction=nonstopmode --output-directory=%o %f")
org-latex-logfiles-extensions (append org-latex-logfiles-extensions
'("acn" "acr" "alg" "bbl" "blg" "glg" "ist" "listing" "fdb_latexmk") nil))
虽然上面的 -%latex
有点 hacky (-pdflatex
期望被赋予一个值),但它允许我们保持
org-latex-compilers
不变。如果我打开一个使用 #+LATEX_COMPILER
的 org 文件,
这很好,它应该仍然可以工作。
我们可以假设在序言部分,定义了下面的各种自定义 \checkbox...
命令。
(defun +org-export-latex-fancy-item-checkboxes (text backend info)
(when (org-export-derived-backend-p backend 'latex)
(replace-regexp-in-string
"\\\\item\\[{$\\\\\\(\\w+\\)$}\\]"
(lambda (fullmatch)
(concat "\\\\item[" (pcase (substring fullmatch 9 -3) ; content of capture group
("square" "\\\\checkboxUnchecked")
("boxminus" "\\\\checkboxTransitive")
("boxtimes" "\\\\checkboxChecked")
(_ (substring fullmatch 9 -3))) "]"))
text)))
(add-to-list 'org-export-filter-item-functions
'+org-export-latex-fancy-item-checkboxes)
页边空白处的节号,这可以用下面的 LaTeX 来完成。
\\renewcommand\\sectionformat{\\llap{\\thesection\\autodot\\enskip}}
\\renewcommand\\subsectionformat{\\llap{\\thesubsection\\autodot\\enskip}}
\\renewcommand\\subsubsectionformat{\\llap{\\thesubsubsection\\autodot\\enskip}}
\\makeatletter
\\g@addto@macro\\tableofcontents{\\clearpage\\setcounter{page}{1}\\pagenumbering{arabic}}
\\makeatother
\\setcounter{page}{1}
\\pagenumbering{Roman}
超大的 ~\chapter~。
\\RedeclareSectionCommand[afterindent=false, beforeskip=0pt, afterskip=0pt, innerskip=0pt]{chapter}
\\setkomafont{chapter}{\\normalfont\\Huge}
\\renewcommand*{\\chapterheadstartvskip}{\\vspace*{0\\baselineskip}}
\\renewcommand*{\\chapterheadendvskip}{\\vspace*{0\\baselineskip}}
\\renewcommand*{\\chapterformat}{%
\\fontsize{60}{30}\\selectfont\\rlap{\\hspace{6pt}\\thechapter}}
\\renewcommand*\\chapterlinesformat[3]{%
\\parbox[b]{\\dimexpr\\textwidth-0.5em\\relax}{%
\\raggedleft{{\\large\\scshape\\bfseries\\chapapp}\\vspace{-0.5ex}\\par\\Huge#3}}%
\\hfill\\makebox[0pt][l]{#2}}
现在在 Org LaTeX 类中添加一些 =KOMA-Script=。
(let* ((article-sections '(("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
(book-sections (append '(("\\chapter{%s}" . "\\chapter*{%s}"))
article-sections))
(hanging-secnum-preamble "
<<latex-hanging-secnum>>
")
(big-chap-preamble "
<<latex-big-chapter>>
"))
(setcdr (assoc "article" org-latex-classes)
`(,(concat "\\documentclass{scrartcl}" hanging-secnum-preamble)
,@article-sections))
(add-to-list 'org-latex-classes
`("report" ,(concat "\\documentclass{scrartcl}" hanging-secnum-preamble)
,@article-sections))
(add-to-list 'org-latex-classes
`("book" ,(concat "\\documentclass[twoside=false]{scrbook}"
big-chap-preamble hanging-secnum-preamble)
,@book-sections))
(add-to-list 'org-latex-classes
`("blank" "[NO-DEFAULT-PACKAGES]\n[NO-PACKAGES]\n[EXTRA]"
,@article-sections))
(add-to-list 'org-latex-classes
`("bmc-article" "\\documentclass[article,code,maths]{bmc}\n[NO-DEFAULT-PACKAGES]\n[NO-PACKAGES]\n[EXTRA]"
,@article-sections))
(add-to-list 'org-latex-classes
`("bmc" "\\documentclass[code,maths]{bmc}\n[NO-DEFAULT-PACKAGES]\n[NO-PACKAGES]\n[EXTRA]"
,@book-sections)))
(setq! org-latex-tables-booktabs t
org-latex-hyperref-template "
<<latex-fancy-hyperref>>
"
org-latex-reference-command "\\cref{%s}")
然而 hyperref
设置需要单独处理。
\\providecolor{url}{HTML}{0077bb}
\\providecolor{link}{HTML}{882255}
\\providecolor{cite}{HTML}{999933}
\\hypersetup{
pdfauthor={%a},
pdftitle={%t},
pdfkeywords={%k},
pdfsubject={%d},
pdfcreator={%c},
pdflang={%L},
breaklinks=true,
colorlinks=true,
linkcolor=link,
urlcolor=url,
citecolor=cite
}
\\urlstyle{same}
%% hide links styles in toc
\\NewCommandCopy{\\oldtoc}{\\tableofcontents}
\\renewcommand{\\tableofcontents}{\\begingroup\\hypersetup{hidelinks}\\oldtoc\\endgroup}
Caption 可以做一些调整,比如
- 可以轻松拥有多个 Caption
- 指向图的链接带到图的顶部 (而不是底部)
- Caption 标签可以稍微加粗一点
- 只有当跨越多行时,多行 Caption 应该向右一点
\\usepackage{subcaption}
\\usepackage[hypcap=true]{caption}
\\setkomafont{caption}{\\sffamily\\small}
\\setkomafont{captionlabel}{\\upshape\\bfseries}
\\captionsetup{justification=raggedright,singlelinecheck=true}
\\usepackage{capt-of} % required by Org
默认的复选框太丑了,用一些好看的替代品吧。
\\newcommand{\\checkboxUnchecked}{$\\square$}
\\newcommand{\\checkboxTransitive}{\\rlap{\\raisebox{-0.1ex}{\\hspace{0.35ex}\\Large\\textbf -}}$\\square$}
\\newcommand{\\checkboxChecked}{\\rlap{\\raisebox{0.2ex}{\\hspace{0.35ex}\\scriptsize \\ding{52}}}$\\square$}
“消息块” 是一个不错的想法,就像 info/warning/error/success。LaTeX 中的宏可 以创建它们。
\\ExplSyntaxOn
\\NewCoffin\\Content
\\NewCoffin\\SideRule
\\NewDocumentCommand{\\defsimplebox}{O{\\ding{117}} O{0.36em} m m m}{%
% #1 ding, #2 ding offset, #3 name, #4 colour, #5 default label
\\definecolor{#3}{HTML}{#4}
\\NewDocumentEnvironment{#3}{ O{#5} }
{
\\vcoffin_set:Nnw \\Content { \\linewidth }
\\noindent \\ignorespaces
\\par\\vspace{-0.7\\baselineskip}%
\\textcolor{#3}{#1}~\\textcolor{#3}{\\textbf{##1}}%
\\vspace{-0.8\\baselineskip}
\\begin{addmargin}[1em]{1em}
}
{
\\end{addmargin}
\\vspace{-0.5\\baselineskip}
\\vcoffin_set_end:
\\SetHorizontalCoffin\\SideRule{\\color{#3}\\rule{1pt}{\\CoffinTotalHeight\\Content}}
\\JoinCoffins*\\Content[l,t]\\SideRule[l,t](#2,-0.7em)
\\noindent\\TypesetCoffin\\Content
\\vspace*{\\CoffinTotalHeight\\Content}\\bigskip
\\vspace{-2\\baselineskip}
}
}
\\ExplSyntaxOff
每个检测到的特征都会给出一个所需的「特征标志」列表。只需合并功能标志列表,不再需 要避免 LaTeX 的重复。然后额外的层在特征标志和可用于实现该特征的规范之间形成双射。
首先,我们将实现该模型的特征检测组件。我希望它能够使用尽可能多的状态信息,因此功 能测试应该非常通用。
(setq! org-latex-conditional-features
'(("\\[\\[\\(?:file\\|https?\\):\\(?:[^]]\\|\\\\\\]\\)+?\\.\\(?:eps\\|pdf\\|png\\|jpeg\\|jpg\\|jbig2\\)\\]\\]\\|\\\\includegraphics[\\[{]" . image)
("\\[\\[\\(?:file\\|https?\\):\\(?:[^]]+?\\|\\\\\\]\\)\\.svg\\]\\]\\|\\\\includesvg[\\[{]" . svg)
("\\\\(\\|\\\\\\[\\|\\\\begin{\\(?:math\\|displaymath\\|equation\\|align\\|flalign\\|multiline\\|gather\\)[a-z]*\\*?}" . maths)
("^[ \t]*|" . table)
("cref:\\|\\cref{" . cleveref)
("[;\\\\]?\\b[A-Z][A-Z]+s?[^A-Za-z]" . acronym)
("\\+[^ ].*[^ ]\\+\\|_[^ ].*[^ ]_\\|\\\\uu?line\\|\\\\uwave\\|\\\\sout\\|\\\\xout\\|\\\\dashuline\\|\\dotuline\\|\\markoverwith" . underline)
(":float wrap" . float-wrap)
(":float sideways" . rotate)
(org-latex-use-microtype . microtype)
("[\u2500-\u259F]" . box-drawing)
("^[ \t]*#\\+caption:\\|\\\\caption" . caption)
((and org-latex-italic-quotes "^[ \t]*#\\+begin_quote\\|\\\\begin{quote}") . italic-quotes)
(org-latex-par-sep . par-sep)
("^[ \t]*\\(?:[-+*]\\|[0-9]+[.)]\\|[A-Za-z]+[.)]\\) \\[[ -X]\\]" . checkbox)
("^[ \t]*#\\+begin_warning\\|\\\\begin{warning}" . box-warning)
("^[ \t]*#\\+begin_info\\|\\\\begin{info}" . box-info)
("^[ \t]*#\\+begin_notes\\|\\\\begin{notes}" . box-notes)
("^[ \t]*#\\+begin_success\\|\\\\begin{success}" . box-success)
("^[ \t]*#\\+begin_error\\|\\\\begin{error}" . box-error)))
然后我们提供一种方法来生成提供这些功能的序言。除了
org-latex-conditional-features
中命名的特性之外,我们还将创建元特性,这些
特性可能是其他特性所需要的 (:requires
),或者默认情况下是启用的
(:eager t
)。为了进一步控制,我只能在某些其他功能处于启用状态 (:when
) 并被
其他功能屏蔽 (:prevents
) 时使用某些功能。我将使用以 .
开头的元功能的约定
,以及以 !
开头的 :eager
功能,使它们的性质更明显。
LaTeX 中的另一个考虑因素是加载顺序,这在某些情况下很重要。除此之外,有某种合理的
排序是很好的。为此我将介绍一个 :order
关键字。使用它将按如下方式排列片段。
0
排版0
字体本身
0.2
数学设置0.3
数学字体0.4
额外的文字整形 (\acr
)0.5-0.9
其他文本修改,尝试将较短的片段放在首位
1
(default)2
表和图3
其他短内容4
各种 boxes
(setq! org-latex-feature-implementations
'((image :snippet "\\usepackage{graphicx}" :order 2)
(svg :snippet "\\usepackage[inkscapelatex=false]{svg}" :order 2)
(maths :snippet org-latex-maths-preamble :order 0.2)
(table :snippet "\\usepackage{longtable}\n\\usepackage{booktabs}" :order 2)
(cleveref :snippet "\\usepackage{biber}\n\\usepackage[capitalize]{cleveref}"
:order 1) ; after bmc-maths
(underline :snippet "\\usepackage[normalem]{ulem}" :order 0.5)
(float-wrap :snippet "\\usepackage{wrapfig}" :order 2)
(rotate :snippet "\\usepackage{rotating}" :order 2)
(caption :snippet org-latex-caption-preamble :order 2.1)
(microtype :snippet "\\usepackage[activate={true,nocompatibility},final,tracking=true,kerning=true,spacing=true,factor=2000]{microtype}"
:order 0.1)
(acronym :snippet "\\newcommand{\\acr}[1]{\\protect\\textls*[110]{\\scshape #1}}\n\\newcommand{\\acrs}{\\protect\\scalebox{.91}[.84]{\\hspace{0.15ex}s}}"
:order 0.4)
(box-drawing :snippet "\\usepackage{pmboxdraw}" :order 0.05)
(italic-quotes :snippet "\\renewcommand{\\quote}{\\list{}{\\rightmargin\\leftmargin}\\item\\relax\\em}\n"
:order 0.5)
(par-sep :snippet "\\setlength{\\parskip}{\\baselineskip}\n\\setlength{\\parindent}{0pt}"
:order 0.5)
(.pifont :snippet "\\usepackage{pifont}")
(.xcoffins :snippet "\\usepackage{xcoffins}")
(checkbox :requires .pifont
:order 3
:snippet (concat (unless (memq 'maths features)
"\\usepackage{amssymb} % provides \\square")
org-latex-checkbox-preamble))
(.fancy-box :requires (.pifont .xcoffins) :snippet org-latex-box-preamble :order 3.9)
(box-warning :requires .fancy-box
:snippet "\\defsimplebox{warning}{e66100}{Warning}"
:order 4)
(box-info :requires .fancy-box
:snippet "\\defsimplebox{info}{3584e4}{Information}"
:order 4)
(box-notes :requires .fancy-box
:snippet "\\defsimplebox{notes}{26a269}{Notes}"
:order 4)
(box-success :requires .fancy-box
:snippet "\\defsimplebox{success}{26a269}{\\vspace{-\\baselineskip}}"
:order 4)
(box-error :requires .fancy-box
:snippet "\\defsimplebox{error}{c01c28}{Important}"
:order 4)))
(setq! org-latex-packages-alist
'(("svgnames" "xcolor" t)
("" "tikz" t)))
现在我们已经定义了 org-latex-conditional-features
,我们需要使用它来提取
在 Org 缓冲区中找到的特征列表。
(defun org-latex-detect-features (&optional buffer info)
"List features from `org-latex-conditional-features' detected in BUFFER."
(let ((case-fold-search nil))
(with-current-buffer (or buffer (current-buffer))
(delete-dups
(mapcan (lambda (construct-feature)
(when (let ((out (pcase (car construct-feature)
((pred stringp) (car construct-feature))
((pred functionp) (funcall (car construct-feature) info))
((pred listp) (eval (car construct-feature)))
((pred symbolp) (symbol-value (car construct-feature)))
(_ (user-error "org-latex-conditional-features key %s unable to be used" (car construct-feature))))))
(if (stringp out)
(save-excursion
(goto-char (point-min))
(re-search-forward out nil t))
out))
(if (listp (cdr construct-feature)) (cdr construct-feature) (list (cdr construct-feature)))))
org-latex-conditional-features)))))
一旦确定了所需功能的列表,我们希望使用 org-latex-feature-implementations
来生成 LaTeX,该 LaTeX 应该插入到序言中以提供这些功能。
首先,我们要在 org-latex-feature-implementations
中处理我们的关键字,以
生成扩展的功能列表。我们将通过执行以下步骤来做到这一点。
- 每个列出的功能的依赖项都添加到功能列表 (src_elisp{:requires}) 中。
- 每个特性的 src_elisp{:when} 条件,以及带有 src_elisp{:eager t} 的可用特 性,都会被评估,并相应地添加 / 删除
- src_elisp{:prevents} 值中存在的任何特性都将被删除
- 功能列表清除重复项
- 特征列表按 src_elisp{:order} (升序) 排序
(defun org-latex-expand-features (features)
"For each feature in FEATURES process :requires, :when, and :prevents keywords and sort according to :order."
(dolist (feature features)
(unless (assoc feature org-latex-feature-implementations)
(message "Feature %s not provided in org-latex-feature-implementations, ignoring." feature)
(setq features (remove feature features))))
(setq current features)
(while current
(when-let ((requirements (plist-get (cdr (assq (car current) org-latex-feature-implementations)) :requires)))
(setcdr current (if (listp requirements)
(append requirements (cdr current))
(cons requirements (cdr current)))))
(setq current (cdr current)))
(dolist (potential-feature
(append features (delq nil (mapcar (lambda (feat)
(when (plist-get (cdr feat) :eager)
(car feat)))
org-latex-feature-implementations))))
(when-let ((prerequisites (plist-get (cdr (assoc potential-feature org-latex-feature-implementations)) :when)))
(setf features (if (if (listp prerequisites)
(cl-every (lambda (preq) (memq preq features)) prerequisites)
(memq prerequisites features))
(append (list potential-feature) features)
(delq potential-feature features)))))
(dolist (feature features)
(when-let ((prevents (plist-get (cdr (assoc feature org-latex-feature-implementations)) :prevents)))
(setf features (cl-set-difference features (if (listp prevents) prevents (list prevents))))))
(sort (delete-dups features)
(lambda (feat1 feat2)
(if (< (or (plist-get (cdr (assoc feat1 org-latex-feature-implementations)) :order) 1)
(or (plist-get (cdr (assoc feat2 org-latex-feature-implementations)) :order) 1))
t nil))))
现在我们有一个很好的最终要使用的特性列表,可以提取它们的片段并将结果连接在一起。
(defun org-latex-generate-features-preamble (features)
"Generate the LaTeX preamble content required to provide FEATURES.
This is done according to `org-latex-feature-implementations'"
(let ((expanded-features (org-latex-expand-features features)))
(concat
(format "\n%% features: %s\n" expanded-features)
(mapconcat (lambda (feature)
(when-let ((snippet (plist-get (cdr (assoc feature org-latex-feature-implementations)) :snippet)))
(concat
(pcase snippet
((pred stringp) snippet)
((pred functionp) (funcall snippet features))
((pred listp) (eval `(let ((features ',features)) (,@snippet))))
((pred symbolp) (symbol-value snippet))
(_ (user-error "org-latex-feature-implementations :snippet value %s unable to be used" snippet)))
"\n")))
expanded-features
"")
"% end features\n")))
然后需要建议 Org 实际使用这个生成的前导内容。
(defadvice! org-latex-save-info (info &optional t_ s_)
:before #'org-latex-make-preamble
(setq org-export-latex--preamble-info info))
(defadvice! org-splice-latex-header-and-generated-preamble-a (orig-fn tpl def-pkg pkg snippets-p &optional extra)
"Dynamically insert preamble content based on `org-latex-conditional-preambles'."
:around #'org-splice-latex-header
(let ((header (funcall orig-fn tpl def-pkg pkg snippets-p extra)))
(if snippets-p header
(concat header
(org-latex-generate-features-preamble (org-latex-detect-features nil org-export-latex--preamble-info))
"\n"))))
我对 org-export-latex--preamble-info
的使用有点老套。 当我尝试将其上游化时,这应
该会变得更加清晰,因为我可以通过直接修改 org-latex-make-preamble
来传递信息。
数学总是层出不穷。我想这既说明了我和这门学科本身。虽然 LaTeX 的命令集相当合理, 但我们可以让一些常用的符号更方便一些。
首先我们需要非常常用的包。
%% Maths-related packages
% More maths environments, commands, and symbols.
\\usepackage{amsmath, amssymb}
% Slanted fractions with \sfrac{a}{b}, in text and maths.
\\usepackage{xfrac}
% Visually cancel expressions with \cancel{value} and \cancelto{expression}{value}
\\usepackage[makeroom]{cancel}
% Improvements on amsmath and utilities for mathematical typesetting
\\usepackage{mathtools}
\\usepackage{upgreek,extarrows}
\\usepackage[math-style=ISO]{unicode-math}
接下来,我们要将各种类型的四舍五入和绝对值分隔符作为命令访问。
% Deliminators
\\DeclarePairedDelimiter{\\abs}{\\lvert}{\\rvert}
\\DeclarePairedDelimiter{\\norm}{\\lVert}{\\rVert}
\\DeclarePairedDelimiter{\\ceil}{\\lceil}{\\rceil}
\\DeclarePairedDelimiter{\\floor}{\\lfloor}{\\rfloor}
\\DeclarePairedDelimiter{\\round}{\\lfloor}{\\rceil}
然后,我们有各种常见的数字集,如果能有一种方便的方法来键入它们并选择性地赋予它们
幂,那就更好了。要同时支持 \XX
和 \XX[n]
是相当容易的。
\\newcommand{\\RR}[1][]{\\ensuremath{\\ifstrempty{#1}{\\mathbb{R}}{\\mathbb{R}^{#1}}}} % Real numbers
\\newcommand{\\NN}[1][]{\\ensuremath{\\ifstrempty{#1}{\\mathbb{N}}{\\mathbb{N}^{#1}}}} % Natural numbers
\\newcommand{\\ZZ}[1][]{\\ensuremath{\\ifstrempty{#1}{\\mathbb{Z}}{\\mathbb{Z}^{#1}}}} % Integer numbers
\\newcommand{\\QQ}[1][]{\\ensuremath{\\ifstrempty{#1}{\\mathbb{Q}}{\\mathbb{Q}^{#1}}}} % Rational numbers
\\newcommand{\\CC}[1][]{\\ensuremath{\\ifstrempty{#1}{\\mathbb{C}}{\\mathbb{C}^{#1}}}} % Complex numbers
导数的排版其实很麻烦,如果能有一个支持 \dv
的命令就更好了:
\dv{x}
:x
的导数\dv{f}{x}
:f
相对于x
的导数\dv[2]{f}{x}
:f
关于x
的二阶导数
同样,如果能有一个部分派生的对应 \pdv
就更好了,它的行为方式类似,但可以提供多
个逗号分隔的变量 – 例如 \pdv{f}{x,y,z}
.
% Easy derivatives
\\ProvideDocumentCommand\\dv{o m g}{%
\\IfNoValueTF{#3}{%
\\dv[#1]{}{#2}}{%
\\IfNoValueTF{#1}{%
\\frac{\\dd #2}{\\dd #3}%
}{\\frac{\\dd[#1] #2}{\\dd {#3}^{#1}}}}}
% Easy partial derivatives
\\ExplSyntaxOn
\\ProvideDocumentCommand\\pdv{o m g}{%
\\IfNoValueTF{#3}{\\pdv[#1]{}{#2}}%
{\\ifnum\\clist_count:n{#3}<2
\\IfValueTF{#1}{\\frac{\\partial^{#1} #2}{\\partial {#3}^{#1}}}%
{\\frac{\\partial #2}{\\partial #3}}
\\else
\\frac{\\IfValueTF{#1}{\\partial^{#1}}{\\partial^{\\clist_count:n{#3}}}#2}%
{\\clist_map_inline:nn{#3}{\\partial ##1 \\,}\\!}
\\fi}}
\\ExplSyntaxOff
公共运算符集可以进行一些扩展。
% Laplacian
\\DeclareMathOperator{\\Lap}{\\mathcal{L}}
% Statistics
\\DeclareMathOperator{\\Var}{Var} % varience
\\DeclareMathOperator{\\Cov}{Cov} % covarience
\\newcommand{\\EE}{\\ensuremath{\\mathbb{E}}} % expected value
\\DeclareMathOperator{\\E}{E} % expected value
默认情况下,矩阵中的所有内容都是居中排列的,但我发现这往往并不可取。如果能将对齐 方式作为环境的一个可选参数,并默认为右对齐,那就更好了。
% Redefine the matrix environment to allow for alignment
% via an optional argument, and use r as the default.
\\makeatletter
\\renewcommand*\\env@matrix[1][r]{\\hskip -\\arraycolsep%
\\let\\@ifnextchar\\new@ifnextchar
\\array{*\\c@MaxMatrixCols #1}}
\\makeatother
要制作漂亮的封面,想到的一个简单方法就是重新定义 \maketitle
。为了精确控制定位
,我们将使用 tikz
包,然后添加 Tikz 库 calc
和 shape.geometric
来为背
景做一些漂亮的装饰。
首先为序言设置必要的补充。 这将完成以下任务:
- 加载所需的包
- 重新定义
\maketitle
- 用 Tikz 画一个
Org
图标,用在封面上 (这是一个小彩蛋) - 通过重新定义
\tableofcontents
在目录之后开始一个新页面
\\usepackage{tikz}
\\usetikzlibrary{shapes.geometric}
\\usetikzlibrary{calc}
\\newsavebox\\orgicon
\\begin{lrbox}{\\orgicon}
\\begin{tikzpicture}[y=0.80pt, x=0.80pt, inner sep=0pt, outer sep=0pt]
\\path[fill=black!6] (16.15,24.00) .. controls (15.58,24.00) and (13.99,20.69) .. (12.77,18.06)arc(215.55:180.20:2.19) .. controls (12.33,19.91) and (11.27,19.09) .. (11.43,18.05) .. controls (11.36,18.09) and (10.17,17.83) .. (10.17,17.82) .. controls (9.94,18.75) and (9.37,19.44) .. (9.02,18.39) .. controls (8.32,16.72) and (8.14,15.40) .. (9.13,13.80) .. controls (8.22,9.74) and (2.18,7.75) .. (2.81,4.47) .. controls (2.99,4.47) and (4.45,0.99) .. (9.15,2.41) .. controls (14.71,3.99) and (17.77,0.30) .. (18.13,0.04) .. controls (18.65,-0.49) and (16.78,4.61) .. (12.83,6.90) .. controls (10.49,8.18) and (11.96,10.38) .. (12.12,11.15) .. controls (12.12,11.15) and (14.00,9.84) .. (15.36,11.85) .. controls (16.58,11.53) and (17.40,12.07) .. (18.46,11.69) .. controls (19.10,11.41) and (21.79,11.58) .. (20.79,13.08) .. controls (20.79,13.08) and (21.71,13.90) .. (21.80,13.99) .. controls (21.97,14.75) and (21.59,14.91) .. (21.47,15.12) .. controls (21.44,15.60) and (21.04,15.79) .. (20.55,15.44) .. controls (19.45,15.64) and (18.36,15.55) .. (17.83,15.59) .. controls (16.65,15.76) and (15.67,16.38) .. (15.67,16.38) .. controls (15.40,17.19) and (14.82,17.01) .. (14.09,17.32) .. controls (14.70,18.69) and (14.76,19.32) .. (15.50,21.32) .. controls (15.76,22.37) and (16.54,24.00) .. (16.15,24.00) -- cycle(7.83,16.74) .. controls (6.83,15.71) and (5.72,15.70) .. (4.05,15.42) .. controls (2.75,15.19) and (0.39,12.97) .. (0.02,10.68) .. controls (-0.02,10.07) and (-0.06,8.50) .. (0.45,7.18) .. controls (0.94,6.05) and (1.27,5.45) .. (2.29,4.85) .. controls (1.41,8.02) and (7.59,10.18) .. (8.55,13.80) -- (8.55,13.80) .. controls (7.73,15.00) and (7.80,15.64) .. (7.83,16.74) -- cycle;
\\end{tikzpicture}
\\end{lrbox}
\\makeatletter
\\g@addto@macro\\tableofcontents{\\clearpage}
\\renewcommand\\maketitle{
\\thispagestyle{empty}
\\hyphenpenalty=10000 % hyphens look bad in titles
\\renewcommand{\\baselinestretch}{1.1}
\\let\\oldtoday\\today
\\renewcommand{\\today}{\\LARGE\\number\\year\\\\\\large%
\\ifcase \\month \\or Jan\\or Feb\\or Mar\\or Apr\\or May \\or Jun\\or Jul\\or Aug\\or Sep\\or Oct\\or Nov\\or Dec\\fi
~\\number\\day}
\\begin{tikzpicture}[remember picture,overlay]
%% Background Polygons %%
\\foreach \\i in {2.5,...,22} % bottom left
{\\node[rounded corners,black!3.5,draw,regular polygon,regular polygon sides=6, minimum size=\\i cm,ultra thick] at ($(current page.west)+(2.5,-4.2)$) {} ;}
\\foreach \\i in {0.5,...,22} % top left
{\\node[rounded corners,black!5,draw,regular polygon,regular polygon sides=6, minimum size=\\i cm,ultra thick] at ($(current page.north west)+(2.5,2)$) {} ;}
\\node[rounded corners,fill=black!4,regular polygon,regular polygon sides=6, minimum size=5.5 cm,ultra thick] at ($(current page.north west)+(2.5,2)$) {};
\\foreach \\i in {0.5,...,24} % top right
{\\node[rounded corners,black!2,draw,regular polygon,regular polygon sides=6, minimum size=\\i cm,ultra thick] at ($(current page.north east)+(0,-8.5)$) {} ;}
\\node[fill=black!3,rounded corners,regular polygon,regular polygon sides=6, minimum size=2.5 cm,ultra thick] at ($(current page.north east)+(0,-8.5)$) {};
\\foreach \\i in {21,...,3} % bottom right
{\\node[black!3,rounded corners,draw,regular polygon,regular polygon sides=6, minimum size=\\i cm,ultra thick] at ($(current page.south east)+(-1.5,0.75)$) {} ;}
\\node[fill=black!3,rounded corners,regular polygon,regular polygon sides=6, minimum size=2 cm,ultra thick] at ($(current page.south east)+(-1.5,0.75)$) {};
\\node[align=center, scale=1.4] at ($(current page.south east)+(-1.5,0.75)$) {\\usebox\\orgicon};
%% Text %%
\\node[left, align=right, black, text width=0.8\\paperwidth, minimum height=3cm, rounded corners,font=\\Huge\\bfseries] at ($(current page.north east)+(-2,-8.5)$)
{\\@title};
\\node[left, align=right, black, text width=0.8\\paperwidth, minimum height=2cm, rounded corners, font=\\Large] at ($(current page.north east)+(-2,-11.8)$)
{\\scshape \\@author};
\\renewcommand{\\baselinestretch}{0.75}
\\node[align=center,rounded corners,fill=black!3,text=black,regular polygon,regular polygon sides=6, minimum size=2.5 cm,inner sep=0, font=\\Large\\bfseries ] at ($(current page.west)+(2.5,-4.2)$)
{\\@date};
\\end{tikzpicture}
\\let\\today\\oldtoday
\\clearpage}
\\makeatother
现在我们有了一个不错的封面页,我们只需要不时使用它。将此添加到 #+options
感觉
最合适。让封面选项接受 auto 作为值,然后根据字数决定是否应使用封面。然后我们只想
插入一个 LaTeX 片段在封面中来调整标题格式。
(defvar org-latex-cover-page 'auto
"When t, use a cover page by default.
When auto, use a cover page when the document's wordcount exceeds
`org-latex-cover-page-wordcount-threshold'.
Set with #+option: coverpage:{yes,auto,no} in org buffers.")
(defvar org-latex-cover-page-wordcount-threshold 5000
"Document word count at which a cover page will be used automatically.
This condition is applied when cover page option is set to auto.")
(defvar org-latex-subtitle-coverpage-format "\\\\\\bigskip\n\\LARGE\\mdseries\\itshape\\color{black!80} %s\\par"
"Variant of `org-latex-subtitle-format' to use with the cover page.")
(defvar org-latex-cover-page-maketitle "
<<latex-cover-page>>
"
"LaTeX preamble snippet that sets \\maketitle to produce a cover page.")
(eval '(cl-pushnew '(:latex-cover-page nil "coverpage" org-latex-cover-page)
(org-export-backend-options (org-export-get-backend 'latex))))
(defun org-latex-cover-page-p ()
"Whether a cover page should be used when exporting this Org file."
(pcase (or (car
(delq nil
(mapcar
(lambda (opt-line)
(plist-get (org-export--parse-option-keyword opt-line 'latex) :latex-cover-page))
(cdar (org-collect-keywords '("OPTIONS"))))))
org-latex-cover-page)
((or 't 'yes) t)
('auto (when (> (count-words (point-min) (point-max)) org-latex-cover-page-wordcount-threshold) t))
(_ nil)))
(defadvice! org-latex-set-coverpage-subtitle-format-a (contents info)
"Set the subtitle format when a cover page is being used."
:before #'org-latex-template
(when (org-latex-cover-page-p)
(setf info (plist-put info :latex-subtitle-format org-latex-subtitle-coverpage-format))))
(add-to-list 'org-latex-feature-implementations '(cover-page :snippet org-latex-cover-page-maketitle :order 9) t)
(add-to-list 'org-latex-conditional-features '((org-latex-cover-page-p) . cover-page) t)
或许之后可以再加一些不同的封面。
来个序言区模板,主要采用 tcblisting
生成主题 box
\\usepackage{accsupp}
\\usepackage[most,breakable,minted]{tcolorbox}
\\definecolor{solarized-light-background}{HTML}{FDF6E3}
\\definecolor{solarized-light-frame}{HTML}{EEE8D6}
\\definecolor{solarized-light-title}{HTML}{979797}
\\definecolor{solarized-light-lineno}{HTML}{237D99}
\\newcommand{\\SetFancyVerbLine}{
\\renewcommand{\\theFancyVerbLine}{
\\protect\\BeginAccSupp{ActualText={}}\\sffamily\\textcolor{solarized-light-lineno}{\\scriptsize\\oldstylenums{\\arabic{FancyVerbLine}}}\\protect\\EndAccSupp{}
}
}
\\newenvironment{orglisting}[2][]{
\\SetFancyVerbLine
\\tcblisting{
frame empty,
enhanced jigsaw,
drop fuzzy shadow,
breakable,
center,
width=\\linewidth,
bottom=1mm, top=1mm, left=6mm,
fonttitle=\\bfseries,
listing only,
listing engine=minted,
colback=solarized-light-background,
colframe=solarized-light-frame,
coltitle=solarized-light-title,
minted style=solarized-light,
minted language=#2,
minted options={
breaklines=t,
breakbefore=.,
samepage=nil,
encoding=utf8,
fontsize=\\small,
mathescape=t,
escapeinside=,
autogobble=t,
breakautoindent=t,
tabsize=4,
numbersep=2mm,
% numbers=left,
numberblanklines=t,
firstline=1,
firstnumber=1,
% lastline=,
showspaces=nil,
space=\\textvisiblespace, %% only showspaces=true
obeytabs=nil,
showtabs=nil,
#1
},
}
}{
\\endtcblisting
}
设置一下自己的代码渲染方式
(setq! org-latex-listings 'tcblisting
org-latex-tcblisting-code-preamble "
<<latex-tcblisting-code-preamble>>
")
修改一下导出代码块的行为
(defadvice! org-latex-src-block-tcblisting (orig-fn src-block contents info)
"Like `org-latex-src-block', but supporting an tcblisting backend"
:around #'org-latex-src-block
(if (eq 'tcblisting org-latex-src-block-backend)
(ginshio/org-latex-scr-block src-block contents info)
(funcall orig-fn src-block contents info)))
(defun ginshio/org-latex-src-block-getlang (language minted-langs)
(if (not (string-equal-ignore-case language "fundamental"))
(or (cadr (assq (intern language) minted-langs))
(downcase language))
"text"))
(defun ginshio/org-latex-scr-block (src-block contents info)
(let* ((lang (org-element-property :language src-block))
(attributes (org-export-read-attribute :attr_latex src-block))
(float (plist-get attributes :float))
(num-start (org-export-get-loc src-block info))
(retain-labels (org-element-property :retain-labels src-block))
(caption (org-element-property :caption src-block))
(caption-above-p (org-latex--caption-above-p src-block info))
(caption-str (org-latex--caption/label-string src-block info))
(placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement))
(plist-get info :latex-default-figure-position)))
(float-env
(cond
((string= "multicolumn" float)
(format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}"
placement
(if caption-above-p caption-str "")
(if caption-above-p "" caption-str)))
(caption
(format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}"
placement
(if caption-above-p caption-str "")
(if caption-above-p "" caption-str)))
((string= "t" float)
(concat (format "\\begin{listing}[%s]\n" placement)
"%s\n\\end{listing}"))
(t "%s")))
(options (plist-get info :latex-minted-options))
(body
(format
"\\begin{orglisting}[%s]{%s}\n%s\\end{orglisting}"
;; Options.
(concat
(org-latex--make-option-string
(if (or (not num-start) (assoc "linenos" options))
options
(append
`(("linenos")
("firstnumber" ,(number-to-string (1+ num-start))))
options)))
(let ((local-options (plist-get attributes :options)))
(and local-options (concat "," local-options))))
;; Language.
(ginshio/org-latex-src-block-getlang lang (plist-get info :latex-minted-langs))
;; Source code.
(let* ((code-info (org-export-unravel-code src-block))
(max-width
(apply 'max
(mapcar 'length
(org-split-string (car code-info)
"\n")))))
(org-export-format-code
(car code-info)
(lambda (loc _num ref)
(concat
loc
(when ref
;; Ensure references are flushed to the right,
;; separated with 6 spaces from the widest line
;; of code.
(concat (make-string (+ (- max-width (length loc)) 6)
?\s)
(format "(%s)" ref)))))
nil (and retain-labels (cdr code-info)))))))
;; Return value.
(format float-env body)))
内联代码块的行为相对更好修改
(defadvice! org-latex-inline-src-block-tcblisting (orig-fn inline-src-block contents info)
"Like `org-latex-inline-src-block', but supporting an tcblisting backend"
:around #'org-latex-inline-src-block
(if (eq 'tcblisting org-latex-src-block-backend)
;; (funcall orig-fn inline-src-block contents (plist-put info :latex-listings 'minted))
(ginshio/org-latex-inline-src-block inline-src-block contents info)
(funcall orig-fn inline-src-block contents info)))
(defun ginshio/org-latex-inline-src-block (inline-src-block _contents info)
(let* ((code (org-element-property :value inline-src-block))
(separator (org-latex--find-verb-separator code))
(org-lang (org-element-property :language inline-src-block))
(mint-lang (ginshio/org-latex-src-block-getlang lang (plist-get info :latex-minted-langs)))
(options (org-latex--make-option-string
(plist-get info :latex-minted-options))))
(format "\\mintinline%s{%s}{%s}"
(if (string= options "") "" (format "[%s]" options))
mint-lang code)))
最终将其添加到智能序言中
(add-to-list 'org-latex-conditional-features '("^[ \t]*#\\+begin_src\\|^[ \t]*#\\+BEGIN_SRC\\|src_[A-Za-z]" . tcblisting-code-preamble) t)
(add-to-list 'org-latex-feature-implementations '(tcblisting-code-preamble :snippet org-latex-tcblisting-code-preamble :order 99) t)
有一个问题,就是代码中的所有引号有问题。
区分 verbatim
和 verb
(setq! org-latex-text-markup-alist
'((bold . "\\textbf{%s}")
(code . protectedtexttt)
(italic . "\\emph{%s}")
(strike-through . "\\sout{%s}")
(underline . "\\uline{%s}")
(verbatim . verb)))
顾名思义,这是一个语言的巴别塔,我们可以在 org-mode 中运行所有编程语言!当然,我 们需要定制一些东西。
(after! ox-pandoc
<<ox-pandoc-conf>>
)
在使用 Pandoc 进行导出 gfm 时,链接 headline 时链接会被导出为数字。具体参见 Issue #58。
(advice-add 'org-pandoc-link
:around #'(lambda (fun link contents info)
(let* ((dest (when (string= (org-element-property :type link) "fuzzy")
(org-export-resolve-fuzzy-link link info)))
(dest-type (when dest (org-element-type dest)))
(path (org-element-property :path link)))
(if (eq dest-type 'headline)
(format "[[#%s][%s]]" path path)
(funcall fun link contents info)))))
(setq! LaTeX-biblatex-use-Biber t)
(custom-set-variables '(LaTeX-section-label '(("part" . "part:")
("chapter" . "chap:")
("section" . "sec:")
("subsection" . "subsec:")
("subsubsection" . "subsubsec:")))
'(TeX-auto-local "auto")
'(TeX-command-extra-options "--shell-escape --interaction=nonstopmode"))
(after! latex
<<tex-conf>>
)
(setq! TeX-save-query nil
TeX-show-compilation t
LaTeX-clean-intermediate-suffixes (append TeX-clean-default-intermediate-suffixes
'("\\.acn" "\\.acr" "\\.alg" "\\.glg"
"\\.ist" "\\.listing" "\\.fdb_latexmk")))
(add-to-list 'TeX-command-list '("LatexMk (LuaLaTeX)" "LC_ALL=en_US.UTF-8 latexmk -pdf -lualatex -8bit %S%(mode) %(file-line-error) %(extraopts) %t" TeX-run-latexmk nil
(plain-tex-mode latex-mode doctex-mode)
:help "Run LatexMk (LuaLaTeX)"))
如果 bib
中有你不想要的某些字段,可以通过一下方法去除 (导言区)
\AtEveryBibitem{
\clearfield{note}
\ifentrytype{book}{
\clearfield{url}
\clearfield{isbn}
}{}
\ifentrytype{article}{
\clearfield{url}
}{}
\ifentrytype{thesis}{
\clearfield{url}
}{}
}
增强一点点视觉效果
(setq TeX-fold-math-spec-list
`(;; missing/better symbols
("≤" ("le"))
("≥" ("ge"))
("≠" ("ne"))
;; convenience shorts -- these don't work nicely ATM
;; ("‹" ("left"))
;; ("›" ("right"))
;; private macros
("ℝ" ("RR"))
("ℕ" ("NN"))
("ℤ" ("ZZ"))
("ℚ" ("QQ"))
("ℂ" ("CC"))
("ℙ" ("PP"))
("ℍ" ("HH"))
("𝔼" ("EE"))
("𝑑" ("dd"))
;; known commands
("" ("phantom"))
(,(lambda (num den) (if (and (TeX-string-single-token-p num) (TeX-string-single-token-p den))
(concat num "/" den)
(concat "❪" num "/" den "❫"))) ("frac"))
(,(lambda (arg) (concat "√" (TeX-fold-parenthesize-as-necessary arg))) ("sqrt"))
(,(lambda (arg) (concat "⭡" (TeX-fold-parenthesize-as-necessary arg))) ("vec"))
("‘{1}’" ("text"))
;; private commands
("|{1}|" ("abs"))
("‖{1}‖" ("norm"))
("⌊{1}⌋" ("floor"))
("⌈{1}⌉" ("ceil"))
("⌊{1}⌉" ("round"))
("𝑑{1}/𝑑{2}" ("dv"))
("∂{1}/∂{2}" ("pdv"))
;; fancification
("{1}" ("mathrm"))
(,(lambda (word) (string-offset-roman-chars 119743 word)) ("mathbf"))
(,(lambda (word) (string-offset-roman-chars 119951 word)) ("mathcal"))
(,(lambda (word) (string-offset-roman-chars 120003 word)) ("mathfrak"))
(,(lambda (word) (string-offset-roman-chars 120055 word)) ("mathbb"))
(,(lambda (word) (string-offset-roman-chars 120159 word)) ("mathsf"))
(,(lambda (word) (string-offset-roman-chars 120367 word)) ("mathtt"))
)
TeX-fold-macro-spec-list
'(
;; as the defaults
("[f]" ("footnote" "marginpar"))
("[c]" ("cite"))
("[l]" ("label"))
("[r]" ("ref" "pageref" "eqref"))
("[i]" ("index" "glossary"))
("..." ("dots"))
("{1}" ("emph" "textit" "textsl" "textmd" "textrm" "textsf" "texttt"
"textbf" "textsc" "textup"))
;; tweaked defaults
("©" ("copyright"))
("®" ("textregistered"))
("™" ("texttrademark"))
("[1]:||►" ("item"))
("❡❡ {1}" ("part" "part*"))
("❡ {1}" ("chapter" "chapter*"))
("§ {1}" ("section" "section*"))
("§§ {1}" ("subsection" "subsection*"))
("§§§ {1}" ("subsubsection" "subsubsection*"))
("¶ {1}" ("paragraph" "paragraph*"))
("¶¶ {1}" ("subparagraph" "subparagraph*"))
;; extra
("⬖ {1}" ("begin"))
("⬗ {1}" ("end"))
))
(defun string-offset-roman-chars (offset word)
"Shift the codepoint of each character in WORD by OFFSET with an extra -6 shift if the letter is lowercase"
(apply 'string
(mapcar (lambda (c)
(string-offset-apply-roman-char-exceptions
(+ (if (>= c 97) (- c 6) c) offset)))
word)))
(defvar string-offset-roman-char-exceptions
'(;; lowercase serif
(119892 . 8462) ; ℎ
;; lowercase caligraphic
(119994 . 8495) ; ℯ
(119996 . 8458) ; ℊ
(120004 . 8500) ; ℴ
;; caligraphic
(119965 . 8492) ; ℬ
(119968 . 8496) ; ℰ
(119969 . 8497) ; ℱ
(119971 . 8459) ; ℋ
(119972 . 8464) ; ℐ
(119975 . 8466) ; ℒ
(119976 . 8499) ; ℳ
(119981 . 8475) ; ℛ
;; fraktur
(120070 . 8493) ; ℭ
(120075 . 8460) ; ℌ
(120076 . 8465) ; ℑ
(120085 . 8476) ; ℜ
(120092 . 8488) ; ℨ
;; blackboard
(120122 . 8450) ; ℂ
(120127 . 8461) ; ℍ
(120133 . 8469) ; ℕ
(120135 . 8473) ; ℙ
(120136 . 8474) ; ℚ
(120137 . 8477) ; ℝ
(120145 . 8484) ; ℤ
)
"An alist of deceptive codepoints, and then where the glyph actually resides.")
(defun string-offset-apply-roman-char-exceptions (char)
"Sometimes the codepoint doesn't contain the char you expect.
Such special cases should be remapped to another value, as given in `string-offset-roman-char-exceptions'."
(if (assoc char string-offset-roman-char-exceptions)
(cdr (assoc char string-offset-roman-char-exceptions))
char))
(defun TeX-fold-parenthesize-as-necessary (tokens &optional suppress-left suppress-right)
"Add ❪ ❫ parenthesis as if multiple LaTeX tokens appear to be present"
(if (TeX-string-single-token-p tokens) tokens
(concat (if suppress-left "" "❪")
tokens
(if suppress-right "" "❫"))))
(defun TeX-string-single-token-p (teststring)
"Return t if TESTSTRING appears to be a single token, nil otherwise"
(if (string-match-p "^\\\\?\\w+$" teststring) t nil))
一些 local 快捷键使生活更轻松
(map!
:map LaTeX-mode-map
:ei [C-return] #'LaTeX-insert-item)
(setq TeX-electric-math '("\\(" . ""))
当然数学界定符不需要强调
;; Making \( \) less visible
(defface unimportant-latex-face
'((t :inherit font-lock-comment-face :weight extra-light))
"Face used to make \\(\\), \\[\\] less visible."
:group 'LaTeX-math)
(font-lock-add-keywords
'latex-mode
`(("\\\\[]()[]" 0 'unimportant-latex-face prepend))
'end)
;; (font-lock-add-keywords
;; 'latex-mode
;; '(("\\\\[[:word:]]+" 0 'font-lock-keyword-face prepend))
;; 'end)
默认情况下,符号修改非常好用,但可以充实更多符号。让我们将前缀更改为同样很少使用但更方便的键,例如 =;=。
(after! cdlatex
(setq cdlatex-env-alist
'(("bmatrix" "\\begin{bmatrix}\n?\n\\end{bmatrix}" nil)
("equation*" "\\begin{equation*}\n?\n\\end{equation*}" nil)))
(setq ;; cdlatex-math-symbol-prefix ?\; ;; doesn't work at the moment :(
cdlatex-math-symbol-alist
'( ;; adding missing functions to 3rd level symbols
(?_ ("\\downarrow" "" "\\inf"))
(?2 ("^2" "\\sqrt{?}" "" ))
(?3 ("^3" "\\sqrt[3]{?}" "" ))
(?^ ("\\uparrow" "" "\\sup"))
(?k ("\\kappa" "" "\\ker"))
(?m ("\\mu" "" "\\lim"))
(?c ("" "\\circ" "\\cos"))
(?d ("\\delta" "\\partial" "\\dim"))
(?D ("\\Delta" "\\nabla" "\\deg"))
;; no idea why \Phi isnt on 'F' in first place, \phi is on 'f'.
(?F ("\\Phi"))
;; now just convenience
(?. ("\\cdot" "\\dots"))
(?: ("\\vdots" "\\ddots"))
(?* ("\\times" "\\star" "\\ast")))
cdlatex-math-modify-alist
'( ;; my own stuff
(?B "\\mathbb" nil t nil nil)
(?a "\\abs" nil t nil nil))))
(setq!
;;; %o: TeX-output-extension; %n: TeX-current-line; %b: TeX-current-file-name-master-relative
TeX-view-program-list '(("Okular" "okular --unique %o#src:%n%(dir)./%b"))
TeX-view-program-selection '((output-pdf "Okular") (output-dvi "Okular")))
(add-hook! latex-mode #'TeX-latex-mode)
Doom 默认的 Markdown 是 GFM
(GitHub Flavored Markdown),不过有了 Emacs
和
Org Mode
谁还用 Markdown
。但是 toc-org-mode
依然可以使用。
可以采用如下方式支持 Markdown。
# TOC <!-- :TOC: -->
tcc 也是 C++
(add-to-list 'auto-mode-alist '("\\.tcc\\'" . c++-mode))
如果开启了 format 那可以使用 clang-format 自动格式化代码
(set-formatter! 'clang-format
'("clang-format" "--Wno-error=unknown" ("-assume-filename=%S" (or buffer-file-name mode-result "")))
:modes '(c-mode c++-mode))
设置 gud-gdb 显示当前行
(after! gud-gdb
;;; Keep the current line in sync with the point and in the center of the
;;; buffer. Otherwise the current line may disappear from the buffer as you step
;;; into the code. I don't know why this is not the default.
(defadvice gud-display-line (after gud-display-line-centered activate)
"Center the current line in the source code window"
(when (and gud-overlay-arrow-position gdb-source-window)
(with-selected-window gdb-source-window
; (marker-buffer gud-overlay-arrow-position)
(save-restriction
;; Compiler-happy equivalent to (goto-line (ad-get-arg 1))
(goto-char (point-min))
(forward-line (1- (ad-get-arg 1)))
(recenter))))))