[[https://travis-ci.org/kimim/kimim-emacs][https://travis-ci.org/kimim/kimim-emacs.svg]]
This Emacs configuration file is written in literate programming method [fn:1]. The =emacs-lisp= code is extracted from this =orgmode= [fn:2] file, and then compiled to binary =elc= file for fast loading in the future.
First of all, you need to get =emacs= and install it in your machine.
** Windows/MSYS2
On Windows, we have three options: 1) MSYS2, 2) Cygwin, 3) WSL2.
If your msys2 [fn:3] is installed in =C:\msys64=, you can open =C:\msys64\mingw64.exe=, and run following command to install Emacs:
pacman -S git mingw-w64-x86_64-emacs
** Windows/Cygwin
Since 2020, I use MSYS2 MingW64 Emacs for most of the time, Cygwin Emacs is not actively tested now, but Emacs should work in Cygwin environment smoothly.
Cygwin project[fn:4] is a large collection of GNU and Open Source tools provide functionality similar to a Linux distribution on Windows.
You can download and install Cygwin setup [fn:5] in your machine, for example, at =C:\cygwin64=. Then you can use =mintty.exe= to work with =bash=.
Then start =emacs= from cygwin terminal, and right click the =emacs= icon to pin it to taskbar, then click the property of this icon to add bellow to the target field. This way will hide the black terminal.
C:\cygwin64\bin\run.exe emacs-w32
You can also add =emacs --daemon= in your scheduled task, and change the target field as:
C:\cygwin64\bin\run.exe emacsclient -c
This will attach the client to the server daemon. You can get a running =emacs= very quick.
** Windows/WSL2
Nowadays, Windows is embracing Linux tightly. You can try =emacs= on Windows subsystem for Linux version 2. You can get Ubuntu Linux from Windows App Store or Manjaro Linux for WSL2 [fn:6].
Commands to install Emacs is same as on Linux in next section.
** Linux
Most of the external tools I used in this Emacs configuration should be easily installed or already available in main Linux distributions.
For example, in Ubuntu, you can install this way:
sudo snap install emacs --classic
It is also very quick to add emacs in ArchLinux/Manjaro:
pacman -S emacs
** macOS
For Apple macOS, most UNIX tools are installed already. You can use homebrew [fn:7] to install additional application if it is missing.
/bin/bash -c \ "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" brew tap railwaycat/emacsmacport brew install emacs-mac
You can follow below shell commands to prepare the =emacs= configuration files and folders:
cd ~ && mv .emacs .emacs-backup && mv .emacs.d .emacs.d-backup
git clone --recurse-submodules https://github.com/kimim/kimim-emacs
cp kimim-emacs/.emacs ~
This configuration uses several path to keep different information, you need to define them in =~/.emacs=:
Let's tell =emacs=, if the path is not set, report error, if the path is set, but not exists, create it.
(mapc (lambda (path) (if (not (boundp path)) (error (concat "please set " (symbol-name path) " in ~/.emacs")) (if (not (file-exists-p (symbol-value path))) (make-directory (symbol-value path))))) '(kimim/path-sync kimim/path-emacs kimim/path-org kimim/path-notes kimim/path-docs kimim/path-kimim-emacs))
Then you can execute =emacs= to bootstrap itself.
** chemacs2
Another way to try this configure out is to use [[https://github.com/plexus/chemacs2][chemacs2]].
Clone to ~~/kimim-emacs~
git clone https://github.com/kimim/kimim-emacs ~/kimim-emacs
Add to chemacs2 profile file ~~/.emacs.profile.el~
(("default" . ((user-emacs-directory . "~/.emacs.default"))) ("kimim" . ((user-emacs-directory . "~/kimim-emacs"))))
Start emacs with this config:
emacs --with-profile kimim
If you want use ~~/.emacs.kimim~ as the ~user-emacs-directory~, you need to modify the value of variable ~kimim/path-kimim-emacs~ in ~early-init.el~.
(defvar kimim/path-kimim-emacs "~/.emacs.kimim/")
** PATH and exec-path
Environment variable =PATH= is the the searching path of executables by the shell running in Emacs while =exec-path= is the search path of Emacs itself. So we should set both of them to almost the same paths.
As I have a Windows box in the office, and an Apple macOS at home, so I need to specify these variables in different way.
(cond ((eq system-type 'cygwin) (setq kimim/path-root "/")) ((eq system-type 'darwin) (setq kimim/path-root "/") (add-to-list 'exec-path "/Library/TeX/texbin")) ((eq system-type 'gnu/linux) (setq kimim/path-root "/") (add-to-list 'exec-path "/usr/local/texlive/2020/bin/x86_64-linux/")))
(add-to-list 'exec-path (concat kimim/path-root "bin")) (add-to-list 'exec-path (concat kimim/path-root "usr/bin")) (add-to-list 'exec-path (concat kimim/path-root "usr/local/bin"))
Then append exec-path to PATH:
(setenv "PATH" (concat (mapconcat #'identity exec-path path-separator) (getenv "PATH")))
For Windows/MSYS64, we need to modify =executable-find= to locate shell scripts:
(defun executable-find (command &optional remote)
"Search for COMMAND in exec-path' and return the absolute file name. Return nil if COMMAND is not found anywhere in
exec-path'. If
REMOTE is non-nil, search on the remote host indicated by
`default-directory' instead."
(if (and remote (file-remote-p default-directory))
(let ((res (locate-file
command
(mapcar
(lambda (x) (concat (file-remote-p default-directory) x))
(exec-path))
exec-suffixes 'file-executable-p)))
(when (stringp res) (file-local-name res)))
;; Use 1 rather than file-executable-p to better match the
;; behavior of call-process.
(let ((default-directory (file-name-quote default-directory 'top)))
(locate-file command exec-path exec-suffixes))))
** Language
I prefer to use English/UTF-8 as default language environment.
(setenv "LANG" "en_US.UTF-8") (setenv "LC_ALL" "en_US.UTF-8") ;; remove svn log LC_TYPE not defined warning. (setenv "LC_CTYPE" "en_US.UTF-8") (setenv "LC_TIME" "en_US.UTF-8") (set-locale-environment "en_US.UTF-8") (set-language-environment 'English) (prefer-coding-system 'utf-8) (set-buffer-file-coding-system 'utf-8-unix) (set-keyboard-coding-system 'utf-8) (set-selection-coding-system 'utf-8) (set-file-name-coding-system 'utf-8) (set-terminal-coding-system 'utf-8) (set-clipboard-coding-system 'utf-8) (cond ((member system-type '(windows-nt cygwin)) (set-clipboard-coding-system 'utf-16le)))
** global key map
Define new command prefix for keys such as "C-x m f", "C-x m v".
(define-prefix-command 'ctl-x-m-map) (global-set-key "\C-xm" 'ctl-x-m-map)
=package= [fn:8] is the modern =elisp= package management system, which let you easily download and install packages that implement additional features. Each package is a separate Emacs Lisp program, sometimes including other components such as an Info manual.
All the extensions used in this file are installed and managed by =package=.
Here I use =use-package= to defer the package loading and even installation, When you use the =:commands= keyword, it creates autoloads for those commands and defers loading of the module until they are used.
When I want to upgrade elpa packages, I just call ~list-packages~, and let emacs refresh the package lists, then I just need to press =U= to upgrade all new packages.
If some weird things happen, for example ~compat-current-version~ error, a ~byte-force-recompile~ in =~/.emacs.d= could work.
;; temporary disable signature check (setq package-check-signature nil) (setq package-user-dir "~/.emacs.d/elpa") (setq package-archives '(;;("elpa" . "https://elpa.gnu.org/packages/") ;;("melpa" . "https://melpa.org/packages/") ("gnu" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/gnu/") ("melpa" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/melpa/"))) (mapc (lambda (package) (unless (package-installed-p package) (progn (message "installing %s" package) (package-refresh-contents) (package-install package)))) '(use-package diminish bind-key))
(require 'use-package) (require 'diminish) (require 'bind-key) ;; install package if missing (setq use-package-always-ensure t) (setq use-package-always-defer t) (setq use-package-verbose t)
Don't display menu-bar, tool-bar, tooltip and scroll-bar. Because sometimes, they may catch your attention.
(defun kimim/menu-and-bar () (cond (window-system ;; Enable copy and paste in Win32 (setq select-enable-clipboard t) (tool-bar-mode -1) (tooltip-mode -1) (scroll-bar-mode -1) (when (eq window-system 'w32) (menu-bar-mode 0))) ((eq window-system nil) (menu-bar-mode 0))))
** Font and Frame Size
Set default font and frame size for both window system. You should =set-default-font= first, otherwise, the frame height and width will be calculated with original default font height and width: =frame-char-height= and =frame-char-width=.
(use-package cnfonts :bind (("C-+" . cnfonts-increase-fontsize) ("C--" . cnfonts-decrease-fontsize) ("C-=" . cnfonts-increase-fontsize) ("C-0" . cnfonts-reset-fontsize)))
(defun kimim/set-frame-alist (top left height width) (let ((frame (selected-frame))) (set-frame-position frame left top) (set-frame-height frame height) (set-frame-width frame width)) (setq default-frame-alist `((top . ,top) (left . ,left) (height . ,height) (width . ,width) (vertical-scroll-bars) (tool-bar-lines))))
(defun kimim/screen-width () (/ (display-pixel-width) (frame-char-width)))
(defun kimim/screen-height () (/ (display-pixel-height) (frame-char-height)))
(defun kimim/frame-and-font () (interactive) (when window-system (require 'cnfonts) (cnfonts-enable) (cnfonts-set-font) ;; top, left ... must be integer (let ((width (ceiling ( 0.8 (kimim/screen-width)))) (height (ceiling (* 0.8 (kimim/screen-height)))) (top (/ (display-pixel-height) 10)) (left (/ (display-pixel-width) 10))) (kimim/menu-and-bar) (kimim/set-frame-alist top left height width))))
(defun kimim/frame-and-font-phone () (interactive) (when window-system (require 'cnfonts) (cnfonts-enable) (cnfonts-set-font) ;; top, left ... must be integer (let ((width (ceiling ( 0.36 (kimim/screen-width)))) (height (ceiling ( 0.9 (kimim/screen-height)))) (top (/ (display-pixel-height) 20)) (left (/ ( 34 (display-pixel-width)) 100))) (kimim/menu-and-bar) (kimim/set-frame-alist top left height width))))
(defun kimim/frame-and-font-cast () (interactive) (when window-system (require 'cnfonts) (cnfonts-enable) (cnfonts-set-font) ;; top, left ... must be integer (let ((width (ceiling ( 0.36 (kimim/screen-width)))) (height (ceiling ( 0.34 (kimim/screen-height)))) (top (/ (display-pixel-height) 10)) (left (/ ( 33 (display-pixel-width)) 100))) (kimim/set-frame-alist top left height width))))
(defun kimim/frame-and-font-mini () (interactive) ;; top, left ... must be integer (let ((width (ceiling ( 0.8 (kimim/screen-width)))) (height (ceiling (* 0.4 (kimim/screen-height)))) (top (/ (display-pixel-height) 2)) (left (/ (display-pixel-width) 10)) (frame (selected-frame))) (kimim/menu-and-bar) (kimim/set-frame-alist top left height width)))
(defun kimim/new-mini-frame-bottom () "Create a small frame at bottom for write note." (interactive) ;; after-make-frame-hook make this no work, maybe change that hook (let ((frm (make-frame `((height . ,(ceiling ( 0.4 (kimim/screen-height)))) (width . ,(ceiling ( 0.8 (kimim/screen-width)))))))) (set-frame-position frm (/ (display-pixel-width) 10) (/ (display-pixel-height) 2))))
(kimim/frame-and-font)
** Frames
Customize the frame title to display buffer file name.
(setq frame-title-format '((:eval (buffer-name)))) ;; don't expand minibuffer in other frame (setq minibuffer-follows-selected-frame nil)
** Mode Line
Display date and time, but do not display system load.
(use-package time :ensure nil :defer 0 :custom (display-time-24hr-format t) (display-time-day-and-date t) (display-time-interval 10) (display-time-default-load-average nil) :config (display-time-mode t))
Show (line, column) numbers in mode line:
(use-package simple :ensure nil :defer 3 :bind ;; cycling from one space, zero space and original space ("M-SPC" . cycle-spacing) :custom ;; put pastebin content to kill ring before kill others (save-interprogram-paste-before-kill t) :config (line-number-mode 1) (column-number-mode 1) (toggle-word-wrap -1))
** Celestial modeline
Zwei Dinge erfüllen das Gemüt mit immer neuer und zunehmender Bewunderung und Ehrfurcht, je öfter und anhaltender sich das Nachdenken damit beschäftigt: Der bestirnte Himmel über mir, und das moralische Gesetz in mir.
-- Immanuel Kant
(use-package celestial-mode-line :defer 1 :custom (celestial-mode-line-update-interval 300) :config ;; use smaller symbols, the original one expand the modeline (setq celestial-mode-line-sunrise-sunset-alist '((sunrise . "☼ꜛ") (sunset . "☼ꜜ"))) (setq celestial-mode-line-phase-representation-alist '((0 . "●") (1 . ">") (2 . "○") (3 . "<"))) (setq global-mode-string '("" celestial-mode-line-string " " display-time-string "")))
Add sunrise/sunset info to modeline text description.
(use-package celestial-mode-line :config (defun kimim/celestial-mode-line--sunrise-sunset-string (time) (cl-destructuring-bind (sun-time location) time (let ((h (truncate sun-time)) (m (truncate ( 60 (- sun-time h))))) (concat (assoc-default (if (< h 12) 'sunrise 'sunset) celestial-mode-line-sunrise-sunset-alist 'equal celestial-mode-line-polar-representation) (format "%d:%02d" h m)))))
(defun kimim/celestial-mode-line--sun-description (orig-fun &rest args) (concat (kimim/celestial-mode-line--sunrise-sunset-string (car (solar-sunrise-sunset (car args)))) " " (kimim/celestial-mode-line--sunrise-sunset-string (cadr (solar-sunrise-sunset (car args)))) ", " (apply orig-fun args)))
;; add sun rise/set info to modeline text description (advice-add 'celestial-mode-line--text-description :around
(celestial-mode-line-start-timer))
** awesome tray
~awesome-tray~ adds an overlay to minibuffer and hides mode line to save window space.
(use-package awesome-tray :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/awesome-tray")) :commands (awesome-tray-mode) :custom (awesome-tray-date-format "%-m-%-e %H:%M") (awesome-tray-active-modules '("changed" "org-pomodoro" "location-or-page" "belong" "celestial" "date" "input-method")) (awesome-tray-mode-line-default-height 0.85) (awesome-tray-location-info-top "↑") (awesome-tray-location-info-bottom "↓") (awesome-tray-input-method-local-style "Ѱ") :custom-face (awesome-tray-grey-face ((((background light)) :foreground "dim grey" :bold nil) (t :foreground "dark grey" :bold nil))) (awesome-tray-module-buffer-name-face ((t :inherit awesome-tray-grey-face))) (awesome-tray-module-location-or-page-face ((t :inherit awesome-tray-grey-face))) (awesome-tray-module-git-face ((t :inherit awesome-tray-grey-face))) (awesome-tray-module-pdf-view-page-face ((t :inherit awesome-tray-grey-face))) (awesome-tray-module-input-method-face ((t :inherit awesome-tray-grey-face))) (org-mode-line-clock ((t :inherit unspecified))) (org-mode-line-clock-overrun ((t :inherit unspecified))) :config (advice-add 'awesome-tray-enable :before (lambda () (setq awesome-tray-mode-line-colors nil) (setq awesome-tray-mode-line-active-color (face-attribute 'mode-line :background)) (setq awesome-tray-mode-line-inactive-color (face-attribute 'default :background))))
(advice-add 'awesome-tray-enable :after (lambda () (set-face-attribute 'mode-line-inactive nil :underline (face-attribute 'mode-line :foreground))))
(advice-add 'awesome-tray-disable :after (lambda () (set-face-attribute 'mode-line-inactive nil :underline 'unspecified)))
(defun kimim/awesome-tray-module-buffer-changed-info () (if (and (buffer-modified-p) (not (eq buffer-file-name nil))) "✶")) (add-to-list 'awesome-tray-module-alist '("changed" . (kimim/awesome-tray-module-buffer-changed-info awesome-tray-grey-face)))
(defvar kimim/awesome-tray-original-modules nil) (defun kimim/awesome-tray-minimalistic () (interactive) (if kimim/awesome-tray-original-modules (progn (message "restore awesome tray modules") (setq awesome-tray-active-modules kimim/awesome-tray-original-modules) (setq kimim/awesome-tray-original-modules nil)) (progn (message "awesome tray minimalistic") (setq kimim/awesome-tray-original-modules awesome-tray-active-modules) (setq awesome-tray-active-modules '("buffer-name" "changed" "location-or-page" "date" "input-method"))))))
** path in headerline
When minimalistic emacs is on with awesome tray, we sometimes need to lookup buffer file name with header line.
(use-package path-headerline-mode :bind ("C-x /" . kimim/toggle-path-header) :config (defun kimim/toggle-path-header () "Toggle display path header" (interactive) (if header-line-format (path-header-line-off) (path-header-line-on))))
** Color Theme
Use =rainbow-mode= to edit colorful color string and symbol. In the beginning, I add ~:hook prog-mode~, that means to enable ~rainbow-mode~ for all programming mode, but later, I find that ~#def~ part of ~#define~ in C is changed to gray color. Then I remove the this hook. So I will turn on ~rainbow-mode~ manually, if I want to see the color.
(use-package rainbow-mode :diminish rainbow-mode)
Rainbow-delimiters is a "rainbow parentheses"-like mode which highlights parentheses, brackets, and braces according to their depth.
(use-package rainbow-delimiters :diminish rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode))
Toggle Font-Lock mode in all buffers.
(use-package font-lock :ensure nil :custom ((font-lock-maximum-decoration t) (font-lock-global-modes '(not shell-mode text-mode)) (font-lock-verbose t)) :config (global-font-lock-mode 1))
Use kimim-light as default theme.
(use-package hippo-themes :ensure nil :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/emacs-hippo-theme")) :custom (;; do not warning when load new theme (custom-safe-themes t)))
** Image
Always set white background color for transparent images to display clearly in dark color theme.
(use-package image :ensure nil :config (setq auto-mode-alist (append '(("\.svg\'" . image-mode)) auto-mode-alist)) (defun create-image-advice (im) (when im ;; only add property when im is non-nil (nconc im (list :background "#f8f8f8")))) (advice-add 'create-image :filter-return #'create-image-advice))
** posframe
(use-package posframe)
** Other Visual Element
(setq inhibit-startup-message t) (setq initial-scratch-message nil) (setq visible-bell t) (setq ring-bell-function #'ignore) (fset 'yes-or-no-p 'y-or-n-p) (show-paren-mode 1) (setq blink-cursor-blinks 3) (blink-cursor-mode 1) (tooltip-mode -1) ;; mark highlight in other windows also (setq highlight-nonselected-windows nil)
(use-package hi-lock :custom (hi-lock-auto-select-face t))
In Windows environment, =kimim/xterm= and =kimim/dc= will look up the program from system PATH, so you should set these to system PATH.
(use-package kimim
:load-path (lambda ()
(concat kimim/path-kimim-emacs
"site-lisp"))
:ensure nil
:commands (kimim/mail-setup
kimim/open-external
kimim/open-external-pdf)
:defines (mac-option-modifier
mac-command-modifier)
:bind
(("
(use-package info :commands (info) :hook (Info-mode . (lambda () (setq line-spacing 0.5))) :config (add-to-list 'Info-additional-directory-list (concat kimim/path-root "usr/share/info")) (add-to-list 'Info-additional-directory-list (concat kimim/path-root "usr/local/share/info")) (add-to-list 'Info-additional-directory-list (concat kimim/path-root "ucrt64/share/info")) ;; additional info, collected from internet (add-to-list 'Info-additional-directory-list "~/info"))
** Youdao dictionary
Search dictionary with Ctrl+F3 by youdao dictionary.
(use-package youdao-dictionary
:bind (
("C-x m 1" . youdao-dictionary-search-at-point-posframe)
("C-x m 2" . youdao-dictionary-search)
:map youdao-dictionary-mode-map
("C-y" . youdao-dictionary-search-yanked)
("
(defun youdao-dictionary-def-copied () (interactive) (youdao-dictionary-search (gui-get-selection))) (defun youdao-dictionary-search-yanked () (interactive) (youdao-dictionary-search (if (gui-get-selection) (gui-get-selection) (car kill-ring)))))
** sdcv
A local dictionary tool is useful when network connection has problems. You can get dictionary files from [[https://github.com/manateelazycat/lazycat-emacs/tree/master/site-lisp/sdcv-dict][lazycat-emacs]], or [[http://download.huzheng.org/dict.org/][huzheng.org]].
(use-package sdcv :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/sdcv")) :bind ("C-M-z" . sdcv-search-input) ("C-x m ," . sdcv-search-pointer) ("C-`" . sdcv-search-pointer+) :config (require 'sdcv) (setq sdcv-program "sdcv") (setq sdcv-say-word-p t) ;; set your local dictionaries path (setq sdcv-dictionary-data-dir (file-truename (concat kimim/path-kimim-emacs "site-lisp/sdcv-dict"))) (setq sdcv-dictionary-simple-list '("lazyworm-zh-en" "lazyworm-en-zh")) (setq sdcv-dictionary-complete-list '("oxford" "lazyworm-en-zh" "lazyworm-zh-en" "xdict-en-zh" "xdict-zh-en" "stardict-en-zh" "WordNet" "Jargon" "langdao-zh-en" "cdict-en-zh" "georges-de-lat" "georges-lat-de" "etymonline")) (defun kimim/sdcv-call-process-advice (orig-fun &rest args) (let ((default-process-coding-system '(utf-8 . utf-8))) (apply orig-fun args)))
(advice-add 'sdcv-call-process :around
Need to install ~mpg123~ or ~mpv~ to play the pronunciations.
pacman -S mingw-w64-ucrt-x86_64-mpg123
** fanyi.el
A translator extension written by [[https://condy0919.github.io][Youmu]].
I added ~kimim/fanyi-dwim-add-sdcv~ as ~:after~ advice for ~fanyi-dwim~ to look up local dictionary with help from ~sdcv~.
(use-package fanyi
:ensure t
:bind
(("C-x m ." . kimim/fanyi-dwim)
("C-x m y" . kimim/fanyi-current-kill))
:custom-face
(fanyi-word-face
((t :height 1.1 :weight bold :foreground "dark cyan")))
:custom
(fanyi-providers '(;; 海词
fanyi-haici-provider
;; 有道同义词词典
fanyi-youdao-thesaurus-provider
;; Etymonline
fanyi-etymon-provider
;; Longman
fanyi-longman-provider))
:bind (:map fanyi-mode-map
("n" . outline-next-visible-heading)
("p" . outline-previous-visible-heading)
("o" . other-window)
("
(defun kimim/fanyi-dwim () (interactive) (if-let ((word (thing-at-point 'word))) (progn (fanyi-dwim word) (cl-pushnew word fanyi-history)) (call-interactively #'fanyi-dwim)))
(defun kimim/fanyi-current-kill () (interactive) (fanyi-dwim (current-kill 0)))
(defun kimim/sdcv-translate-result-advice (word dictionary-list) (let* ((arguments (cons word (mapcan (lambda (d) (list "-u" d)) dictionary-list))) (result (mapconcat (lambda (result) (let-alist result (format "## %s\n%s\n\n" .dict .definition))) (apply #'sdcv-call-process arguments) ""))) (if (string-empty-p result) sdcv-fail-notify-string result)))
(advice-add 'sdcv-translate-result :override
(defun kimim/fanyi-dwim-add-sdcv (word) (let ((buf (get-buffer fanyi-buffer-name))) (with-current-buffer buf (let ((inhibit-read-only t) (inhibit-point-motion-hooks t)) ;; Clear the previous search result. (point-max) (insert "# SDCV\n\n") (insert (sdcv-search-with-dictionary word sdcv-dictionary-complete-list)) (insert "\n\n") (beginning-of-buffer) ;;(window-resize nil (- 35 (window-size nil t)) t) ))))
(advice-add 'fanyi-dwim :after
** Wordreference
(use-package wordreference :commands (wordreference-search kimim/wr-fren kimim/wr-enfr kimim/wr-deen kimim/wr-ende kimim/wr-sven kimim/wr-ensv) :config (defun kimim/wr-ende () (interactive) (let ((wordreference-source-lang "en") (wordreference-target-lang "de")) (wordreference-search)))
(defun kimim/wr-ensv () (interactive) (let ((wordreference-source-lang "en") (wordreference-target-lang "sv")) (wordreference-search)))
(defun kimim/wr-enfr () (interactive) (let ((wordreference-source-lang "en") (wordreference-target-lang "fr")) (wordreference-search)))
(defun kimim/wr-deen () (interactive) (let ((wordreference-source-lang "de") (wordreference-target-lang "en")) (wordreference-search)))
(defun kimim/wr-sven () (interactive) (let ((wordreference-source-lang "sv") (wordreference-target-lang "en")) (wordreference-search)))
(defun kimim/wr-fren () (interactive) (let ((wordreference-source-lang "fr") (wordreference-target-lang "en")) (wordreference-search))))
** dict.leo.org Translate word between English and German.
(use-package leo :bind (:map leo-mode-map ("s" . leo-translate-word)) :custom-face (leo-auxiliary-face ((t :inherit default))) (leo-match-face ((t :inherit font-lock-keyword-face))) (leo-link-face ((t :inherit font-lock-keyword-face :foreground "tomato"))))
** reverso Translate between almost any languages.
(use-package reverso :commands (reverso reverso-translate))
** eldoc-box
Show eldoc in a childframe box.
(use-package eldoc-box :diminish eldoc-box-hover-mode ;;:hook (eglot-managed-mode . eldoc-box-hover-mode) :custom ((eldoc-box-offset '(10 40 10)) (eldoc-box-max-pixel-width 1200) (eldoc-box-max-pixel-height 800)))
Increase right margin from default 16 to 40 to remove some overlap.
(use-package rime :bind (:map rime-mode-map ("C-|" . rime-force-enable) :map rime-active-mode-map ("C-h" . rime--backspace) ("M-h" . rime--backspace)) :custom (default-input-method "rime") (rime-title "Ѱ") (rime-disable-predicates '(kimim/rime-predicate-p)) (rime-show-candidate 'posframe) (rime-posframe-properties (list :internal-border-width 14)) :config
(when (eq (window-system) 'mac) (setq rime-librime-root "~/.emacs.d/librime/dist"))
(defun kimim/rime-predicate-space-after-ascii-p () "If cursor is after only ONE whitespace which follow a ascii character." (and (> (point) (save-excursion (back-to-indentation) (point))) (let ((string (buffer-substring (point) (max (line-beginning-position) (- (point) 80))))) (and (string-match-p " $" string) ;; -+* bullet items (not (string-match-p "[\x2a\x2b\x2d] $" string)) (not (string-match-p "\cc +$" string)) (not (string-match-p " $" string))))))
(defun kimim/rime-predicate-current-input-punctuation-p () "If the current charactor entered is a punctuation." (and rime--current-input-key (or (and (<= #x21 rime--current-input-key) (<= rime--current-input-key #x2c)) (= rime--current-input-key #x2e) (and (<= #x3a rime--current-input-key) (<= rime--current-input-key #x40)) (and (<= #x5b rime--current-input-key) (<= rime--current-input-key #x5e)) (and (<= #x7b rime--current-input-key) (<= rime--current-input-key #x7f)))))
(defun kimim/rime-predicate-p () "Always use rime punctuation." (if (kimim/rime-predicate-current-input-punctuation-p) nil (or (rime-predicate-current-uppercase-letter-p) (rime-predicate-space-after-cc-p) (rime-predicate-after-ascii-char-p) (kimim/rime-predicate-space-after-ascii-p)))))
** sis Emacs smart input source ([[https://github.com/laishulu/emacs-smart-input-source][sis]]) can automatically switch input method for buffers and contexts.
When sis is enabled, =C-x C-c= a emacs client frame will crash, so, add an advice to disable sis when ~save-buffers-kill-terminal~.
By the way, you need to use =C-
(use-package sis :functions (kimim/sis-enable kimim/sis-disable) :hook (server-after-make-frame . kimim/sis-enable) :config (set-face-attribute 'sis-inline-face nil :foreground (face-attribute 'font-lock-constant-face :foreground) :underline t :inverse-video 'unspecified) (setq sis-other-cursor-color "tomato") (cond ((eq system-type 'windows-nt) (sis-ism-lazyman-config nil t 'w32)) ((eq system-type 'darwin) (sis-ism-lazyman-config "com.apple.keylayout.ABC" "im.rime.inputmethod.Squirrel.Hans")))
(defun kimim/sis-enable () ;; enable the /cursor color/ mode (sis-global-cursor-color-mode t) ;; enable the /respect/ mode (sis-global-respect-mode t) ;; enable the /context/ mode for all buffers (sis-global-context-mode t) ;; enable the /inline english/ mode for all buffers (sis-global-inline-mode t))
(defun kimim/sis-disable () (sis-global-cursor-color-mode -1) (sis-global-respect-mode -1) (sis-global-context-mode -1) (sis-global-inline-mode -1))
(advice-add 'save-buffers-kill-terminal :before (lambda (&optional arg) (if (eq 1 (length server-clients)) (kimim/sis-disable)))) (add-hook 'server-after-make-frame-hook 'kimim/sis-enable))
** General
(use-package autorevert :ensure nil :diminish auto-revert-mode)
(setq inhibit-eol-conversion nil) (setq-default fill-column 70) ;; see discussion https://emacs-china.org/t/topic/2616/30 (setq word-wrap-by-category t) (setq require-final-newline t)
(use-package drag-stuff :diminish drag-stuff-mode :config (drag-stuff-global-mode 1))
(delete-selection-mode 1) (setq kill-ring-max 200) (setq kill-whole-line t) (setq-default tab-width 4) (setq tab-stop-list (number-sequence 4 120 4)) ;; stretch to tab width when on tab (setq x-stretch-cursor t) (setq track-eol t) (setq backup-directory-alist '(("." . "~/temp"))) (setq version-control t) (setq kept-old-versions 10) (setq kept-new-versions 20) (setq delete-old-versions t) (setq backup-by-copying t)
(setq auto-save-interval 50) (setq auto-save-timeout 60) (setq auto-save-default nil) (setq auto-save-list-file-prefix "~/temp/auto-saves-") (setq auto-save-file-name-transforms `((".*" , "~/temp/"))) (setq create-lockfiles nil)
(use-package time-stamp :config (setq time-stamp-active t) (setq time-stamp-warn-inactive t) (setq time-stamp-format "%:y-%02m-%02d %3a %02H:%02M:%02S Kimi MA") (add-hook 'write-file-functions 'time-stamp))
(defun kimim/save-buffer-advice (orig-fun &rest arg) (when (not (memq major-mode '(org-mode markdown-mode text-mode))) (delete-trailing-whitespace)) (apply orig-fun arg))
(advice-add 'save-buffer :around #'kimim/save-buffer-advice) (setq save-silently t)
(diminish 'visual-line-mode) (add-hook 'text-mode-hook (lambda () (when (derived-mode-p 'org-mode 'markdown-mode 'text-mode 'info-mode) (visual-line-mode) (setq line-spacing 0.4)))) (setq-default indent-tabs-mode nil)
(setq uniquify-buffer-name-style 'forward) (setq suggest-key-bindings 5)
(add-to-list 'auto-mode-alist '("\.css\'" . css-mode)) (add-to-list 'auto-mode-alist '("\.S\'" . asm-mode)) (add-to-list 'auto-mode-alist '("\.pas\'" . delphi-mode))
(require 'saveplace) (setq-default save-place t) (setq save-place-file (expand-file-name "saveplace" "~"))
** multi cursors
You can mark a region, and ~C-S-c C-S-c~ to start edit every line in this region. That's amazing.
(use-package multiple-cursors :bind ("C-S-c C-S-c" . mc/edit-lines) ("C->" . mc/mark-next-like-this) ("C-<" . mc/mark-previous-like-this) ("C-c C-<" . mc/mark-all-like-this) ("C-c C->" . mc/mark-all-dwim))
** Highlight
Highlight current line in window systems, but disable this in terminal. Because the line highlight will cause the terminal blinking.
(use-package hl-line :if window-system :config (global-hl-line-mode -1))
** pulsar
Frequently, you may lose your point in multiple windows. ~pulsar~ can show a transient highlight line for you to find your point after specified functions.
(use-package pulsar :defer 5 :custom (pulsar-pulse t) (pulsar-face 'pulsar-green) (pulsar-highlight-face 'pulsar-yellow) :config (setq pulsar-pulse-functions '(recenter-top-bottom move-to-window-line-top-bottom reposition-window bookmark-jump consult-bookmark other-window delete-window delete-other-windows forward-page backward-page scroll-up-command scroll-down-command windmove-right windmove-left windmove-up windmove-down windmove-swap-states-right windmove-swap-states-left windmove-swap-states-up windmove-swap-states-down org-next-visible-heading org-previous-visible-heading org-forward-heading-same-level org-backward-heading-same-level org-agenda-goto markdown-next-visible-heading markdown-previous-visible-heading markdown-forward-heading-same-level markdown-backward-heading-same-level markdown-outline-next-same-level markdown-outline-previous-same-level outline-backward-same-level outline-forward-same-level outline-next-visible-heading outline-previous-visible-heading outline-up-heading ace-window xref-find-definitions xref-go-back)) (advice-add 'switch-to-buffer :after (lambda ( &optional _) (pulsar-pulse-line))) ;; turn on visual line, pulsar will high light only visual line, but ;; this mode will mess up some buffer, such as org agenda. ;; (global-visual-line-mode) (pulsar-global-mode 1))
** ispell
[[https://git.savannah.gnu.org/cgit/emacs.git/tree/etc/NEWS.26#n1155][Emacs 26]] supports Enchant, which is a meta-spell-checker that uses providers such as Hunspell to do the actual checking. With it, users can use spell-checkers not directly supported by Emacs, such as Voikko, Hspell and AppleSpell, more easily share personal word-lists with other programs, and configure different spelling-checkers for different languages.
The benefit is that you can use the same personal word-lists for different spell checkers in Windows, Linux or macOS.
I get this idea from [[https://github.com/Eason0210][Eason0210]] at [[https://emacs-china.org/t/emacs-enchant-spell-checker/24035][Emacs China]] on [2023-07-02 Sun].
Install ~enchant~.
Windows/msys64:
pacman -S mingw64/mingw-w64-x86_64-enchant
macOS
sudo port install enchant2
brew install enchant
Add ~ENCHANT_CONFIG_DIR~ to your ~.bashrc~, if you want to keep enchant settings in your home folder. Otherwise, it keeps personal dictionary at ~Local Settings~. see [[https://abiword.github.io/enchant/src/enchant.html][enchant manual]].
export ENCHANT_CONFIG_DIR=~/.config/enchant/
(use-package ispell :custom ;; enchant-2 becomes very slow in Windows 11 (ispell-program-name "hunspell") (ispell-silently-savep t) :config (cond ((eq system-type 'windows-nt) (setq ispell-alternate-dictionary "~/.emacs.d/dict/words.txt"))) ;; remove minibuffer message "Starting look.exe process ...", ;; which is annoying (advice-add 'ispell-lookup-words :around (lambda (orig-fun &rest args) (advice-add 'message :override (lambda (format-string &rest args) "")) (let ((result (apply orig-fun args))) (advice-remove 'message (lambda (format-string &rest args) "")) result))))
** flyspell
Check spell on the fly.
(use-package flyspell :diminish flyspell-mode :hook (;;(prog-mode . flyspell-prog-mode) (org-mode . flyspell-mode)))
** olivetti
(use-package olivetti
:diminish olivetti-mode
:custom
(olivetti-body-width (+ fill-column 10))
:hook ((elfeed-show-mode
eww-mode
Info-mode
woman-mode
fanyi-mode)
. olivetti-mode)
:config
(add-hook 'cnfonts-set-font-finish-hook
(lambda (args)
(let ((frame-width ( (+ fill-column 7)
(frame-char-width))))
(setq org-image-actual-width (,frame-width)) (setq markdown-max-image-size
(,frame-width . ,( 2 frame-width)))
(when (bound-and-true-p org-inline-image-overlays)
(org-redisplay-inline-images))
(when (bound-and-true-p markdown-inline-image-overlays)
(markdown-remove-inline-images)
(markdown-display-inline-images))))))
** Chinese word segmentation
(use-package cns :after text-mode :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/cns")) :hook (text-mode . cns-mode) :bind ((:map cns-mode-map) ("M-h" . cns-backward-kill-word)) :config (setq cns-process-buffer "cns") (setq cns-prog (cond ((eq system-type 'windows-nt) (concat kimim/path-kimim-emacs "site-lisp/cns/cnws.exe")) ((eq system-type 'darwin) (concat kimim/path-kimim-emacs "site-lisp/cns/cnws")))) (setq cns-dict-directory (concat kimim/path-kimim-emacs "site-lisp/cns/cppjieba/dict")) (setq cns-process-shell-command (format "%s %s" cns-prog (cns-set-prog-args cns-dict-directory))) (setq cns-recent-segmentation-limit 20) ; default is 10 (setq cns-debug nil))
** wraplish
Automatically add space between Chinese and English, and more.
(use-package wraplish :commands wraplish-mode :after text-mode :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/wraplish")))
Before enable wraplish, you need to install python, pip and epc.
pacman -S mingw-w64-x86_64-python mingw-w64-x86_64-python3-pip pip install epc
** tempel
Use ~tempel~ to expand template.
;; Configure Tempel
(use-package tempel
:bind (("M-+" . tempel-complete)
("M-=" . tempel-complete)
("M-*" . tempel-insert)
:map tempel-map
("M-RET" . tempel-done)
("S-
(use-package tempel-collection)
By enabling ~winner-mode~, you can restore to previous window
configuration by typing ~C-c M-
(use-package winner
;; restore windows configuration, built-in package
:commands winner-mode
:bind
("C-x M-
When type ~C-x m w~ it will create a new frame with the default frame configuration.
(use-package frame :ensure nil :defer 1 :bind ("C-x m w" . make-frame))
preserve the point in screen during scrolling looks nice (see [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Scrolling.html][scrolling]]). scroll slowly with touchpad, thus we adjust the scroll amount.
(setq scroll-preserve-screen-position t) (setq mouse-wheel-scroll-amount '(0.01))
** Move Frame
Move frame to one of the nine grids on the screen with ~C-x y
(use-package nine-grid :diminish nine-grid-minor-mode :commands (nine-grid) :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/nine-grid")) :bind (("C-c 5 1" . (lambda () (interactive) (nine-grid 1))) ("C-c 5 2" . (lambda () (interactive) (nine-grid 2))) ("C-c 5 3" . (lambda () (interactive) (nine-grid 3))) ("C-c 5 4" . (lambda () (interactive) (nine-grid 4))) ("C-c 5 5" . (lambda () (interactive) (nine-grid 5))) ("C-c 5 6" . (lambda () (interactive) (nine-grid 6))) ("C-c 5 7" . (lambda () (interactive) (nine-grid 7))) ("C-c 5 8" . (lambda () (interactive) (nine-grid 8))) ("C-c 5 9" . (lambda () (interactive) (nine-grid 9)))) :config (require 'nine-grid) (nine-grid-mode))
** Windmove
(use-package windmove
:bind
("C-x
** Command
Display key candidates when you typed part key prefix with ~which-key-mode~.
;; https://github.com/justbur/emacs-which-key (use-package which-key :defer 3 :diminish which-key-mode :custom (which-key-popup-type 'side-window) :config (which-key-mode 1))
List recent used commands with ~smex~:
;; smex will list the recent function on top of the cmd list (use-package smex :commands (smex) :config (smex-initialize))
** Key Frequency
We will use =keyfreq= to record the frequency of the key typing, and get a frequency report by =M-x keyfreq-show=.
(use-package keyfreq :custom (keyfreq-file "~/.emacs.d/emacs.keyfreq") :config (keyfreq-mode +1) (keyfreq-autosave-mode +1))
** eshell
(use-package eshell)
** Navigation
(use-package bookmark :custom (bookmark-default-file "~/.emacs.d/emacs.bmk") (bookmark-save-flag 1) (bookmark-fontify nil) :config (add-hook 'bookmark-after-jump-hook (lambda () (recenter 'top))))
~bm~ is used to temporally toggle buffer local bookmarks with ~C-x m t~, then you can view all the local temporally bookmarks with ~C-x m s~.
(use-package bm
:bind (("C-x m t" . bm-toggle)
("C-x m s" . bm-show-all)
("C-x m
You can jump to any character by triggering ~ace-jump-mode~ (~C-x m c~), and jump to any window by triggering ~ace-window~ (~C-x m w~).
(use-package ace-window :bind (("C-x o" . other-window) ("M-o" . ace-window) ("C-x m w" . ace-swap-window) ("C-x m x" . ace-delete-window)) :custom (aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))
** vundo
(use-package vundo :bind ("C-x u" . vundo))
Emacs default ~isearch~ does not allow key binding in minibuffer, ~isearch-mb~ enhances at this aspect.
(use-package isearch-mb :defer 1 :bind (:map isearch-mb-minibuffer-map ("C-l" . recenter-other-window) ("C-n" . isearch-repeat-forward) ("C-p" . isearch-repeat-backward) ("C-." . (lambda () (interactive) (isearch-exit) (sdcv-search-pointer+)))) :custom (isearch-repeat-on-direction-change t) ;; Show match count next to the minibuffer prompt (isearch-lazy-count t) ;; Don't be stingy with history; default is to keep just 16 entries (search-ring-max 200) (search-invisible nil) (regexp-search-ring-max 200) :config (add-hook 'isearch-mode-hook #'display-line-numbers-mode) (add-hook 'isearch-mode-end-hook (lambda () (display-line-numbers-mode -1))) (defun isearch-mb--update-prompt (&rest _) "Update the minibuffer prompt according to search status." (when isearch-mb--prompt-overlay (let ((count (isearch-lazy-count-format)) (len (or (overlay-get isearch-mb--prompt-overlay 'isearch-mb--len) 0))) (overlay-put isearch-mb--prompt-overlay 'isearch-mb--len (max len (length count))) (overlay-put isearch-mb--prompt-overlay 'before-string (concat count ;; Count is padded so that it only grows. (make-string (max 0 (- len (length count))) ?\ ) (capitalize (or (isearch--describe-regexp-mode isearch-regexp-function) ""))))))) (isearch-mb-mode))
** imenu & imenu-anywhere
=imenu= is used to navigate the function definitions in current buffer.
(use-package imenu :functions kimim/imenu-default-goto-function-advice :bind ("C-x i" . imenu) :config (advice-add 'imenu-default-goto-function :around
(use-package imenu-anywhere :bind ("C-x m i" . imenu-anywhere))
** ripgrep: a fast command line search tool
(use-package ripgrep :bind ("C-x g" . ripgrep-regexp))
** search from web
(use-package eww :custom (eww-search-prefix "https://cn.bing.com/search?q="))
** recentf
(use-package recentf :config (recentf-mode))
** avy
(use-package avy :bind ("C-x m g" . avy-goto-word-or-subword-1))
To avoid accidentally delete files, let emacs move the deleted file to trash.
(setq delete-by-moving-to-trash t)
** dired
(use-package dired
:ensure nil
:defines (dired-omit-localp
dired-omit-files)
:functions (dired-omit-mode
dired-dwim-target-directory
kimim/drawio-to)
:custom
(dired-listing-switches "-AGhlgov")
(dired-recursive-copies t)
(dired-recursive-deletes t)
(ls-lisp-dirs-first t)
(dired-create-destination-dirs 'ask)
(dired-dwim-target t)
:bind
(("C-x C-j" . dired-jump)
:map dired-mode-map
("C-c l" . kimim/dired-get-org-link)
("
(defun compose-attach-marked-files () "Compose mail and attach all the marked files from a dired buffer." (interactive) (let ((files (dired-get-marked-files)) (file-names (dired-copy-filename-as-kill))) (compose-mail nil (concat "Attachments: " file-names) nil t) (dolist (file files) (if (file-regular-p file) (mml-attach-file file (mm-default-file-type file) nil "attachment") (message "skipping non-regular file %s" file)))))
(defadvice dired-next-line (after dired-next-line-advice (arg) activate) "Move down lines then position at filename, advice" (interactive "p") (if (eobp) (progn (goto-char (point-min)) (forward-line 1) (dired-move-to-filename))))
(defadvice dired-previous-line (before dired-previous-line-advice (arg) activate) "Move up lines then position at filename, advice" (interactive "p") (if (= 2 (line-number-at-pos)) (goto-char (point-max))))
(defun kimim/dired-other-window () (interactive) (let ((other-dired-buffer (dired-dwim-target-directory))) (if other-dired-buffer (dired-other-window other-dired-buffer) (dired-jump-other-window))))
(defun kimim/dired-get-org-link () "get a link from dired for org" (interactive) (let ((filename (dired-get-filename))) (kill-new (concat "[[" (concat "~/" (file-relative-name filename "~")) "][" (file-name-nondirectory filename) "]]"))))
(defun kimim/open-with-inkscape () (interactive) (let* ((filename (dired-get-filename))) (cond ((string-equal system-type "windows-nt") (w32-shell-execute "open" "inkscape" filename)) ((string-equal system-type "darwin") (start-process "" nil "open" "-a" "inkscape" filename)) ((string-equal system-type "gnu/linux") (start-process "" nil "xdg-open" "inkscape" filename)) ((string-equal system-type "cygwin") (start-process "" nil "xdg-open" "inkscape" filename)))))
(defun kimim/pdf2svg () (interactive) (let* ((filename (dired-get-filename)) (exportname (replace-regexp-in-string ".pdf$" ".svg" filename)) (counter 10)) (w32-shell-execute "open" "inkscape" (format "--export-filename=\"%s\" \"%s\"" exportname filename)) (while (and (not (file-exists-p exportname)) (> counter 0)) ; true-or-false-test (sleep-for 1) (setq counter (1- counter))) (dired-revert)))
(defun kimim/drawio-to (ext) (let* ((filename (dired-get-filename)) (exportname (replace-regexp-in-string "drawio$" ext filename)) (counter 10)) (w32-shell-execute "open" (concat (getenv "MSYS64_PATH") "\kimikit\draw.io\draw.io.exe") (format "--crop -b 5 -x \"%s\" -o \"%s\"" filename exportname)) (while (and (not (file-exists-p exportname)) (> counter 0)) ; true-or-false-test (sleep-for 1) (setq counter (1- counter))) (dired-revert)))
(defun kimim/drawio2png () (interactive) (kimim/drawio-to "png"))
(defun kimim/drawio2svg () (interactive) (kimim/drawio-to "svg"))
(defun kimim/drawio2pdf () (interactive) (kimim/drawio-to "pdf")))
** dired-recent
Keep a list of recently visited directories. Then we can quickly revisit them.
(use-package dired-recent :config (dired-recent-mode 1))
** dired-efap
dired-efap, Edit file at point, can be used to rename file name at the point:
(use-package dired-efap :commands dired-efap)
** dired-narrow
~M-n~ will prompt for strings to narrow the files in current dired buffer.
(use-package dired-narrow :commands dired-narrow)
** dired-filter
(use-package dired-filter :diminish dired-filter-mode)
** ibuffer
~M-o~ is bound to ~ibuffer-visit-buffer-1-window~ to visit the buffer on this line, and delete other windows. This conflicts with global key binding to ~ace-window~. Unbind ~M-o~ from ~ibuffer-mode-map~.
(use-package ibuffer
:bind (("C-x C-b" . ibuffer-other-window)
:map ibuffer-mode-map
("
(use-package marginalia :init (marginalia-mode))
** consult
(use-package consult
:defines (xref-show-xrefs-function
xref-show-definitions-function)
:bind (;; C-c bindings (mode-specific-map)
("C-c h" . consult-history)
("C-c m" . consult-mode-command)
("C-c k" . consult-kmacro)
;; C-x bindings (ctl-x-map)
("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
("C-x b" . consult-buffer) ;; orig. switch-to-buffer
("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
("C-x M-b" . consult-buffer-other-window)
("C-x m j" . consult-bookmark) ;; orig. bookmark-jump
("C-x m v" . find-variable)
("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
;; Custom M-# bindings for fast register access
("M-#" . consult-register-load)
("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
("C-M-#" . consult-register)
;; Other custom bindings
("M-y" . consult-yank-pop) ;; orig. yank-pop
("
;; Enable automatic preview at point in the Completions buffer. This is ;; relevant when you use the default completion UI. ;;:hook (completion-list-mode . consult-preview-at-point-mode)
;; The :init configuration is always executed (Not lazy)
:init
(global-set-key [remap repeat-complex-command] #'consult-complex-command)
(use-package recentf)
;; Optionally configure the register formatting. This improves the register
;; preview for consult-register',
consult-register-load',
;; `consult-register-store' and the Emacs built-ins.
(setq register-preview-delay 0.5
register-preview-function #'consult-register-format)
;; Optionally tweak the register preview window. ;; This adds thin lines, sorting and hides the mode line of the window. (advice-add #'register-preview :override #'consult-register-window)
;; Use Consult to select xref locations with preview (setq xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref)
;; Configure other variables and modes in the :config section, ;; after lazily loading the package. :config
(defun kimim/consult-ripgrep-current () (interactive) (consult-ripgrep "."))
;; Optionally configure preview. The default value
;; is 'any, such that any key triggers the preview.
;; (setq consult-preview-key '(:debounce 1.5 any))
;; (setq consult-preview-key 'any)
;; (setq consult-preview-key "M-.")
;; (setq consult-preview-key (list "
;; Optionally configure the narrowing key. ;; Both < and C-+ work reasonably well. (setq consult-narrow-key "<") )
;; Enable vertico (use-package vertico :init (vertico-mode)
;; Different scroll margin ;; (setq vertico-scroll-margin 0)
;; Show more candidates ;; (setq vertico-count 20)
;; Grow and shrink the Vertico minibuffer ;; (setq vertico-resize t)
;; Optionally enable cycling for vertico-next' and
vertico-previous'.
;; (setq vertico-cycle t)
)
(use-package orderless :init (setq completion-styles '(orderless) completion-category-defaults nil completion-category-overrides '((file (styles partial-completion)))))
;; Persist history over Emacs restarts. Vertico sorts by history position. (use-package savehist :init (savehist-mode))
;; A few more useful configurations...
(use-package emacs
:init
;; Add prompt indicator to completing-read-multiple'. ;; Alternatively try
consult-completing-read-multiple'.
(defun crm-indicator (args)
(cons (concat "[CRM] " (car args)) (cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
;; Do not allow the cursor in the minibuffer prompt (setq minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt)) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
;; Emacs 28: Hide commands in M-x which do not work in the current mode. ;; Vertico commands are hidden in normal buffers. ;; (setq read-extended-command-predicate ;; #'command-completion-default-include-p)
;; Enable recursive minibuffers (setq enable-recursive-minibuffers t))
** abbrev
(diminish 'abbrev-mode)
** corfu
(use-package emacs :init ;; TAB cycle if there are only few candidates (setq completion-cycle-threshold 2)
;; Enable indentation+completion using the TAB key. ;; `completion-at-point' is often bound to M-TAB. (setq tab-always-indent t))
(use-package corfu
:defer 1
:bind
(:map
corfu-map
("
(use-package corfu-prescient :commands (corfu-prescient-mode) :config (setq corfu-prescient-override-sorting t))
** cape
(use-package cape
:init
;; Add completion-at-point-functions', used by
completion-at-point'.
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
(add-to-list 'completion-at-point-functions #'cape-elisp-symbol)
:custom
(cape-dabbrev-check-other-buffers nil)
(cape-dict-grep nil)
(cape-dict-file
(concat kimim/path-kimim-emacs
"site-lisp/english-words/words_alpha.txt"))
:hook
(emacs-lisp-mode
.
(lambda ()
(setq-local
completion-at-point-functions
(list
(cape-capf-super
#'cape-elisp-symbol
;;#'cape-yasnippet
#'cape-dabbrev)))))
((text-mode org-mode markdown-mode) . (lambda () (setq-local completion-at-point-functions (list (cape-capf-super
#'cape-dabbrev
#'cape-dict
;;#'cape-yasnippet
)))))
(plantuml-mode . (lambda () (setq-local completion-at-point-functions (list (cape-capf-super ;;#'cape-yasnippet
(eshell-mode . (lambda () (setq-local corfu-auto nil) (corfu-mode))) :config (defvar cape--dict-all-words nil) (defvar cape-dict-limit 100) (defun kimim/cape--dict-list (input) "Return all words from `cape-dict-file' matching INPUT without grep." (unless (equal input "") (let* ((inhibit-message t) (message-log-max nil) (files (ensure-list (if (functionp cape-dict-file) (funcall cape-dict-file) cape-dict-file))) (_ (unless cape--dict-all-words (setq cape--dict-all-words (split-string (with-temp-buffer (mapc #'insert-file-contents files) (buffer-string)) "\n" 'omit-nulls)))) (words (let ((completion-ignore-case t) (completion-regexp-list (list (regexp-quote input)))) (all-completions "" cape--dict-all-words)))) (cons (apply-partially (if (and cape-dict-limit (length= words cape-dict-limit))
input)
(cape--case-replace-list cape-dict-case-replace input words)))))
(advice-add 'cape--dict-list :override #'kimim/cape--dict-list))
~project-find-file~ (~C-x p f~) can find files of current project, indicated by git or other version control information.
(use-package project :bind (("C-x p r" . project-find-ripgrep-regexp) ("C-x p s" . kimim/magit-stage-file)) :functions (magit-stage-1 magit-with-toplevel magit-untracked-files magit-unstaged-files magit-file-relative-name project--read-regexp) :config (require 'magit) (defun project-find-ripgrep-regexp (regexp) "Find all matches for REGEXP in the current project's roots." (interactive (list (project--read-regexp))) (require 'ripgrep) (let* ((caller-dir default-directory) (pr (project-current t)) (default-directory (project-root pr)) (dir (if (not current-prefix-arg) default-directory (read-directory-name "Base directory: " caller-dir nil t)))) (ripgrep-regexp regexp dir)))
(defun kimim/magit-stage-file () (interactive) (let* ((current (magit-file-relative-name)) (choices (nconc (magit-unstaged-files) (magit-untracked-files))) (default (car (member current choices)))) (if default (magit-with-toplevel (magit-stage-1 nil (list default))) (message "Already staged")))))
** Compiling
(setq next-error-recenter 20)
(setq compilation-scroll-output t)
(bind-key "C-
** Version Control
Bind ~magit~ to ~C-x p m~ with the same prefix of ~project~, as they have strong relationship.
(use-package magit
:bind (("C-x p m" . magit-status-here)
(:map magit-revision-mode-map)
("C-
Following error will reported when using magit to commit changes:
server-ensure-safe-dir: The directory ‘~/.emacs.d/server’ is unsafe
The solution is to change the owner of =~/.emacs.d/server= [fn:9]
Click R-mouse on ~/.emacs.d/server and select “Properties” (last item in menu). From Properties select the Tab “Security” and then select the button “Advanced”. Then select the Tab “Owner” and change the owner from =“Administrators (\Administrators)”= into =“ (\”=. Now the server code will accept this directory as secure because you are the owner.
** Use tempel for LSP
(use-package lsp-snippet-tempel :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/lsp-snippet")) :config (when (featurep 'lsp-mode) ;; Initialize lsp-snippet -> tempel in lsp-mode (lsp-snippet-tempel-lsp-mode-init)) (when (featurep 'eglot) ;; Initialize lsp-snippet -> tempel in eglot (lsp-snippet-tempel-eglot-init)))
** LSP with Eglot
~eglot~ is simple and built-in LSP support in emacs.
(use-package eglot :bind (:map eglot-mode-map ("C-x l a" . eglot-code-actions) ("C-x l t" . eglot-find-typeDefinition) ("C-x l d" . eglot-find-declaration) ("C-x l i" . eglot-find-implementation) ("C-x l b" . eldoc) ("C-x l l" . eldoc-box-help-at-point)) :hook ((c-mode c++-mode rust-mode python-mode r-mode) . eglot-ensure) (eglot-managed-mode . kimim/eglot-completion) :config (require 'cape) (require 'lsp-snippet-tempel) (defun kimim/eglot-completion () (setf (alist-get 'styles (alist-get 'eglot completion-category-defaults)) '(orderless basic flex substring partial-completion)) (setq-local completion-at-point-functions (list (cape-capf-super
#'cape-dabbrev)))))
** Parenthesis
~smartparens-mode~[fn:10] is a general purpose mode for dealing with parenthesis. We define some keys for it:
(use-package smartparens
:bind (:map
smartparens-mode-map
("C-" nil :actions nil) ;; also only use the pseudo-quote inside strings where it ;; serves as hyperlink. (sp-local-pair "
" "'" :when '(sp-in-string-p sp-in-comment-p))))
** COMMENT parinfer-rust-mode
(use-package parinfer-rust-mode :commands parinfer-rust-mode :hook ((clojure-mode clojurec-mode clojurescript-mode) . parinfer-rust-mode))
** tree-sitter
(use-package tree-sitter-langs) (use-package tree-sitter :ensure nil :hook (((c-mode c++-mode clojure-mode rust-mode) . tree-sitter-mode) ((c-mode c++-mode clojure-mode rust-mode) . tree-sitter-hl-mode)) :config ;; assoc bb-mode to clojure (setq tree-sitter-major-mode-language-alist (put-alist 'bb-mode 'clojure tree-sitter-major-mode-language-alist)))
** ts-fold
(use-package ts-fold
:init
(use-package fringe-helper)
(require 'ts-fold)
:load-path (lambda ()
(concat kimim/path-kimim-emacs
"site-lisp/ts-fold"))
:bind ("C-
** COMMENT Code folding
With ~yafolding-mode~, you can:
(use-package yafolding :hook (prog-mode . yafolding-mode))
** static code analysis
(use-package flycheck :commands (global-flycheck-mode) :custom (flycheck-global-modes '(not org-mode)))
** eldoc
(use-package eldoc :hook (prog-mode . eldoc-mode) :diminish eldoc-mode :custom (eldoc-echo-area-use-multiline-p nil))
** cmake mode
(use-package cmake-mode :mode ("CMakeLists\.txt\'" . cmake-mode))
** xref
(use-package xref :ensure nil :custom (xref-after-return-hook '(xref-pulse-momentarily recenter)) :bind (:map prog-mode-map ("C-." . xref-find-references)))
(use-package clang-format)
(use-package ggtags :bind (:map ggtags-navigation-mode-map ("M-o" . other-window) ("M-<" . beginning-of-buffer) ("M->" . end-of-buffer)) :hook ((c-mode c++-mode) . ggtags-mode) :config ;; eglot use M-. for code navigation (unbind-key "M-." ggtags-mode-map) (setq ggtags-mode-line-project-name nil) (setq ggtags-global-ignore-case t) (setq ggtags-sort-by-nearness t))
(use-package cc-mode
:ensure nil
:custom (c-default-style
'((java-mode . "java")
(awk-mode . "awk")
(c-mode . "cc-mode")
(c++-mode . "stroustrup++")
(other . "k&r")))
:defines c++-mode-map
:bind (:map
c++-mode-map
("C-c-basic-offset' times 1 ;; -
c-basic-offset' times -1
;; ++ c-basic-offset' times 2 ;; --
c-basic-offset' times -2
;; * c-basic-offset' times 0.5 ;; /
c-basic-offset' times -0.5
(c-add-style "stroustrup++"
'("stroustrup"
(c-basic-offset . 4)
(c-offsets-alist
(topmost-intro . 0)
(inclass . +)
(innamespace . -)
(access-label . /)))))
(use-package ob-C :ensure nil :config (add-to-list 'org-src-lang-modes '("C" . c)) (add-to-list 'org-babel-load-languages '(C . t)))
(use-package hideif :hook ((c-mode c++-mode) . hide-ifdef-mode) :config (when (eq system-type 'gnu/linux) (add-to-list 'hide-ifdef-env '(linux . 1)) (add-to-list 'hide-ifdef-env '(GNUC . 11))) (when (eq system-type 'darwin) (add-to-list 'hide-ifdef-env '(APPLE . 1)) (add-to-list 'hide-ifdef-env '(clang . 1)) (add-to-list 'hide-ifdef-env '(llvm . 1))) (when (eq system-type 'windows-nt) (add-to-list 'hide-ifdef-env '(MINGW32 . 1)) (add-to-list 'hide-ifdef-env '(_WIN32 . 1)) (add-to-list 'hide-ifdef-env '(GNUC . 1))) :custom (hide-ifdef-initially nil) (hide-ifdef-shadow t))
** C#
(use-package csharp-mode :ensure nil :hook ((csharp-mode . tree-sitter-mode) (csharp-mode . tree-sitter-hl-mode)) :mode ("\.cs\'" . csharp-mode))
** Clojure
Clojure[fn:11] is a lisp over JVM. Emm, I like it.
(use-package clojure-mode :mode (("\.cljs\'" . clojurescript-mode) ("\.\(clj\|dtm\|edn\|bb\)\'" . clojure-mode) ("\.cljc\'" . clojurec-mode) ("\(?:build\|profile\)\.boot\'" . clojure-mode)) :config (require 'cider) (require 'flycheck) (require 'flycheck-clj-kondo) (require 'clojure-mode-extra-font-locking))
(use-package clojure-mode-extra-font-locking)
*** clj-kondo
Install with npm:
npm install -g clj-kondo
(use-package flycheck-clj-kondo)
*** Cider
Cider[fn:12] extends Emacs with support for interactive programming in Clojure.
(use-package cider :functions tramp-dissect-file-name :custom ((cider-clojure-cli-command "clojure") (nrepl-use-ssh-fallback-for-remote-hosts t) (nrepl-sync-request-timeout 100)) :config ;;(setq cider-interactive-eval-output-destination 'output-buffer) (defun nrepl--ssh-tunnel-command (ssh dir port) "Command string to open SSH tunnel to the host associated with DIR's PORT." (with-parsed-tramp-file-name dir v ;; this abuses the -v option for ssh to get output when the port ;; forwarding is set up, which is used to synchronise on, so that ;; the port forwarding is up when we try to connect. (format-spec "%s -v -N -L %p:localhost:%p %u'%h' %x" `((?s . ,ssh) (?p . ,port) (?h . ,v-host) (?u . ,(if v-user (format "-l '%s' " v-user) "")) (?x . "-o \"ProxyCommand=nc -X connect -x 127.0.0.1:1080 %h %p\""))))))
(use-package ob-clojure :ensure org :custom (org-babel-clojure-backend 'cider) :config (add-to-list 'org-src-lang-modes '("clojure" . clojure)))
** Babashka Download ~bb~ from https://github.com/babashka/babashka/releases and put ~bb~ to execute PATH.
(use-package ob-bb :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/ob-bb")))
** Python
Python development configuration is quite easy. =elpy= [fn:13] is used here:
;; (use-package elpy ;; :config ;; (elpy-enable))
(use-package python :ensure nil ;; :defines elpy-rpc-backend :mode ("\.py\'" . python-mode) :interpreter ("python" . python-mode) :config ;; (add-hook 'python-mode-hook ;; (lambda () ;; (setq yas-indent-line nil))) (add-to-list 'python-shell-completion-native-disabled-interpreters "python"))
;; (use-package company-jedi ;; :config ;; (setq elpy-rpc-backend "jedi"))
Following =python= package is required according to =elpy= mannual:
pip install rope pip install jedi
pip install flake8
pip install importmagic
pip install autopep8
pip install yapf
pip install virtualenv
** Rust
The easiest way to install rust is to run following script:
curl https://sh.rustup.rs -sSf | sh
(use-package rustic :hook (rustic-mode . (lambda () (set (make-local-variable 'compile-command) "cargo run"))) :custom (rustic-lsp-client 'eglot))
** R ESS
(use-package ess :custom (inferior-ess-r-program "r"))
** Swift
(use-package swift-mode :mode ("\.swift\'" . swift-mode))
** TypeScript
(use-package typescript-mode :hook ((typescript-mode . tree-sitter-mode) (typescript-mode . tree-sitter-hl-mode) (typescript-mode . eglot-ensure)))
** json
(use-package json-mode :mode ("\.json\'" . json-mode) :hook ((json-mode . tree-sitter-mode) (json-mode . tree-sitter-hl-mode)))
** Golang Open =.go= file with go-mode.
(use-package go-mode :mode ("\.go\'" . go-mode))
** Docker file
Some dockerfile is not end with =.dockerfile=, so lets guess:
(use-package dockerfile-mode :mode ("\dockerfile\'" . dockerfile-mode))
** Emacs lisp
(use-package elisp-mode :ensure nil :mode ("\.el\'" . emacs-lisp-mode) :config (define-derived-mode lisp-interaction-mode emacs-lisp-mode "ᴧ"))
** AutoHotKey
=ahk-mode= developed by Rich Alesi[fn:14]
(use-package ahk-mode :mode ("\.ahk\'" . ahk-mode))
** yaml mode
(use-package yaml-mode :mode ("\.yml\'" . yaml-mode) :bind (:map yaml-mode-map ("\C-m" . newline-and-indent)))
** shell
(use-package shell :mode ("\.sh\'" . shell-script-mode))
(use-package ob-shell :ensure nil :config (require 'shell) (add-to-list 'org-src-lang-modes '("shell" . shell)) (add-to-list 'org-babel-load-languages '(shell . t)))
** powershell
(use-package powershell :mode ("\.ps1\'" . powershell-mode))
** solidity
Major mode to edit ethereum solidity smart contract code.
(use-package solidity-mode :mode ("\.sol\'" . solidity-mode))
** lua and fennel
(use-package lua-mode) (use-package fennel-mode)
That's fun to draw UML with =ob-plantuml= inside =orgmode=:
For Windows Cygwin, install =graphviz= in =cygwin= setup tool
For macOS, install =graphviz= with homebrew:
brew install graphviz
Download =plantuml.jar= from https://plantuml.com/download, and put it to some place and assign ~plantuml-jar-path~ to there.
(use-package plantuml-mode :mode ("\.puml\'" . plantuml-mode) :custom (plantuml-output-type "svg") (plantuml-default-exec-mode 'jar) (plantuml-jar-path (expand-file-name (concat kimim/path-kimikit "plantuml/plantuml.jar"))) (plantuml-executable-args '("-charset" "utf-8")))
(use-package ob-plantuml :ensure nil :config (require 'plantuml-mode) ;; WARNING: if variables are from other package, setq them at :config (setq org-plantuml-jar-path plantuml-jar-path) (setq org-plantuml-args plantuml-executable-args) (add-to-list 'org-src-lang-modes '("plantuml" . plantuml)))
I want to preview plantuml result in a full window, so I set ~image-auto-resize~ to ~fit-window~. If the image is still to small, when it is a long sequence diagram, I can use key ~s i~ to invoke ~image-transform-fit-to-width~ to maximize the width of the image.
(use-package image-mode :ensure nil :custom (image-auto-resize 'fit-window) :config (add-to-list 'auto-mode-alist '("\.svg\'" . image-mode)))
** graphviz & dot
~dot~ is used to draw simple diagram in code. You need to install ~graphviz~:
pacman -S mingw-w64-ucrt-x86_64-graphviz
(use-package graphviz-dot-mode :ensure t :custom (graphviz-dot-preview-extension "svg"))
** ditaa
(use-package ob-ditaa :ensure nil :custom (org-ditaa-jar-path (expand-file-name (concat kimim/path-kimikit "ditaa/ditaa.jar"))) :config (add-to-list 'org-src-lang-modes '("ditaa" . artist)))
** Mermaid
Mermaid [fn:15] is another js based diagramming and charting tool. To use it inside orgmode, mermaid-cli should be installed:
yarn add @mermaid-js/mermaid-cli
~mmdc~ will be installed at ~~/node_modules/.bin/mmdc~. Then we just setup ~ob-mermaid~ and ~mermaid-mode~ for babel evaluation and editing.
(use-package ob-mermaid :custom (ob-mermaid-cli-path "~/node_modules/.bin/mmdc.cmd") :config (add-to-list 'org-babel-load-languages '(mermaid . t)))
(use-package mermaid-mode :mode ("\.mermaid\'" . mermaid-mode))
** iscroll
scroll images line by line.
(use-package iscroll :diminish iscroll-mode :hook ((org-mode markdown-mode) . iscroll-mode))
** chatu
(use-package chatu :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/chatu")) :commands (chatu-add chatu-open) :hook ((org-mode markdown-mode) . chatu-mode))
(eval-and-compile (defun lilypond-load-path () (cond ((eq system-type 'darwin) "/opt/homebrew/share/emacs/site-lisp/lilypond") ((eq system-type 'windows-nt) (concat kimim/path-kimikit "lilypond-2.24.3/share/emacs/site-lisp")) ((eq system-type 'gnu/linux) "/usr/local/share/emacs/site-lisp/lilypond"))))
(use-package lilypond-mode :load-path (lambda () (list (lilypond-load-path))) :mode ("\.ly\'" . LilyPond-mode))
(use-package ob-lilypond :ensure nil :config (require 'lilypond-mode) (cond ((eq system-type 'darwin) (setq org-babel-lilypond-ly-command "/opt/homebrew/bin/lilypond"))) (defun org-babel-lilypond-process-basic (body params) "Execute a lilypond block in basic mode." (let* ((out-file (cdr (assq :file params))) (cmdline (or (cdr (assq :cmdline params)) "")) (in-file (org-babel-temp-file "lilypond-")))
(with-temp-file in-file
(insert (org-babel-expand-body:generic body params)))
(org-babel-eval
(concat
org-babel-lilypond-ly-command
" -dcrop --loglevel=ERROR "
(or (cdr (assoc (file-name-extension out-file)
'(("pdf" . "--pdf ")
("ps" . "--ps ")
("svg" . "--svg ")
("png" . "--png "))))
"--png ")
"--output="
(file-name-sans-extension out-file)
" "
cmdline
in-file
;; copy .preview file to sans .preview file
" && mv -f "
(file-name-sans-extension out-file)
".cropped."
(file-name-extension out-file)
" "
out-file) "")) nil))
Hook ~pdf-view-themed-minor-mode~ to ~pdf-view-mode~ and add ~pdf-view-refresh-themed-buffer~ to ~enable-theme-functions~ to follow emacs theme color.
(use-package pdf-tools
:diminish pdf-view-themed-minor-mode
:functions (pdf-view-refresh-themed-buffer)
:defines (pdf-view-themed-minor-mode)
:mode ("\.pdf\'" . pdf-view-mode)
:hook ((pdf-view-mode . pdf-view-themed-minor-mode)
(pdf-view-mode . pdf-isearch-minor-mode))
:custom (pdf-view-display-size 3.85)
:bind
(:map
pdf-view-mode-map
("C-s" . isearch-forward)
("C-r" . isearch-backward)
("C-o" . pdf-occur)
("C-l" . pdf-view-center-in-window)
("j" . (lambda ()
"Next line within page"
(interactive)
(image-next-line 10)))
("k" . (lambda ()
"Previous line within page"
(interactive)
(image-next-line -10)))
("n" . kimim/pdf-view-next-page)
("p" . kimim/pdf-view-previous-page)
("o" . other-window)
("
(advice-add 'enable-theme :after (lambda (&rest _) (when pdf-view-themed-minor-mode (pdf-view-refresh-themed-buffer t))))
(require 'bibtex-completion) (defun kimim/pdf-view-next-page (&optional n) (interactive "p") (pdf-view-next-page n) (image-bob))
(defun kimim/pdf-view-previous-page (&optional n) (interactive "p") (pdf-view-previous-page n) (image-bob))
(defun pdf-view-open-bibtex-notes () "From PDF file, open the notes if they exist." (interactive) (bibtex-completion-edit-notes (list (pdf-view-get-bibtex-key))))
(defun pdf-view-get-bibtex-key () "Get bibtex key from PDF buffer name in pdf-view mode" (car (string-split (buffer-name) "[-\(_\.]+")))
(defun kimim/pdf-view-pagetext () "Show pdf text in a buffer." (interactive) (pdf-view-mark-whole-page) (pdf-view-kill-ring-save) (switch-to-buffer "pdf-view-pagetext") (yank)))
** pdf-view-store
To remember visited pages of PDF files.
(use-package pdf-view-restore :after pdf-tools :custom (pdf-view-restore-filename "~/.emacs.d/.pdf-view-restore") :hook (pdf-view-mode . pdf-view-restore-mode))
** pdf-view-pagemark
Add indicator of remaining text when scrolling PDF pages.
(use-package pdf-view-pagemark :after pdf-tools :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/pdf-view-pagemark")) :hook (pdf-view-mode . pdf-view-pagemark-mode))
** org-ref
(use-package bibtex-completion :defines bibtex-completion-bibliography :custom (bibtex-completion-display-formats '((t . "${=key=:30} ${author:36} ${title:*} ${year:4} ${=has-pdf=:1}${=has-note=:1} ${=type=:7}"))) (bibtex-completion-bibliography (concat kimim/path-docs "references.bib")) (bibtex-completion-library-path kimim/path-docs) (bibtex-completion-notes-path (concat kimim/path-notes "org-ref-notes.txt")) :bind ("C-x m b" . (lambda () (interactive) (find-file (concat kimim/path-docs "references.bib")))))
(use-package org-ref :functions (-flatten f-join org-ref-get-bibtex-key-and-file bibtex-completion-key-at-point bibtex-completion-candidates bibtex-completion-init bibtex-completion-edit-notes org-ref-cite-hydra/body org-ref-find-bibliography kimim/org-ref-open-pdf kimim/org-ref-open-pdf-in-dired kimim/org-ref-open-notes kimim/org-ref-open-notes-action kimim/org-ref-get-pdf-filename kimim/org-ref-open-pdf-action kimim/org-ref-open-pdf-in-dired-action) :bind (("C-x m p" . kimim/org-ref-open-pdf-at-point) ("C-x m P" . kimim/org-ref-open-pdf-in-dired-at-point) ("C-x m n" . kimim/org-ref-open-notes-at-point) :map org-mode-map ("C-c ]" . org-ref-insert-cite-link) ("C-c o" . kimim/org-roam-ref-open-pdf)) :config (require 'bibtex-completion) (require 'org-roam-bibtex) ;; use MS word to open office file (add-to-list 'org-file-apps '("\.docx?\'" . default)) (add-to-list 'org-file-apps '("\.pptx?\'" . default)) (add-to-list 'org-file-apps '("\.xlsx?\'" . default))
;; dont put [ inside file name (defun kimim/org-ref-get-pdf-filename (key) (if bibtex-completion-library-path (let ((pdf-dirs (if (listp bibtex-completion-library-path) bibtex-completion-library-path (list bibtex-completion-library-path))) (pdfs (-flatten (--map (file-expand-wildcards (f-join it (format "%s" key))) (-flatten (append pdf-dirs (--map (directory-files-recursively it "" t) pdf-dirs))))))) (cond ((= 0 (length pdfs)) (expand-file-name (format "%s.pdf" key) bibtex-completion-library-path)) ((= 1 (length pdfs)) (car pdfs)) ((> (length pdfs) 1) (completing-read "Choose: " pdfs)))) ;; No bibtex-completion-library-path defined so return just a file name. (format "%s.pdf" key)))
(defun kimim/org-ref-open-pdf-action (key) "Open the pdf for bibtex key under point if it exists." (let* ((pdf-file (kimim/org-ref-get-pdf-filename key))) (if (file-exists-p pdf-file) (find-file pdf-file) (message "no pdf found for %s" key))))
(defun kimim/org-ref-open-bibtex-pdf () (interactive) (kimim/org-ref-open-pdf-action (bibtex-completion-get-key-bibtex)))
(defun kimim/org-ref-open-pdf (&optional arg) (interactive) (kimim/org-ref-open-pdf-action (org-ref-read-key)))
(defun kimim/org-ref-open-pdf-at-point () "Open the pdf for bibtex key under point if it exists." (interactive) (let* ((results (condition-case nil (if (eq 'org-mode (buffer-local-value 'major-mode (current-buffer))) (org-ref-get-bibtex-key-and-file)) (error nil)))) (if (or (null results) (string= "" (car results)) (null (car results))) (kimim/org-ref-open-pdf) (let ((pdf-file (kimim/org-ref-get-pdf-filename (car results)))) (if (file-exists-p pdf-file) (find-file pdf-file) (kimim/org-ref-open-pdf))))))
(defun kimim/org-ref-open-pdf-in-dired-action (key) "Open the pdf dired for bibtex key under point if it exists." (let* ((pdf-file (kimim/org-ref-get-pdf-filename key))) (if (file-exists-p pdf-file) (dired-jump nil pdf-file) (message "no pdf found for %s" key))))
(defun kimim/org-ref-open-pdf-in-dired (&optional arg) (interactive) (kimim/org-ref-open-pdf-in-dired-action (org-ref-read-key)))
(defun kimim/org-ref-open-pdf-in-dired-at-point () "Open the pdf dired for bibtex key under point if it exists." (interactive) (let* ((results (condition-case nil (org-ref-get-bibtex-key-and-file) (error nil))) (key (car results))) (if (or (string= "" key) (null key)) (kimim/org-ref-open-pdf-in-dired) (let ((pdf-file (kimim/org-ref-get-pdf-filename key))) (if (file-exists-p pdf-file) (dired-jump nil pdf-file) (message "no pdf found for %s" key))))))
(defun kimim/org-ref-open-notes-action (key) "Open the notes for bibtex key under point if it exists." (bibtex-completion-edit-notes (list key)))
(defun kimim/org-ref-open-notes (&optional arg) (interactive) (kimim/org-ref-open-notes-action (org-ref-read-key)))
(defun kimim/org-ref-open-notes-at-point () "Open the notes of a reference if they exist." (interactive) (let* ((results (condition-case nil (org-ref-get-bibtex-key-and-file) (error nil))) (key (car results))) (if (or (string= "" key) (null key)) (kimim/org-ref-open-notes) (kimim/org-ref-open-notes-action key))))
(defun kimim/org-roam-ref-open-pdf () "Open pdf from ROAM_REFS of a note." (interactive) (kimim/org-ref-open-pdf-action (cadr (string-split (car (org-property-values "ROAM_REFS")) ":"))))
(defun kimim/bibtex-completion-get-title () "Copy the title by KEY." (interactive) (kill-new (s-format "${title}" 'bibtex-completion-apa-get-value (bibtex-completion-get-entry (org-ref-get-bibtex-key-under-cursor)))))
(defhydra+ org-ref-citation-hydra () "Add copy action to `org-ref-citation-hydra'." ("y" kimim/bibtex-completion-get-title "Copy title" :column "Copy")))
There is a built-in =bibtex-mode= to manage references. We can extend it to support more functions from =org-ref=:
(use-package bibtex :ensure nil :bind (:map bibtex-mode-map ("C-x m p" . kimim/org-ref-open-bibtex-pdf) ("C-x m n" . org-ref-open-bibtex-notes) ("C-x m d" . kimim/org-ref-open-bibtex-in-dired) ("C-c C-z" . org-ref-open-bibtex-notes)) :config (require 'org-ref) (require 'org-roam-bibtex))
** nov: reading epub books
(use-package nov
:mode ("\.epub\'" . nov-mode)
:hook ((nov-mode . olivetti-mode)
(nov-mode . (lambda ()
(visual-line-mode)
(setq line-spacing 0.5))))
:custom
(nov-header-line-format nil)
:bind
(:map
nov-mode-map
("
(defun kimim/fanyi-in-epub () "Invoke fanyi in epub view." (interactive) ;;(mouse-set-point last-input-event) (mark-thing-at-mouse last-input-event 'word) (if-let ((word (thing-at-point 'word))) (progn (fanyi-dwim word) (cl-pushnew word fanyi-history)) (call-interactively #'fanyi-dwim))))
(use-package org :mode (("\.txt\'" . org-mode) ("\.org\'" . org-mode)) :hook (org-mode . olivetti-mode) :bind (:map org-mode-map ("C-c b" . org-iswitchb) ("C-c l" . org-store-link) ("C-c C-x l" . org-toggle-link-display) ("C-c !" . org-time-stamp-inactive) ("C-c 。" . org-time-stamp) ("M-." . org-open-at-point) ("M-" . org-mark-ring-last-goto) ("M-h" . nil) ("C-'" . org-emphasize) ("C-c p" . kimim/preview-babel-image) ("C-c C-w" . org-refile-reverse) ("C-c w" . org-refile) ("M-," . org-mark-ring-goto)) :custom (org-modules '(org-habit ol-w3m ol-bbdb ol-bibtex ol-docview ol-gnus ol-info ol-irc ol-mhe ol-rmail ol-eww)) (org-export-with-sub-superscripts '{}) (org-startup-folded 'showall) (org-startup-with-inline-images t) (org-export-with-tags nil) (org-tags-column (- fill-column)) ;; image width in preview (org-image-actual-width `(,( (+ fill-column 10) (frame-char-width)))) :config ;; no use for me, I always press this key accidentally (unbind-key "C-'" 'org-mode-map) (setq org-hide-emphasis-markers t) (setq org-support-shift-select t) ;; no empty line after collapsed (setq org-cycle-separator-lines 0) (if window-system (setq org-startup-indented t) (setq org-startup-indented nil)))
** org-appear
(use-package org-appear :commands (org-appear-mode) :ensure t :custom (org-appear-autolinks nil) :hook (org-mode . org-appear-mode))
** org-indent
Add advice to ~org-indent--compute-prefixes~ to remove needless indent spaces before plain text line.
(use-package org-indent :ensure nil :custom (org-indent-mode-turns-on-hiding-stars nil) :hook (org-mode . org-indent-mode) :diminish org-indent-mode :config (defun kimim/org-indent-adjust-indent () (dotimes (n org-indent--deepest-level) (let ((indentation (* (1- org-indent-indentation-per-level) n))) ;; Text line prefixes. (aset org-indent--text-line-prefixes n (org-add-props (concat (make-string indentation ?\s) (and (> n 0) (char-to-string org-indent-boundary-char))) nil 'face 'org-indent))))) (advice-add 'org-indent--compute-prefixes :after
** org-modern
(use-package org-modern
:custom
;; https://github.com/minad/org-modern/issues/134
(org-modern-star '("○" "●" "▼"))
(org-modern-list
'((?- . "▬")
(?+ . "♦")
(? . "●")))
(org-modern-checkbox
'((?X . "☑")
(?- . #("☐–" 0 2 (composition ((2)))))
(?\s . "☐")))
(org-modern-timestamp nil)
(org-modern-tag nil)
(org-modern-todo nil)
(org-modern-block-name nil)
(org-modern-block-fringe nil)
(org-modern-keyword nil)
(org-modern-priority nil)
:hook
(org-mode . org-modern-mode)
:config
(advice-add
'org-modern--make-font-lock-keywords
:filter-return
(lambda (result)
(append
result
(when-let ((bullet (alist-get ?- org-modern-list)))
(("^\\(-\\)[ \t]" 1 '(face nil display ,bullet)))) (when-let ((bullet (alist-get ?+ org-modern-list)))
(("^[ ]\{2\}\(-\)[ \t]" 1 '(face nil display ,bullet))))
(when-let ((bullet (alist-get ? org-modern-list)))
`(("^[ ]\{4\}\(-\)[ \t]" 1 '(face nil display ,bullet))))))))
** pretty-symbols-in-org-mode
(use-package org :ensure nil :hook (org-mode . prettify-symbols-in-org-mode) :config (defun prettify-symbols-in-org-mode () "Beautify Org Symbols" (push '(":category:" . "▲") prettify-symbols-alist) (push '(":PROPERTIES:" . "🗅") prettify-symbols-alist) (push '(":END:" . "∎") prettify-symbols-alist) (push '("#+TITLE:" . "🗎") prettify-symbols-alist) (push '("#+SUBTITLE:" . "⮱") prettify-symbols-alist) (push '(":SETTINGS:" . "⌘") prettify-symbols-alist) (push '("#+begin_src" . "«" ) prettify-symbols-alist) (push '("#+end_src" . "»" ) prettify-symbols-alist) (push '("#+begin_comment" . "♯" ) prettify-symbols-alist) (push '("#+end_comment" . "▪" ) prettify-symbols-alist) (prettify-symbols-mode)))
** org-inline-pdf Sometimes, SVG images are not properly converted in LaTeX PDF file. Including a PDF image can solve this problem. Then we need a method to toggle PDF image display. =org-inline-pdf= solves this issue by using =pdf2svg= to convert PDF to SVG on-the-fly.
(use-package org-inline-pdf :hook (org-mode . org-inline-pdf-mode))
** orgalist
(use-package orgalist :commands (orgalist-mode))
** org for writing
(use-package org-download :commands (org-download-enable) :custom (org-download-heading nil) :functions kimim/org-download-annotate :config (setq org-download-timestamp "") (setq-default org-download-image-dir "./images") (setq org-download-method 'directory)
(defun kimim/org-download-annotate (link) "Annotate LINK with the time of download." (format "#+NAME: fig:%s\n#+CAPTION: %s\n" (file-name-base link) (file-name-base link))) (setq org-download-annotate-function #'kimim/org-download-annotate) (setq org-download-display-inline-images nil) (setq image-file-name-extensions (quote ("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm" "svg" "pdf" "bmp"))) (defun org-download--dir-2 () "."))
(use-package org :custom (org-num-skip-footnotes t) :config (require 'org-download) (setq org-hide-leading-stars t) (setq org-footnote-auto-adjust t) (setq org-footnote-define-inline nil))
** org with source code
(use-package org :config (setq org-src-window-setup 'current-window) (setq org-src-fontify-natively t) (setq org-src-preserve-indentation t) (setq org-edit-src-content-indentation 0) (setq org-confirm-babel-evaluate nil) (add-hook 'org-babel-after-execute-hook 'org-display-inline-images) ;; get the idea from John Kitchen(author of org-ref) (defadvice org-babel-execute-src-block (around load-language nil activate) "Load language if needed" (let* ((language (org-element-property :language (org-element-at-point))) (language-to-load (if (string= language "C++") "C" language))) (unless (cdr (assoc (intern language-to-load) org-babel-load-languages)) (require (intern (concat "ob-" language-to-load))) (add-to-list 'org-babel-load-languages (cons (intern language-to-load) t)) (org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)) ad-do-it)))
** org exporting
When exporting, do not export with author and date.
(use-package org :bind ("C-c C-'" . org-insert-structure-template) :functions (org-export--collect-headline-numbering org-export--get-min-level) :custom (org-export-allow-BIND t) (org-export-html-validation-link nil) ;;(org-export-with-sub-superscripts '{}) (org-export-with-author nil) (org-export-with-date t) (org-structure-template-alist '(("a" . "export ascii") ("c" . "center") ("C" . "comment") ("d" . "definition") ("e" . "example") ("E" . "export") ("h" . "export html") ("l" . "export latex") ("L" . "lemma") ("p" . "proof") ("o" . "corollary") ("?" . "question") ("q" . "quote") ("Q" . "quotation") ("r" . "result") ("s" . "src") ("t" . "theorem") ("v" . "verse"))) (org-html-head "") :config (require 'ox-latex)
(defun kimim/org-html-src-block-advice (oldfun src-block contents info) (let* ((class-tag (org-export-read-attribute :attr_html src-block :class)) (html-block (funcall oldfun src-block contents info))) (if (string-empty-p class-tag) html-block (string-replace ;; add src-bad class "class=\"src" (concat "class=\"src src-" class-tag) html-block))))
(advice-add 'org-html-src-block :around
(defmacro by-backend (&rest body) `(pcase (if (boundp 'backend) (org-export-backend-name backend) nil) ,@body))
(defun org-export--collect-tree-properties (data info) "Extract tree properties from parse tree.
DATA is the parse tree from which information is retrieved. INFO is a list holding export options.
Following tree properties are set or updated:
`:headline-offset' Offset between true level of headlines and local level. An offset of -1 means a headline of level 2 should be considered as a level 1 headline in the context.
`:headline-numbering' Alist of all headlines as key and the associated numbering as value.
`:id-alist' Alist of all ID references as key and associated file as value.
Return updated plist."
;; Install the parse tree in the communication channel.
(setq info (plist-put info :parse-tree data))
;; Compute :headline-offset' in order to be able to use ;;
org-export-get-relative-level'.
(setq info
(plist-put info
:headline-offset
(- 1 (org-export--get-min-level data info))))
;; From now on, properties order doesn't matter: get the rest of the
;; tree properties.
(org-combine-plists
info
(list :headline-numbering (org-export--collect-headline-numbering data info)
:id-alist
(org-element-map data 'link
(lambda (l)
(and (string= (org-element-property :type l) "id")
(let* ((id (org-element-property :path l))
(file (car (org-id-find id))))
;; replace txt extension with exported PDF file
(and file
(let ((pdf-file (concat (file-name-sans-extension file) ".pdf")))
(if (file-exists-p pdf-file)
(cons id (file-relative-name pdf-file))
(cons id (file-relative-name file)))))))))))))
*** org to pdf
LaTeX is required to convert =org-mode= to PDF.
For MacOS:
brew cask install mactex-no-gui
For Windows, there are three options:
apt-cyg install texlive-collection-xetex \ texlive-collection-latex \ texlive-collection-fontsrecommended
For Linux, download texlive install pacakge from [[http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz][ctan.org]]
tar zxvf install-tl-unx.tar.gz cd install-tl-20200908/ sudo ./install-tl
Then for all the OS platforms, use =tlmgr= to install user level tex packages (notes that, in windows, you may need to run =tlmgr.bat=):
tlmgr init-usertree tlmgr --usermode install ctex titlesec enumitem ms fontspec abstract \ zhnumber fandol lastpage pdftexcmds infwarerr \ minted fvextra etoolbox fancyvrb upquote \ lineno catchfile xstring framed float \ grffile wrapfig ulem lettrine minifp \ capt-of xcolor svg koma-script trimspaces \ titling layaureo parskip extsizes pgf \ moderncv microtype fmtutil-sys --all
Recently, I adopted to mainly use texlive on Windows. It works fine and provide a GUI tool to maintain packages: ~tlshell.exe~. You can use it to install and update latex packages.
To export =org-mode= to PDF, with code style highlight, you need to install =python= and =pygments=. Because =pygmentize= from =pygments= is used to generate =latex= markups for font highlighting.
For MacOS, the OS shipped =python2.7= does not accompanied with =pip= package management script. So you need to install =pip=, and then add =pygments=, acc. https://pip.pypa.io/en/stable/installing/ , =pygmentize= will be installed under =$HOME/Library/Python/2.7/bin=, which is added to =exec-path= and =PATH.=
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py python get-pip.py
Get =pygments= with =pip=:
pip install pygments
For Ubuntu Linux:
sudo apt install python3-pygments
(use-package latex-classes :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp")) :config (require 'bibtex-completion))
(use-package ox-latex :ensure nil :defines (kimim/latex-classes org-beamer-frame-level org-latex-minted-langs) :functions (org-html--make-attribute-string) :commands org-latex-publish-to-pdf :diminish org-beamer-mode :custom (org-latex-listings 'minted) (org-latex-minted-options '(("frame" "lines") ("fontsize" "\scriptsize"))) (org-latex-pdf-process '("latexmk -xelatex -shell-escape -output-directory=%o %F")) ;; avoid warning when preview tikz in org babel (org-babel-latex-preamble (lambda (_) "\documentclass[preview]{standalone}")) ;; emacs cannot handle relative path correctly in OneDrive folder ;; use full-name instead. %f -> %F (org-babel-latex-pdf-svg-process "inkscape \ --pdf-poppler \ --export-area-drawing \ --export-text-to-path \ --export-plain-svg \ --export-filename=%O \ %F") :config (require 'ox) (require 'ox-beamer) (require 'latex-classes) (setq org-startup-with-beamer-mode t) (setq org-beamer-frame-level 2) ;; export quotes match (setq org-export-with-smart-quotes t) (add-to-list 'org-latex-minted-langs '(plantuml "text")) (add-to-list 'org-latex-minted-langs '(ditaa "text")) (add-to-list 'org-latex-minted-langs '(bb "clojure")) (add-to-list 'org-latex-minted-langs '(conf "text")) (add-to-list 'org-latex-minted-langs '(mermaid "text")) (add-to-list 'org-latex-minted-langs '(lilypond "text")) (defun ref-headline-removal (backend) "Remove reference headline with tag: ref" (org-map-entries (lambda () (when (member "ref" org-scanner-tags) (delete-region (point) (line-beginning-position 2)))))) (add-hook 'org-export-before-parsing-functions 'ref-headline-removal)
;;;;; Nicolas Goaziou, http://article.gmane.org/gmane.emacs.orgmode/67692 ;; (defun org-latex-ignore-heading-filter-headline (headline backend info) ;; "Strip headline from HEADLINE. Ignore BACKEND and INFO." ;; (when (and (org-export-derived-backend-p backend 'latex) ;; (string-match "\`.ignoreheading.\n" headline)) ;; (replace-match "" nil nil headline))) ;; (add-to-list 'org-export-filter-headline-functions ;; 'org-latex-ignore-heading-filter-headline)
;; most of the time, I do not need table of contents (setq org-latex-toc-command nil) ;; https://www.tuicool.com/articles/ZnAnym ;; remove error: ! LaTeX Error: Command \nobreakspace unavailable in encoding T1. ;; add: \DeclareRobustCommand\nobreakspace{\leavevmode\nobreak\ } ;; put long latex classes in a separate file (require 'latex-classes) (setq org-latex-classes kimim/latex-classes) (setq org-latex-default-class "article") ;; removed, it will make small image too large! ;;(setq org-latex-image-default-option ;; "height=0.8\textheight,width=\textwidth,keepaspectratio") (setq org-latex-image-default-width "") ;; remove fontenc, and AUTO in front of inputenc, ;; then francais can be processed (setq org-latex-default-packages-alist (quote (("" "inputenc" t ("pdflatex")) ("" "minted" t nil) ("" "amsfonts" t nil) ("" "graphicx" t nil) ("inkscapeopt = -C --export-ignore-filters, inkscapelatex=false" "svg" t nil) ("" "grffile" t nil) ("" "longtable" nil nil) ("" "wrapfig" nil nil) ("" "rotating" nil nil) ("normalem" "ulem" t nil) ("" "amsmath" t nil) ("" "textcomp" t nil) ("" "lettrine" t nil) ("" "capt-of" nil nil)))) ;; latex preview report exception with bibref ;; (setq org-latex-packages-alist ;; `(,(concat "\addbibresource{" ;; (expand-file-name bibtex-completion-bibliography) ;; "}"))) ;; (mapconcat ;; (lambda (it) ;; (concat "\addbibresource{" (expand-file-name it) "}\n")) ;; bibtex-completion-bibliography)
;; increase latex preview size. ;;(setq org-format-latex-options ;; (plist-put org-format-latex-options :scale 2.3)) ;; scale latex equation preview according to frame char height (cond ((eq system-type 'darwin) (add-hook 'cnfonts-set-font-finish-hook (lambda (args) (setq org-format-latex-options (plist-put org-format-latex-options :scale (/ (frame-char-height) 9.0)))))) ((eq system-type 'windows-nt) (add-hook 'cnfonts-set-font-finish-hook (lambda (args) (setq org-format-latex-options (plist-put org-format-latex-options :scale (/ (frame-char-height) 30.0))))))) ;; preview latex equation with SVG image ;; [2024-04-25 Thu] kimim: use %F for input file, ;; because the relative path is not correct when in a symbol link folder. (add-to-list 'org-preview-latex-process-alist '(xdvsvgm :progams ("xelatex" "dvisvgm") :discription "xdv > svg" :message "you need install the programs: xelatex and dvisvgm." :image-input-type "xdv" :image-output-type "svg" :image-size-adjust (1.3 . 1.3) :latex-compiler ("xelatex -no-pdf -shell-escape -output-directory=%o %F") :image-converter ("dvisvgm %F -n -b min -c %S -o %O"))) (setq org-preview-latex-default-process 'xdvsvgm))
*** org to html page
(use-package ox-html :ensure org :functions (org-html-encode-plain-text org-html-close-tag f-read) :commands (org-html-publish-to-html) :config (setq org-html-validation-link nil) (defadvice org-html-paragraph (before fsh-org-html-paragraph-advice (paragraph contents info) activate) "Join consecutive Chinese lines into a single long line without unwanted space when exporting org-mode to html." (let ((fixed-contents) (orig-contents (ad-get-arg 1)) (reg-han "[[:multibyte:]]")) (setq fixed-contents (replace-regexp-in-string (concat "\(" reg-han "\) \n \(" reg-han "\)") "\1\2" orig-contents)) (ad-set-arg 1 fixed-contents))) ;; embed svg image to html file (defun org-html--format-image (source attributes info) "Return \"img\" tag with given SOURCE and ATTRIBUTES. SOURCE is a string specifying the location of the image. ATTRIBUTES is a plist, as returned by `org-export-read-attribute'. INFO is a plist used as a communication channel." (if (string= "svg" (file-name-extension source)) ;;(plist-get attributes :embed-svg) ;; remove width and height information, to fix image to the parent div (let ((svg-txt (replace-regexp-in-string "<svg.\(width=\"\w+\"\s+height=\"\w+\"\).>" "" (f-read source) nil nil 1))) (format "<div align=\"center\">%s
*** org to html slides
(use-package org-re-reveal :bind ("C-x r v" . org-re-reveal-export-to-html-and-browse) :config (use-package htmlize :ensure t) (setq org-re-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js@3.9.2/") (setq org-re-reveal-theme "none") (setq org-re-reveal-width 1000) (setq org-re-reveal-height 750) (setq org-re-reveal-transition "none") (setq org-re-reveal-hlevel 2) (setq org-re-reveal-extra-css "./kimim.css"))
** org link: page in pdf
(use-package org :functions org-supdf-open :config (org-link-set-parameters "supdf" :follow #'org-supdf-open)
(defun org-supdf-open (path) "Visit the pdf page" (let ((file-page (split-string path "::"))) (cond ((eq system-type 'windows-nt) (progn (w32-shell-execute "open" (concat kimim/path-kimikit "sumatrapdf/sumatrapdf.exe") (concat "\"" (expand-file-name (car file-page)) "\" -page " (cadr file-page)))))))))
** org link: onenote
New link to use Office Onenote.
(use-package org :functions org-onenote-open :config (org-link-set-parameters "onenote" :follow #'org-onenote-open)
(defun org-onenote-open (path) "Visit the onenote link" (cond ((eq system-type 'windows-nt) (progn (w32-shell-execute "open" (concat "onenote:" path)))) ((eq window-system 'ns) (shell-command (replace-regexp-in-string "&" "\\&" (format "open onenote:%s" path)))))))
** org publish to jekyll
(use-package o2jk :load-path (lambda () (concat kimim/path-kimim-emacs "site-lisp/o2jk")) :functions (o2jk-input-directory org-publish-cache-get-file-property org-ref-export-to-file-nomarks-noopen org-export-output-file-name org-ref-process-buffer org-export-expand-include-keyword) :commands (o2jk-publish o2jk-list-drafts o2jk-create-draft) :bind (("C-x m k" . o2jk-create-draft) ("C-x m l" . o2jk-list-source)) :custom ((o2jk-blog-author "kimim") (o2jk-source-directory "~/notes/kimi.im/_notes/_posts") (o2jk-jekyll-directory "~/notes/kimi.im/_posts") (o2jk-jekyll-drafts-dir "~/notes/_draft") (o2jk-jekyll-posts-dir "")) :config
(require 'org-ref)
(setq org-publish-project-alist `(("post" ;; dynamic pages like blog articles :base-directory ,(o2jk-input-directory) :base-extension "org\|txt" :publishing-directory ,(o2jk-output-directory) :publishing-function org-ref-html-publish-to-html :headline-levels 4 :html-preamble t :recursive t :make-index t :html-extension "html" :body-only t))) ;; Very simplified version of org-ref-export-to from org-ref-export.el ;; that export to filename (defun org-ref-export-to-file-nomarks-noopen (backend filename &optional async subtreep visible-only body-only info) (org-export-with-buffer-copy (org-export-expand-include-keyword) (org-ref-process-buffer backend subtreep) (org-export-to-file backend filename async subtreep visible-only body-only info)))
;; org-html-publish-to-html from ox-html.el adapted to org-ref ;; Instead of org-export-to-file calls org-ref-export-to-file-nomarks-noopen (defun org-ref-html-publish-to-html (plist filename pub-dir) (unless (or (not pub-dir) (file-exists-p pub-dir)) (make-directory pub-dir t)) ;; Check if a buffer visiting FILENAME is already open. (let* ((org-inhibit-startup t) (visiting (find-buffer-visiting filename)) (work-buffer (or visiting (find-file-noselect filename)))) (unwind-protect (with-current-buffer work-buffer (let ((output (org-export-output-file-name ".html" nil pub-dir))) (org-ref-export-to-file-nomarks-noopen 'html output nil nil nil (plist-get plist :body-only) (org-combine-plists plist `(:crossrefs ,(org-publish-cache-get-file-property ;; Normalize file names in cache. (file-truename filename) :crossrefs nil t) :filter-final-output (org-publish--store-crossrefs org-publish-collect-index ,@(plist-get plist :filter-final-output)))))))))))
Org-roam implements =zettelkasten= method [fn:16] used by famous German socialogist Niklas Luhmann[fn:17].
First you should install =sqlite3=, which is used to index the links.
Windows/MSYS2:
pacman -S mingw-w64-x86_64-sqlite3
Windows/Cygwin:
apt-cyg install sqlite3
sqlite3 is shipped in macOS by default.
(use-package org-roam :commands (kimim/non-cite-filter) :ensure t :custom (org-roam-directory kimim/path-notes) (org-roam-db-location (file-truename (concat user-emacs-directory "org-roam.db"))) (org-roam-link-auto-replace nil) (org-roam-file-extensions '("txt" "org")) (org-roam-node-display-template "${title:70}${tags:30}${refs}") (org-roam-capture-templates '(("d" "default" plain "%?" :if-new (file+head "%(concat (kimim/genfile-timestamp) \"${slug}.txt\")" "#+TITLE: ${title}\n") :unnarrowed t))) (org-roam-dailies-capture-templates '(("d" "default" plain "- /%<%H:%M>/ %?" :target (file+datetree "%<%Y>.org" :day)))) (orb-preformat-keywords '("citekey")) :bind (("C-c n f" . (lambda () (interactive) (org-roam-node-find nil nil 'kimim/non-cite-filter))) ("C-c n F" . (lambda () (interactive) (org-roam-node-find nil nil 'kimim/cite-filter))) ("C-c n o" . kimim/ebdb-link-open-note) ("C-c n c" . org-roam-capture) ("C-c n j" . org-roam-dailies-capture-today) ("C-c n ." . org-roam-dailies-goto-today) ("C-c n r" . org-roam-ref-add) ("C-c n x" . org-roam-node-random) :map org-roam-mode-map (("C-c n l" . org-roam) ("C-c n g" . org-roam-graph)) :map org-mode-map (("C-c n i" . (lambda () (interactive) (org-roam-node-insert 'kimim/non-cite-filter))) ("C-c n I" . (lambda () (interactive) (org-roam-node-insert 'kimim/cite-filter))) ("C-c n t" . org-roam-tag-add) ("C-c n a" . org-roam-alias-add) ("C-c n g" . org-id-get-create) ("C-c n b" . org-roam-buffer-toggle))) :config (add-to-list 'load-path (concat kimim/path-kimim-emacs "site-lisp/")) (require 'org-roam-dailies) (require 'org-roam-bibtex) (require 'emacsql) (require 'kimim) ;; open org link in current window (add-to-list 'org-link-frame-setup '(file . find-file)) ;;(setq org-roam-v2-ack t) (setq emacsql-global-timeout 60) ;; default 30 seconds will timeout ;;(org-roam-db-autosync-enable) (defvar orb-templates '(("r" "reference" plain "#+ROAM_KEY: %^{citekey}\n\n%?" :target (file+head "references/%(concat (kimim/genfile-timestamp) \"${citekey}.txt\")" "#+title: ${title}\n") :unnarrowed t))) (defun kimim/cite-filter (node) (orb-get-node-citekey node))
(defun kimim/non-cite-filter (node) (or (not (orb-get-node-citekey node)) (-contains? (org-roam-node-tags node) "standard") (-contains? (org-roam-node-tags node) "terminology"))) (advice-add 'org-roam-node-visit :after (lambda (&rest r) (reposition-window)))
(advice-add
(lambda (origin-fun &rest args) (let ((org-roam-capture-templates orb-templates)) (apply origin-fun args))))
(defun kimim/ebdb-link-open-note () (interactive) (let* ((context (org-element-context)) (name (buffer-substring (org-element-property :contents-begin context) (org-element-property :contents-end context))) (path (org-element-property :path context)) ;; TODO: extend to citeref in the future (node (kimim/ebdb-note-exists-p path))) (if node (org-roam-node-open node) (kimim/ebdb-note-new uuid name)))))
** org-roam-bibtex
It is useful to create reference notes with ~org-roam-bibtex~. ~C-c C-z~ used in ~org-ref~ is calling ~orb-org-ref-edit-note~ to edit ~org-roam~ note.
(use-package org-roam-bibtex :functions (orb-get-node-citekey orb--new-note) :hook (bibtex-mode . org-roam-bibtex-mode) :diminish org-roam-bibtex-mode ;; use the original title captalization :custom (orb-bibtex-entry-get-value-function
** org-transclusion
Add a virtual piece of other org file to current one.
(use-package org-transclusion
:after org
:custom (org-transclusion-include-first-section nil)
:hook (org-mode . org-transclusion-add-all)
:bind ("
** markdown mode
Markdown is widely used as plain text file format. Pandoc [fn:18] can be used to convert markdown file to html and other formats. We can download the [[https://github.com/jgm/pandoc/releases/latest][latest version]] and put the binary file to system path, such as ~/usr/local/bin~, and then set ~markdown-command~ to ~pandoc~.
(use-package markdown-mode
:mode ("\.\(?:md\|markdown\)\'" . markdown-mode)
:functions (s-starts-with?
markdown--get-remote-image)
:custom ((markdown-hide-urls t)
(markdown-command "pandoc")
(markdown-max-image-size
(,(* (+ fill-column 10) (frame-char-width)) . ,(* 2 (+ fill-column 10) (frame-char-width))))) :hook ((markdown-mode . markdown-toggle-inline-images) (markdown-mode . olivetti-mode)) :bind(:map markdown-mode-map ("C-<tab>" . outline-hide-entry) ("M-<up>" . markdown-move-up) ("M-<down>" . markdown-move-down) ("C-c C-x C-v" . markdown-toggle-inline-images)) :config (setq markdown-fontify-code-blocks-natively t) (setq markdown-list-item-bullets '("▬" "►" "•")) (setq markdown-list-indent-width 2) (advice-add 'markdown-fontify-list-items :override (lambda (last) (when (markdown-match-list-items last) (when (not (markdown-code-block-at-point-p (match-beginning 2))) (let* ((indent (length (match-string-no-properties 1))) (level (/ indent markdown-list-indent-width)) ;; level = 0, 1, 2, ... (bullet (nth (mod level (length markdown-list-item-bullets)) markdown-list-item-bullets))) (add-text-properties (match-beginning 2) (match-end 2) '(face markdown-list-face)) (cond ;; Unordered lists ((string-match-p "[\\*\\+-]" (match-string 2)) (add-text-properties (match-beginning 2) (match-end 2)
(display ,bullet)))
;; Definition lists
((string-equal ":" (match-string 2))
(let ((display-string
(char-to-string (markdown--first-displayable
markdown-definition-display-char))))
(add-text-properties (match-beginning 2) (match-end 2)
`(display ,display-string)))))))
t)))
;; to support azure markdown format with =WxH after file link (setq markdown-regex-link-inline "\(?1:!\)?\(?2:\[\)\(?3:\^?\(?:\\\]\|\ [^]]\)\|\)\(?4:\]\)\(?5:(\)\s-\(?6:[^)]?\)\\ (?:\s-+\(?7:\"[^\"]\"\|=.\)\)?\s-\(?8:)\)")
(defun markdown--browse-url (url) (let* ((struct (url-generic-parse-url url)) (full (url-fullness struct)) (file url)) (message file) ;; Parse URL, determine fullness, strip query string (setq file (car (url-path-and-query struct))) (let ((file (if (and (s-starts-with? "/" file) (not (file-exists-p file))) (concat (project-root (project-current t)) file) file))) ;; Open full URLs in browser, files in Emacs (if full (browse-url url) (when (and file (> (length file) 0)) (let ((link-file (funcall markdown-translate-filename-function file))) (if (and markdown-open-image-command (string-match-p (image-file-name-regexp) link-file)) (if (functionp markdown-open-image-command) (funcall markdown-open-image-command link-file) (process-file markdown-open-image-command nil nil nil link-file)) (find-file-other-window link-file))))))))
(defun markdown-display-inline-images () "Add inline image overlays to image links in the buffer. This can be toggled with `markdown-toggle-inline-images' or \[markdown-toggle-inline-images]." (interactive) (unless (display-images-p) (error "Cannot show images")) (save-excursion (save-restriction (widen) (goto-char (point-min)) (while (re-search-forward markdown-regex-link-inline nil t) (let ((start (match-beginning 0)) (imagep (match-beginning 1)) (end (match-end 0)) (file (match-string-no-properties 6)) ;; make file path if starts with / (file (if (s-starts-with? "/" file) (concat (project-root (project-current t)) file) file))) (when (and imagep (not (zerop (length file)))) (unless (file-exists-p file) (let ((download-file (funcall markdown-translate-filename-function file)) (valid-url (ignore-errors (member (downcase (url-type (url-generic-parse-url download-file))) markdown-remote-image-protocols)))) (if (and markdown-display-remote-images valid-url) (setq file (markdown--get-remote-image download-file)) (when (not valid-url) ;; strip query parameter (setq file (replace-regexp-in-string "?.+\'" "" file)) (unless (file-exists-p file) (setq file (url-unhex-string file))))))) (when (file-exists-p file) (let* ((abspath (if (file-name-absolute-p file) file (concat default-directory file))) (image (cond ((and markdown-max-image-size (image-type-available-p 'imagemagick)) (create-image abspath 'imagemagick nil :max-width (car markdown-max-image-size) :max-height (cdr markdown-max-image-size))) (markdown-max-image-size (create-image abspath nil nil :max-width (car markdown-max-image-size) :max-height (cdr markdown-max-image-size))) (t (create-image abspath))))) (when image (let ((ov (make-overlay start end))) (overlay-put ov 'display image) (overlay-put ov 'face 'default) (push ov markdown-inline-image-overlays))))))))))))
(when (not (boundp 'kimim/file-diary)) (defvar kimim/file-diary (concat kimim/path-org "diary")) (if (not (file-exists-p kimim/file-diary)) (write-region "" nil kimim/file-diary)))
(use-package calendar :defines (calendar-chinese-celestial-stem calendar-chinese-terrestrial-branch) :custom (diary-file kimim/file-diary) (calendar-latitude +30.16) (calendar-longitude +120.12) (calendar-location-name "Hangzhou") (calendar-remove-frame-by-deleting t) (calendar-week-start-day 1) (calendar-mark-holidays-flag t) (holiday-christian-holidays nil) (holiday-hebrew-holidays nil) (holiday-islamic-holidays nil) (holiday-solar-holidays nil) (holiday-bahai-holidays nil) (holiday-general-holidays '((holiday-fixed 1 1 "元旦") (holiday-float 5 0 2 "父親節") (holiday-float 6 0 3 "母親節"))) (calendar-mark-diary-entries-flag t) (calendar-view-holidays-initially-flag nil) (calendar-chinese-celestial-stem ["甲" "乙" "丙" "丁" "戊" "己" "庚" "辛" "壬" "癸"]) (calendar-chinese-terrestrial-branch ["子" "丑" "寅" "卯" "辰" "巳" "午" "未" "申" "酉" "戌" "亥"]) :config (require 'ebdb) ;; redefine Chinese sexagesimal format (defun calendar-chinese-sexagesimal-name (n) "The N-th name of the Chinese sexagesimal cycle. N congruent to 1 gives the first name, N congruent to 2 gives the second name, ..., N congruent to 60 gives the sixtieth name." (format "%s%s 年" (aref calendar-chinese-celestial-stem (% (1- n) 10)) (aref calendar-chinese-terrestrial-branch (% (1- n) 12)))) ;; https://www.emacswiki.org/emacs/CalendarWeekNumbers (defface calendar-iso-week-face '((t :inherit 'calendar-weekend-header :height 0.7 :bold t)) "Week number.") (setq calendar-week-start-day 1 calendar-intermonth-header '(propertize " " 'font-lock-face 'calendar-iso-week-face) calendar-intermonth-text '(propertize (format "%2d" (car (calendar-iso-from-absolute (calendar-absolute-from-gregorian (list month day year))))) 'font-lock-face 'calendar-iso-week-face)))
** org as GTD system
(use-package org-capture :ensure nil :bind (:map org-capture-mode-map ("C-c C-w" . kimim/org-capture-refile-reverse) ("C-c w" . org-capture-refile)) :custom (org-capture-templates '(("c" "Capture" entry (file+headline "capture.org" "Inbox") " %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n") ("t" "TODO Task" entry (file+headline "capture.org" "Inbox") " TODO %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n") ("s" "SCHED Task" entry (file+headline "capture.org" "Inbox") " SCHED %?\nSCHEDULED: %t\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n") ("o" "OPEN Issue" entry (file+headline "capture.org" "Inbox") " OPEN %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n") ("w" "WAIT Task" entry (file+headline "capture.org" "Inbox") " WAIT %?\nSCHEDULED: %t\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n") ("h" "Habit" entry (file+headline "global.org" "Habit") " %? :habit:\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n"))) :config (defun kimim/org-capture-refile-reverse () (interactive) (let ((org-reverse-note-order t)) (org-capture-refile))))
(use-package org
:functions (org-agenda-kill-all-agenda-buffers
org-agenda-todo
org-agenda-error
org-agenda-check-no-diary)
; :hook (org-agenda-mode . hl-line-mode)
:defines org-agenda-mode-map
:commands (org-toggle-office org-toggle-home org-toggle-home-or-office)
:bind (("C-c a" . org-agenda)
("C-c c" . org-capture)
:map org-agenda-mode-map
("o" . other-window)
("C-c M-s" . kimim/org-agenda-unschedule)
("C-c M-d" . kimim/org-agenda-undeadline)
("C-c C-x C-p" . org-previous-link)
("C-c C-x C-n" . org-next-link)
("C-c C-k" . org-agenda-kill-files)
("project' or
category'
;; tag in org-agenda-files
(org-agenda-files . (:tag . "project"))
(org-agenda-files . (:tag . "category"))))
(org-habit-show-all-today t)
:config
(require 'org-capture)
(require 'org-agenda)
(add-hook 'kill-emacs-hook
(lambda ()
(org-clock-out nil t nil)
(org-save-all-org-buffers)))
;; kill diary when exit agenda
(advice-add 'org-agenda-exit
:after (lambda () (kill-buffer "diary")))
(diminish 'auto-fill-function)
(defadvice org-schedule (after add-todo activate) (if (or (string= "OPEN" (org-get-todo-state)) (string= "WAIT" (org-get-todo-state)) (string= "CLOSE" (org-get-todo-state))) (org-todo "WAIT") (org-todo "SCHED")))
(defadvice org-deadline (after add-todo activate) (if (or (string= "OPEN" (org-get-todo-state)) (string= "WAIT" (org-get-todo-state)) (string= "CLOSE" (org-get-todo-state))) (org-todo "WAIT") (org-todo "SCHED")))
(defun kimim/org-agenda-unschedule () (interactive) (org-agenda-schedule `(4)) (org-agenda-todo 'left))
(defun kimim/org-agenda-undeadline () (interactive) (org-agenda-deadline `(4)) (org-agenda-todo 'left))
(defun org-agenda-kill-files () (interactive) (org-agenda-kill-all-agenda-buffers) (mapcar (lambda (file) (if-let (buf (get-file-buffer file)) (kill-buffer buf))) org-agenda-files))
(defun org-agenda-refile-reverse (&optional goto rfloc no-update) "Refile the item at point, reversely." (interactive "P") (cond ((member goto '(0 (64))) (org-refile-cache-clear)) ((equal goto '(16)) (org-refile-goto-last-stored)) (t (let* ((buffer-orig (buffer-name)) (marker (or (org-get-at-bol 'org-hd-marker) (org-agenda-error))) (buffer (marker-buffer marker)) ;; (pos (marker-position marker)) (rfloc (or rfloc (org-refile-get-location (if goto "Goto" "Refile to") buffer org-refile-allow-creating-parent-nodes)))) (with-current-buffer buffer (org-with-wide-buffer (goto-char marker) (let ((org-agenda-buffer-name buffer-orig)) (org-remove-subtree-entries-from-agenda)) (org-refile-reverse goto buffer rfloc)))) (unless no-update (org-agenda-redo))))))
** org-pomodoro
Type ~C-x m m~ on agenda task to invoke ~org-pomodoro~. When an pomodoro is completed, a posframe showing break countdown in large font.
(use-package org-pomodoro :after org :custom ((org-pomodoro-audio-player "mpg123") (org-pomodoro-format "(*) %s")) :bind ("C-x m m" . org-pomodoro) :config (require 'posframe)
(defun kimim/org-pomodoro-tick-hook () (if (or (eq org-pomodoro-state :short-break) (eq org-pomodoro-state :long-break)) (posframe-show "pomodoro" :string (propertize (cadr org-pomodoro-mode-line) 'face '(:height 400 :inherit org-pomodoro-mode-line-break)) :poshandler 'posframe-poshandler-frame-center :timeout 10) (posframe-delete "pomodoro")))
(add-hook 'org-pomodoro-tick-hook
(defun kimim/org-pomodoro-finished-action () (raise-frame))
(add-hook 'org-pomodoro-finished-hook
(use-package ebdb :functions ebdb-gethash :commands ebdb ebdb-mail-aliases :custom (ebdb-mua-pop-up nil) :bind (:map ebdb-mode-map ("C-c C-z" . kimim/ebdb-note-find) ("w i" . kimim/ebdb-citekey)) :config (setq ebdb-sources (concat kimim/path-org "ebdb.gpg")) (setq ebdb-i18n-countries-pref-scripts '(("中国" . chn))) (require 'ebdb-gnus) (require 'ebdb-message) (require 'ebdb-org) (add-hook 'message-setup-hook 'ebdb-mail-aliases) (setq org-link-make-description-function (lambda (link desc) (let* ((link-content (split-string link ":")) (key (car link-content)) (link-str (cadr link-content)) (link-uuid (cadr (split-string link-str "/")))) (if desc desc (if (string= "ebdb" key) (ebdb-record-name-string (ebdb-gethash link-uuid 'uuid)))))))
(defvar kimim/ebdb-notes-cache nil "Cache of EBDB notes.")
(defun kimim/ebdb-get-db-cite-refs ()
"Get a list of cite
refs from Org Roam database."
(let* ((types "ebdb")
(refs (org-roam-db-query
[:select [ref nodes:file id pos title type]
:from refs
:left-join nodes
:on (= refs:node-id nodes:id)
:where (= type $s1)]
types))
result)
(dolist (ref refs result)
(push (-interleave '(:ref :file :id :pos :title :type) ref) result))))
(defun kimim/ebdb-make-notes-cache () "Update ORB notes hash table `kimim/ebdb-notes-cache'." (let* ((db-entries (kimim/ebdb-get-db-cite-refs)) (size (round (/ (length db-entries) 0.8125))) ;; ht oversize (ht (make-hash-table :test #'equal :size size))) (dolist (entry db-entries) (puthash (plist-get entry :ref) (org-roam-node-create :id (plist-get entry :id) :file (plist-get entry :file) :title (plist-get entry :title) :point (plist-get entry :pos)) ht)) (setq kimim/ebdb-notes-cache ht)))
(defun kimim/ebdb-note-exists-p (uuid) "Check if a note exists whose :ROAM_REFS is uuid. Return Org Roam node or nil." (gethash uuid (kimim/ebdb-make-notes-cache)))
(defun kimim/ebdb-citekey () "Get people citekey" (interactive) (if-let* ((record (ebdb-current-record)) (name (ebdb-record-name-string record)) (uuid (ebdb-record-uuid record)) (citekey-ref (format "[[ebdb:uuid/%s][%s]]" uuid name))) (kill-new citekey-ref)))
(defun kimim/ebdb-note-new (uuid name) "Create people note." (if-let* ((citekey-ref (format "[[ebdb:uuid/%s][%s]]" uuid name)) (title name) (node (org-roam-node-create :title title :file (concat kimim/path-notes "people/" (kimim/genfile-timestamp) (s-downcase (s-join "_" (s-split-words title))) ".txt")))) (org-roam-capture- :node node :info (list :ref citekey-ref)) (user-error "Abort")))
(defun kimim/ebdb-note-find () "Find or create people note." (interactive) (let* ((record (ebdb-current-record)) (name (ebdb-record-name-string record)) (uuid (ebdb-record-uuid record)) (ebdb-ref (concat "uuid/" uuid)) (node (kimim/ebdb-note-exists-p ebdb-ref))) (if node (org-roam-node-open node) (kimim/ebdb-note-new uuid name)))))
** erc
;; erc settings (use-package erc :functions erc-autojoin-enable :commands erc :custom (erc-autojoin-channels-alist '(("irc.freenode.net" "#emacs"))) (erc-hide-list '("JOIN" "PART" "QUIT")) :config (require 'erc-join) (erc-autojoin-enable) (setq erc-default-server "irc.freenode.net"))
** GNUS dired
(use-package gnus-dired :ensure nil :commands (turn-on-gnus-dired-mode) :config ;; make the `gnus-dired-mail-buffers' function also work on ;; message-mode derived modes, such as mu4e-compose-mode (defun gnus-dired-mail-buffers () "Return a list of active message buffers." (let (buffers) (save-current-buffer (dolist (buffer (buffer-list t)) (set-buffer buffer) (when (and (derived-mode-p 'message-mode) (null message-sent-message-via)) (push (buffer-name buffer) buffers)))) (nreverse buffers))) (setq gnus-dired-mail-mode 'mu4e-user-agent))
** mu4e
(use-package sendmail :ensure nil :custom (mail-user-agent 'sendmail-user-agent) (mail-signature nil) (mail-self-blind t) (mail-signature-file (concat kimim/path-emacs "signature.txt")))
(use-package mu-cite :commands (mu-cite-original) :config (setq mu-cite-top-format '("On " date ", " from " wrote:\n\n")) (setq mu-cite-prefix-format '(" > ")))
(eval-and-compile (defun mu4e-load-path () (cond ((eq system-type 'darwin) "/usr/local/Cellar/mu/1.0_1/share/emacs/site-lisp/mu/mu4e") ((eq system-type 'windows-nt) "/usr/local/share/emacs/site-lisp/mu4e") ((eq system-type 'gnu/linux) "/usr/local/share/emacs/site-lisp/mu4e/"))))
(use-package mu4e
:ensure nil
:functions (mu4e-compose-reply
mu4e~view-quit-buffer)
:defines (mu4e-html2text-command
mu4e-mu-binary
mu4e-get-mail-command
mu4e-update-interval
mu4e-hide-index-messages
mu4e-use-fancy-chars
mu4e-view-show-images
mu4e-view-fields
mu4e-headers-fields
mu4e-compose-cite-function
mu4e-compose-reply-recipients
mu4e-headers-mode-map
mu4e-compose-mode-map
mu4e-view-mode-map
shr-color-visible-luminance-min
shr-color-visible-distance-min)
:custom
(mu4e-compose-reply-recipients 'sender)
(mu4e-compose-signature-auto-include nil)
:commands (mu4e mu4e-compose-new)
:bind (
:map mu4e-headers-mode-map
("r" . kimim/mu4e-compose-reply-sender)
("R" . kimim/mu4e-compose-reply-all)
("f" . kimim/mu4e~view-quit-buffer)
:map mu4e-compose-mode-map
("
(require 'org-mu4e) ;; capture link (add-to-list 'Info-additional-directory-list "/usr/local/share/info") (setq mu4e-mu-binary "/usr/local/bin/mu") ;; (cond ((eq system-type 'gnu/linux) ;; (setq mu4e-mu-binary "/snap/bin/mu"))) (setq mail-user-agent 'mu4e-user-agent) ;; Fetch mail by offlineimap (setq mu4e-get-mail-command "offlineimap -c ~/.offlineimaprc -u quiet") ;; Fetch mail in 60 sec interval (setq mu4e-update-interval 300) ;; hide indexing messages from minibuffer (setq mu4e-hide-index-messages t) (setq mu4e-use-fancy-chars nil) (setq mu4e-view-show-images t) (setq mu4e-view-fields '(:subject :from :to :cc :date :mailing-list :attachments :signature :decryption)) (setq mu4e-headers-fields '( (:human-date . 12) (:flags . 6) (:from . 22) (:subject . nil))) (setq mu4e-compose-cite-function 'mu-cite-original) (add-hook 'mu4e-view-mode-hook 'visual-line-mode) (add-hook 'mu4e-compose-mode-hook 'kimim/mail-setup) (add-hook 'mu4e-compose-mode-hook 'orgalist-mode) (add-hook 'mu4e-compose-mode-hook (lambda () (auto-fill-mode -1))) (defun kimim/mu4e~view-quit-buffer () (interactive) (when (get-buffer "mu4e-view") (switch-to-buffer "mu4e-view") (mu4e~view-quit-buffer)))
(defun kimim/mu4e-compose-reply-sender () (interactive) (set (make-local-variable 'mu4e-compose-reply-recipients) 'sender) (mu4e-compose-reply))
(defun kimim/mu4e-compose-reply-all () (interactive) (set (make-local-variable 'mu4e-compose-reply-recipients) 'all) (mu4e-compose-reply)))
(use-package restclient :mode ("\.http\'" . restclient-mode) :bind (:map restclient-mode-map ("C-c C-c" . restclient-http-send-current-stay-in-window) ("C-c C-v" . restclient-http-send-current)))
** COMMENT Reading News
(use-package elfeed
:functions elfeed-show-refresh
:commands (elfeed)
:custom
(elfeed-curl-timeout 100)
(browse-url-browser-function 'browse-url-default-browser)
(elfeed-feeds
'(("http://kimi.im/atom.xml" blog)
("https://blog.tecosaur.com/tmio/rss.xml" Org)
("www.chinadaily.com.cn/rss/bizchina_rss.xml" CN)
;; from https://www.foxnews.com/story/foxnews-com-rss-feeds
("http://feeds.foxnews.com/foxnews/world" EN)
("http://feeds.foxnews.com/foxnews/scitech" EN Tech)
;; from https://www.lefigaro.fr/rss
("https://www.lefigaro.fr/rss/figaro_secteur_high-tech.xml" FR Hightech)
("https://www.lefigaro.fr/rss/figaro_management.xml" FR Management)
;; from https://www.zeit.de/hilfe/hilfe#rss
("http://newsfeed.zeit.de/wissen/index" DE Wissen)
("http://newsfeed.zeit.de/kultur/index" DE Kultur)))
:bind (:map elfeed-search-mode-map
("
** Encryption
Sometimes, you need to encrypt some secret files, setting ~epa-pinentry-mode~ to ~loopback~ will prompt password inside minibuffer, while not show a dialog for it.
And we also cache the symmetric key in the same
(use-package epa :ensure nil :custom (epa-pinentry-mode 'loopback) (epa-file-cache-passphrase-for-symmetric-encryption t))
** Viewing Documents
doc-view-mode can view many kind of documents, such as PDF, PS and images. You should install postscript in cygwin.
(use-package doc-view :custom (doc-view-continuous t) (doc-view-image-width 500) (doc-view-resolution 300))
[fn:1] http://www.literateprogramming.com/
[fn:2] https://orgmode.org/
[fn:3] https://www.msys2.org/
[fn:4] http://cygwin.com/
[fn:5] https://cygwin.com/setup-x86_64.exe
[fn:6] http://kimi.im/2021-01-28-emacs-inside-manjaro-wsl2-windows
[fn:7] http://brew.sh/
[fn:8] https://www.gnu.org/software/emacs/manual/html_node/emacs/Packages.html
[fn:9] https://github.com/syl20bnr/spacemacs/issues/381
[fn:10] https://github.com/Fuco1/smartparens
[fn:11] https://clojure.org/
[fn:12] https://cider.mx/
[fn:13] https://github.com/jorgenschaefer/elpy
[fn:14] https://github.com/ralesi/ahk-mode
[fn:15] https://mermaid-js.github.io/
[fn:16] https://zettelkasten.de/
[fn:17] https://en.wikipedia.org/wiki/Niklas_Luhmann
[fn:18] https://pandoc.org/