Skip to content

mkvoya/emacs.d

Repository files navigation

Emacs Main Configuration File

Options

;;; emacs-config.el --- Main Emacs Configuration  -*- lexical-binding: t -*-
;;; Commentary:

;;; Code:

(defvar mk-feature/bibliography t "Enable bibliography.")
(defvar mk-feature/gui t "Enable GUI-related packages.")
(defvar mk-feature/noteman t "Enable note management.")
(defvar mk-feature/light t "Use light mode.")
(defvar mk-feature/news-mail t "Enable news and mails.")
(when is-android
  (setq mk-feature/bibliography nil
        mk-feature/gui nil
        mk-feature/news-mail nil
        mk-feature/noteman nil))

early-init.el

;;; early-init.el --- Early Emacs configuration  -*- lexical-binding: t -*-
;;; Commentary:

;;; Code:

(defvar is-android (string= system-type "android") "Whether on Anroid.")

;; (setq debug-on-error t)
;; (setq debug-on-signal t)
(setq-default
 ;; Package
 load-prefer-newer t ; Load newer packages when available.
 package-enable-at-startup nil  ; do not load packege.el
 package-quickstart nil
 package-native-compile nil
 ;; GC
 gc-cons-threshold most-positive-fixnum
 gc-cons-percentage 0.6
 ;; Resizing the Emacs frame can be a terribly expensive part of changing the
 ;; font. By inhibiting this, we easily halve startup times with fonts that are
 ;; larger than the system default.
 frame-inhibit-implied-resize t
 )

(fset 'yes-or-no-p 'y-or-n-p)
(setq confirm-kill-emacs 'y-or-n-p)
(setq comp-deferred-compilation nil)


(when is-android
  (setenv "PATH" (format "%s:%s" "/data/data/com.termux/files/usr/bin"
                         (getenv "PATH")))
  (setenv "LD_LIBRARY_PATH" (format "%s:%s"
                                    "/data/data/com.termux/files/usr/lib"
                                    (getenv "LD_LIBRARY_PATH")))
  (push "/data/data/com.termux/files/usr/bin" exec-path)
  )
(when (string-equal system-type "android")
  ;; Add Termux binaries to PATH environment
  (let ((termuxpath "/data/data/com.termux/files/usr/bin"))
    (setenv "PATH" (concat (getenv "PATH") ":" termuxpath))
    (setq exec-path (append exec-path (list termuxpath)))))

(unless is-android
  (when (display-graphic-p)
    (tool-bar-mode nil) ; t for enable, nil for disable, -1 for toggle
    (scroll-bar-mode nil)
    (menu-bar-mode nil))

  (setq source-directory (expand-file-name "~/Library/Caches/Homebrew/emacs-plus@30--git"))

  (setq-default
   default-frame-alist
   `(
     (left-fringe . 8)                    ;; Thin left fringe
     (menu-bar-lines . 0)                 ; No menu bar
     (right-divider-width . 1)            ;; Thin vertical window divider
     (right-fringe . 3)                   ;; Thin right fringe
     (tool-bar-lines . 0)                 ; No tool bar
     (tab-bar-lines . 0)                  ; No tab bar
     ;; (undecorated . 1)                 ; this will completely remove the titlebar
     (ns-titlebar-height-adjust . -10)    ; this is actually not used
     (ns-title-hidden . 1)                ; hide the title text in the titlebar
     (ns-fullsize-content . 1)            ; make the content full size
     (ns-transparent-titlebar . 1)        ; make the titlebar transparent
     (vertical-scroll-bars . nil)         ; No vertical scroll-bars
     (horizontal-scroll-bars . nil)       ; No horizontal scroll-bars
     (undecorated . t)
     (width . 120)
     (height . 50)
     (font . "Monaco-12")
     (minibuffer . t)
     (drag-with-header-line . t)
     (drag-with-mode-line . t)
     (drag-with-internal-border . t)
     ))
  ;; (set-frame-font "Monaco-12" nil t)
  (set-face-attribute 'fixed-pitch nil :family "Monaco")

  ) ; End of unless is-android

;; (when window-system (set-frame-size (selected-frame) 120 50))

;; UTF-8
(prefer-coding-system 'utf-8)
(when (display-graphic-p)
  (setq x-select-request-type '(UTF8_STRING COMPUND_TEXT TEXT STRING)))
;; Unicode
(set-language-environment "UTF-8")
(set-default-coding-systems 'utf-8)

(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)

(setq current-language-environment "UTF-8")
;; (setq default-input-method "rfc1345")

;; Sentence
(setq sentence-end-double-space nil) ; Use only one space to end a sentence

(provide 'early-init)
;;; early-init.el ends here

init.el

;;; init.el --- -*- lexical-binding: t -*-
;;; Commentary:

;;; Code:


(setq gc-cons-threshold (* 4 (expt 2 20))
      gc-cons-percentage 0.6)

(let* (;; (file-name-handler-alist nil)  ; This causes loading issues. Check: https://lists.gnu.org/archive/html/emacs-devel/2022-08/msg00218.html
       (read-process-output-max (expt 2 22)))

  ;; 将lisp目录放到加载路径的前面以加快启动速度
  (let ((dir (locate-user-emacs-file "init-lisp")))
    (add-to-list 'load-path (file-name-as-directory dir)))
  (let ((dir (locate-user-emacs-file "lisp")))
    (add-to-list 'load-path (file-name-as-directory dir)))

  (load "~/.emacs.d/emacs-config.el")

  ;; Collect garbage when all else is done
  ;; (garbage-collect)
  )

(setq gc-cons-threshold (expt 2 23)
      gc-cons-percentage 0.1)
(setq gc-cons-threshold (expt 2 28)
      gc-cons-percentage 0.3)

(message "Everything is up. Wish you a nice day. :)")
(put 'narrow-to-region 'disabled nil)

(provide 'init)
;;; init.el ends here

Base and Core

Literal Configuration Bootstrap

(defvar mkconfig/.org "~/.emacs.d/emacs-config.org")
(defvar mkconfig/.el (concat (file-name-sans-extension mkconfig/.org) ".el"))
(defun mk/sync-emacs-config()
  "Synchronize config from org to el and compile to elc."
  (interactive)
  ;; Avoid running hooks when tangling. From https://delta.re/emacs-config-org/
  (let ((prog-mode-hook nil))
    (require 'ob-tangle)
    ;; Tangle the file. It's fast.
    (org-babel-tangle-file mkconfig/.org)
    (message "[CONFIG] Config is synchronized.")
    ;; Async compile the config.
    (async-byte-compile-file mkconfig/.el)))

;; Sync config when the config file is saved.
(add-hook 'after-save-hook
          (lambda ()
            (if (equal (buffer-file-name) (expand-file-name mkconfig/.org))
                (mk/sync-emacs-config))))

Bootstrap

Custom Files

(setq custom-file "~/.emacs.d/customs.el")
(load custom-file t)

Packages

straight.el replacing package.el

straight.elhttps://github.com/raxod502/straight.el
package.elbuilt-in package system
quelpahttps://github.com/quelpa/quelpa
quelpa-use-packagehttps://github.com/quelpa/quelpa-use-package
paradoxA modern interface for package.el
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 6))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

use-package: A use-package declaration for simplifying your .emacs

use-packagehttps://github.com/jwiegley/use-package
diminish
delightbetter: altering mode appearance on modeline
(straight-use-package 'use-package)
(setq straight-use-package-by-default t) ; Ensure :straight t
(setq use-package-compute-statistics t)
(when is-android
  (setq straight-disable-compile t)
  )
(unless is-android
  (straight-use-package 'org))
(use-package use-package-ensure-system-package :ensure t)
(use-package delight)

Benchmarks

(use-package benchmark-init
  :ensure t
  :config
  ;; To disable collection of benchmark data after init is done.
  (add-hook 'after-init-hook 'benchmark-init/deactivate))

Emacs Server

(unless is-android
  ;;; The server part may not be configured so early.
  (load "server") ; Load and start server if it's not running
  (unless (server-running-p) (server-start))
  )

The PATH

;;; Get shell env from user shell.
;; https://apple.stackexchange.com/questions/51677/how-to-set-path-for-finder-launched-applications
;; $ sudo launchctl config user path /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
;; We need to at least make the /usr/local/bin in the path so that imagemagick can use rsgv rather than its built-in svg renderer.
;; The above command works.
(use-package exec-path-from-shell
  :init
  (exec-path-from-shell-initialize))

SETQs

(setq
 ;; Backups
 backup-by-copying t
 backup-directory-alist '(("." . "~/.emacs.d/backups"))
 delete-old-versions t
 kept-new-versions 6
 kept-old-versions 2
 version-control t
 vc-make-backup-files t
 ;;(setq backup-directory-alist '(("." . "~/.emacs.d/backups")))
 ;;(setq delete-old-versiojns -1)
 ;;(setq version-control t)
 auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-save-list/" t))
 ;; History
 savehist-file "~/.emacs.d/savehist"
 history-length t
 history-delete-duplicates t
 savehist-save-minibuffer-history 1
 savehist-additional-variables '(kill-ring search-ring regex-search-ring))
(savehist-mode 1)
(setq-default
 ;; From: https://stackoverflow.com/questions/4657142/how-do-i-encourage-emacs-to-follow-the-compilation-buffer
 compilation-scroll-output t
 ;; (setq compilation-scroll-output 'first-error)
 ;; Prevent Extraneous Tabs
 indent-tabs-mode nil
 fill-column 100
 ;; line-spacing 0.1
 )
(setq enable-recursive-minibuffers t)
(minibuffer-depth-indicate-mode 1)
(defun mkvoya/better-wrap ()
  "Make the word wrap better."
  (interactive)
  (progn
    (visual-line-mode t)
    ;; (setq word-wrap nil)
    ))

(blink-cursor-mode 1)

(setq delete-by-moving-to-trash t)
(use-package ns-win
  :if (memq window-system '(mac ns))
  :straight nil
  :init
  ;; (setq mac-right-command-modifier 'control)
  ;; (setq mac-right-option-modifier 'control)
  )

Fonts

We need to setup fonts early.

(use-package fontaine
  :if (not is-android)
  :ensure t
  :when (and (display-graphic-p) (not is-android))
  ;; :hook (kill-emacs . fontaine-store-latest-preset)
  :config
  (setq fontaine-latest-state-file
        (locate-user-emacs-file "etc/fontaine-latest-state.eld"))
  (setq fontaine-presets
        '((regular
           :default-height 120
           :default-weight regular
           :fixed-pitch-height 1.0
           :variable-pitch-height 1.0
           )
          (large
           :default-height 140
           :default-weight normal
           :fixed-pitch-height 1.0
           :variable-pitch-height 1.05
           )
          (t
           :default-family "Monaco"
           :fixed-pitch-family "Monaco"
           :variable-pitch-family "Monaco"
           :italic-family "Monaco"
           :variable-pitch-weight normal
           :bold-weight bold
           :italic-slant italic
           :line-spacing 0.1)
          ))
  ;; (fontaine-set-preset (or (fontaine-restore-latest-preset) 'regular))
  (fontaine-set-preset 'regular)

  ;; set emoji font
  (set-fontset-font
   t
   (if (version< emacs-version "28.1")
       '(#x1f300 . #x1fad0)
     'emoji)
   (cond
    ((member "Segoe UI Emoji" (font-family-list)) "Segoe UI Emoji")
    ((member "Noto Emoji" (font-family-list)) "Noto Emoji")
    ((member "Symbola" (font-family-list)) "Symbola")
    ((member "Apple Color Emoji" (font-family-list)) "Apple Color Emoji")
    ((member "Noto Color Emoji" (font-family-list)) "Noto Color Emoji")
    ))

  ;; set Chinese font
  (dolist (charset '(kana han symbol cjk-misc bopomofo))
    (set-fontset-font
     (frame-parameter nil 'font)
     charset
     (font-spec :family
                (cond
                 ((member "LXGW WenKai Screen" (font-family-list)) "LXGW WenKai Screen")
                 ((member "Sarasa Mono SC Nerd" (font-family-list)) "Sarasa Mono SC Nerd")
                 ((member "PingFang SC" (font-family-list)) "PingFang SC")
                 ((member "WenQuanYi Zen Hei" (font-family-list)) "WenQuanYi Zen Hei")
                 ((member "Microsoft YaHei" (font-family-list)) "Microsoft YaHei")
                 ))))

  ;; (set-face-attribute 'default nil :font (font-spec :family "ia Writer" :size 14))
  ;; (set-fontset-font t 'unicode (font-spec :family "Noto Color Emoji" :size 14))
  ;; (set-fontset-font t '(#x2ff0 . #x9ffc) (font-spec :family "LXGW WenKai Screen" :size 18 :weight 'bold))
  ;; (set-fontset-font t 'emoji (font-spec :family "Apple Color Emoji") nil 'prepend)
  ;; (set-fontset-font t '(#x2ff0 . #x9ffc) (font-spec :name "TsangerJinKai01" :size 14))
  ;; (set-fontset-font t 'unicode-bmp (font-spec :name "JuliaMono" :size 12) nil 'prepend)

  ;; set Chinese font scale
  (setq face-font-rescale-alist `(
                                  ("LXGW WenKai Screen"  . 1.24)
                                  ("Symbola"             . 1.3)
                                  ("Microsoft YaHei"     . 1.2)
                                  ("WenQuanYi Zen Hei"   . 1.2)
                                  ("Sarasa Mono SC Nerd" . 1.2)
                                  ("PingFang SC"         . 1.16)
                                  ("Lantinghei SC"       . 1.16)
                                  ("Kaiti SC"            . 1.16)
                                  ("Yuanti SC"           . 1.16)
                                  ("Apple Color Emoji"   . 0.91)
                                  ))
  )

Basic libraries

(use-package async :defer t)
(use-package bind-key :defer t)
(use-package marquee-header :defer t)  ; This is really an interesting package.
(use-package dash :defer t)
(use-package ts :defer t)
(use-package s :defer t)
(use-package reveal-in-osx-finder :if (not is-android) :defer t)
(use-package crux :defer t)
(use-package ranger :defer t)  ; The ranger mode
(use-package vlf :defer t)  ; View large files
;; Persist history over Emacs restarts. Vertico sorts by history position.
(use-package savehist :straight nil :hook (after-init . savehist-mode))

;; Check https://emacs-china.org/t/emacs-builtin-mode/11937
;; Winner mode
(use-package winner :straight nil :hook (after-init . winner-mode))
;; Highlight current line
(use-package hl-line :straight nil :hook (after-init . global-hl-line-mode))
;; Remember the cursor position of files
(use-package saveplace :straight nil :hook (after-init . save-place-mode))
(use-package so-long :straight nil :config (global-so-long-mode 1))

(use-package paren :defer t :config
  (setq show-paren-when-point-inside-paren t
        show-paren-when-point-in-periphery t)
  (show-paren-mode))
(use-package simple :straight nil
  :hook (after-init . (lambda ()
                        (line-number-mode)
                        (column-number-mode)
                        (size-indication-mode)
                        ;; better line wrapping for cjk. Try =toggle-word-wrap=
                        ;; (setq-default word-wrap nil)
                        ;; (setq word-wrap nil)
                        )))

(modify-syntax-entry ?_ "w")

Scroll bar

nyan-modehttps://github.com/TeMPOraL/nyan-mode/
yascroll.elhttps://github.com/emacsorphanage/yascroll

Magit

diff-hlHightlight uncommitted changeshttps://github.com/dgutov/diff-hl
(use-package magit
  :straight nil  ; built-in
  :after (project)
  :defer t
  :init
  (setq magit-diff-refine-hunk t)
  :config
  (use-package magit-extras
    :straight nil
    :init
    (setq magit-bind-magit-project-status t)
    )
  (add-hook 'magit-diff-mode-hook #'(lambda () (visual-line-mode t)))
  (add-hook 'magit-status-mode-hook #'(lambda () (visual-line-mode t)))
  )
(use-package git-link :defer t)
(use-package forge :after (magit) :defer t)
;; (use-package git-timemachine)

(use-package diff-hl
  :defer t
  :after (magit)
  :config
  (global-diff-hl-mode)
  (add-hook 'magit-pre-refresh-hook 'diff-hl-magit-pre-refresh)
  (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh))
(use-package blamer
  :ensure t
  :bind (("s-i" . blamer-show-commit-info))
  :defer 20
  :custom
  (blamer-idle-time 0.3)
  (blamer-min-offset 70)
  :custom-face
  (blamer-face ((t :foreground "#7a88cf"
                   :background unspecified
                   :height 110
                   :italic t)))
  :config
  ;; (global-blamer-mode 1)
  )

Undo

undo-treebuilt-in
undo-fu
(use-package undo-fu :ensure t)
(use-package undo-tree
  :disabled
  :config
  (setq undo-tree-visualizer-timestamps t)
  (setq undo-tree-visualizer-diff t)
  (global-undo-tree-mode))

Evil

(use-package evil
  :straight t
  :after (undo-fu)
  :init
  (setq evil-want-C-i-jump nil)
  (setq evil-move-beyond-eol t)
  :config
  ;; Use man (instead of WoMan) for man pages, although is slow in Emacs.
  ;; Install man-db, check this: https://www.reddit.com/r/emacs/comments/mfmg3x/disabling_ivy_for_a_specific_command/
  (evil-define-motion evil-lookup ()
    "Look up the keyword at point. Calls `evil-lookup-func'."
    (call-interactively #'man))

  (setq evil-want-fine-undo t)
  (define-key evil-normal-state-map (kbd "C-u") 'evil-scroll-up)
  (evil-set-undo-system 'undo-fu)
  (use-package evil-numbers
    :demand t
    :config
    (define-key evil-normal-state-map (kbd "C-a") 'evil-numbers/inc-at-pt)
    (define-key evil-normal-state-map (kbd "C-S-a") 'evil-numbers/dec-at-pt))
  ;; Evil rebind
  ;; :q should kill the current buffer rather than quitting emacs entirely
  (defun mk/ex-quit ()
    "Evil ex quit."
    (interactive)
    (if (one-window-p "visible")
        (kill-this-buffer)
      (evil-window-delete)))
  (evil-ex-define-cmd "q" #'mk/ex-quit)
  ;; Need to type out :quit to close emacs
  (evil-ex-define-cmd "quit" 'evil-quit)
  (if (featurep 'ef-themes)
      (ef-themes-with-colors
        (setq evil-emacs-state-cursor `((bar . 3) ,cursor))
        (setq evil-insert-state-cursor `((bar . 1) ,cursor)))
    (setq evil-emacs-state-cursor '((bar . 3) "#E90074"))
    (setq evil-insert-state-cursor '((bar . 1) "#874CCC"))
    )
  ;; Disable Evil in snails-mode
  (dolist (nonevil-mode '(snails-mode
                          notdeft-mode
                          vterm-mode
                          netease-cloud-music-mode
                          cnfonts-ui-mode
                          Ilist-mode
                          TeX-output-mode
                          ebib-index-mode
                          ebib-entry-mode
                          ebib-strings-mode
                          minibuffer-mode
                          corfu-mode
                          motd-message-mode
                          elfeed-search-mode
                          elfeed-show-mode
                          special-mode
                          ))
    (evil-set-initial-state nonevil-mode 'emacs))

  (evil-mode 1))

Evil: Easy Motion

evil-easymotionhttps://github.com/PythonNut/evil-easymotion
evil-snipehttps://github.com/hlissner/evil-snipe
avyhttps://github.com/abo-abo/avy
(use-package avy)
(use-package evil-easymotion
  :after (evil)
  :demand t
  :config
  (evilem-default-keybindings "SPC")

  (defun avy-goto-char (char &optional arg)
    "Jump to the currently visible CHAR.
     The window scope is determined by `avy-all-windows' (ARG negates it)."
    (interactive (list (read-char "char: " t)
                       current-prefix-arg))
    (if (= ?  char)
        (call-interactively 'execute-extended-command)
      (avy-with avy-goto-char
        (avy-jump
         (if (= 13 char)
             "\n"
           (regexp-quote (string char)))
         :window-flip arg))))
  (define-key evil-normal-state-map (kbd "SPC") 'avy-goto-char))

Evil: Magit

;; optional: this is the evil state that evil-magit will use
;; (setq evil-magit-state 'normal)
;; optional: disable additional bindings for yanking text
;; (setq evil-magit-use-y-for-yank nil)
(use-package evil-magit
  :after (evil magit)
  :defer t)

Dir

(use-package neotree :defer t)
;; (use-package perspective :config (persp-mode))

Ctrl-f

(use-package ctrlf
  :defer t
  :config
  (ctrlf-mode +1))

smart-tab

;;; Smart Tab
(use-package smart-tab
  :straight nil
  :defer t
  :config
  (smart-tabs-insinuate 'c 'javascript))

whitespace

whitespaceBuilt-inhttp://ergoemacs.org/emacs/whitespace-mode.html
;;; Use whitespace (instead of column-marker, column-enforce-mode)
(use-package whitespace
  :ensure nil
  :config
  (setq whitespace-style
        '(face trailing tabs newline tab-mark newline-mark))
  ;; '(face trailing tabs newline tab-mark newline-mark lines-tail)
  (setq whitespace-display-mappings
        '((newline-mark 10 [8617 10])
          (tab-mark 9 [8594 9] [92 9])))
  (set-face-background 'trailing-whitespace "#ffaf5f")
  (set-face-background 'whitespace-trailing "#ffaf5f")
  (if mk-feature/gui
      (set-face-background 'whitespace-tab "#FAFAFA")
    (set-face-background 'whitespace-tab "undefined")
    )
  ;; (global-whitespace-mode t)
  (add-hook 'prog-mode-hook 'whitespace-mode)
  )

Which-Key

Emacs package that displays available keybindings in popup

which-keyhttps://github.com/justbur/emacs-which-key
;; which-key is a fork of guide-key
(use-package which-key
  :bind (
         ("C-h ,m" . which-key-show-major-mode)
         ("C-h ,t" . which-key-show-top-level)
         ("C-h ,n" . which-key-show-next-page)
         )
  :init
  (setq which-key-show-remaining-keys t)

  (setq which-key-show-early-on-C-h t)
  (setq which-key-idle-delay 2)
  (setq which-key-allow-imprecise-window-fit t)
  (setq which-key-sort-order 'which-key-prefix-then-key-order)
  ;; (which-key-setup-minibuffer)
  (which-key-mode)
  )

Rainbow

(use-package rainbow-mode
  :defer t
  :config (rainbow-mode t))
(use-package rainbow-delimiters
  :defer t
  :hook (prog-mode . rainbow-delimiters-mode))
(use-package highlight-indent-guides :defer t)

Calender

;; https://raw.githubusercontent.com/wowhxj/emacs-from-scratch/master/emacs-config.org
(use-package calendar
  :init
  (setq calendar-longitude 121.4737
        calendar-latitude 31.2304
        calendar-location-name "SH")
  :ensure nil
  :hook (calendar-today-visible . calendar-mark-today)
  :custom
  ;; 是否显示中国节日,我们使用 `cal-chinese-x' 插件
  (calendar-chinese-all-holidays-flag nil)
  ;; 是否显示节日
  (calendar-mark-holidays-flag t)
  ;; 是否显示Emacs的日记,我们使用org的日记
  (calendar-mark-diary-entries-flag nil)
  ;; 数字方式显示时区,如 +0800,默认是字符方式如 CST
  (calendar-time-zone-style 'numeric)
  ;; 日期显示方式:year/month/day
  (calendar-date-style 'iso)
  ;; 中文天干地支设置
  (calendar-chinese-celestial-stem ["" "" "" "" "" "" "" "" "" ""])
  (calendar-chinese-terrestrial-branch ["" "" "" "" "" "" "" "" "" "" "" ""])
  ;; 设置中文月份
  (calendar-month-name-array ["一月" "二月" "三月" "四月" "五月" "六月" "七月" "八月" "九月" "十月" "十一月" "十二月"])
  ;; 设置星期标题显示
  (calendar-day-name-array ["" "" "" "" "" "" ""])
  ;; 周一作为一周第一天
  (calendar-week-start-day 0)
  )
;; 时间解析增加中文拼音
(use-package parse-time
  :ensure nil
  :defer t
  :config
  (setq parse-time-months
        (append '(("yiy" . 1) ("ery" . 2) ("sany" . 3)
                  ("siy" . 4) ("wuy" . 5) ("liuy" . 6)
                  ("qiy" . 7) ("bay" . 8) ("jiuy" . 9)
                  ("shiy" . 10) ("shiyiy" . 11) ("shiery" . 12)
                  ("yiyue" . 1) ("eryue" . 2) ("sanyue" . 3)
                  ("siyue" . 4) ("wuyue" . 5) ("liuyue" . 6)
                  ("qiyue" . 7) ("bayue" . 8) ("jiuyue" . 9)
                  ("shiyue" . 10) ("shiyiyue" . 11) ("shieryue" . 12))
                parse-time-months))

  (setq parse-time-weekdays
        (append '(("zri" . 0) ("zqi" . 0)
                  ("zyi" . 1) ("zer" . 2) ("zsan" . 3)
                  ("zsi" . 4) ("zwu" . 5) ("zliu" . 6)
                  ("zr" . 0) ("zq" . 0)
                  ("zy" . 1) ("ze" . 2) ("zs" . 3)
                  ("zsi" . 4) ("zw" . 5) ("zl" . 6))
                parse-time-weekdays)))

;; 中国节日设置
(use-package cal-china-x
  :ensure t
  :commands cal-china-x-setup
  :hook (after-init . cal-china-x-setup)
  :config
  ;; 重要节日设置
  (setq cal-china-x-important-holidays cal-china-x-chinese-holidays)
  ;; 所有节日设置
  (setq cal-china-x-general-holidays
        '(;;公历节日
          (holiday-fixed 1 1 "元旦")
          (holiday-fixed 2 14 "情人节")
          (holiday-fixed 3 8 "妇女节")
          (holiday-fixed 4 1 "愚人节")
          (holiday-fixed 5 1 "劳动节")
          (holiday-fixed 5 4 "青年节")
          (holiday-float 5 0 2 "母亲节")
          (holiday-fixed 6 1 "儿童节")
          (holiday-float 6 0 3 "父亲节")
          (holiday-fixed 9 10 "教师节")
          (holiday-fixed 10 1 "国庆节")
          (holiday-fixed 12 25 "圣诞节")
          ;; 农历节日
          (holiday-lunar 12 30 "除夕" 0)
          (holiday-lunar 1 1 "春节" 0)
          (holiday-lunar 1 15 "元宵" 0)
          (holiday-solar-term "清明" "清明")
          (holiday-solar-term "小寒" "小寒")
          (holiday-solar-term "大寒" "大寒")
          (holiday-solar-term "立春" "立春")
          (holiday-solar-term "雨水" "雨水")
          (holiday-solar-term "惊蛰" "惊蛰")
          (holiday-solar-term "春分" "春分")
          (holiday-solar-term "谷雨" "谷雨")
          (holiday-solar-term "立夏" "立夏")
          (holiday-solar-term "小满" "小满")
          (holiday-solar-term "芒种" "芒种")
          (holiday-solar-term "夏至" "夏至")
          (holiday-solar-term "小暑" "小暑")
          (holiday-solar-term "大暑" "大暑")
          (holiday-solar-term "立秋" "立秋")
          (holiday-solar-term "处暑" "处暑")
          (holiday-solar-term "白露" "白露")
          (holiday-solar-term "秋分" "秋分")
          (holiday-solar-term "寒露" "寒露")
          (holiday-solar-term "霜降" "霜降")
          (holiday-solar-term "立冬" "立冬")
          (holiday-solar-term "小雪" "小雪")
          (holiday-solar-term "大雪" "大雪")
          (holiday-solar-term "冬至" "冬至")
          (holiday-lunar 5 5 "端午" 0)
          (holiday-lunar 8 15 "中秋" 0)
          (holiday-lunar 7 7 "七夕" 0)
          (holiday-lunar 9 9 "重阳" 0)))
  ;; 设置日历的节日,通用节日已经包含了所有节日
  (setq calendar-holidays (append cal-china-x-general-holidays)))
;; (setq mark-holidays-in-calendar t)

Calfw - A calendar framework for Emacs

Calfwhttps://github.com/kiwanami/emacs-calfw
(use-package calfw
  :init
  (use-package calfw-org :after (org))
  :config
  (defun mk/open-calendar ()
    (interactive)
    (cfw:open-calendar-buffer
     :contents-sources
     (list
      (cfw:org-create-source "Green")  ; orgmode source
      ;; (cfw:howm-create-source "Blue")  ; howm source
      ;; (cfw:cal-create-source "Orange") ; diary source
      ;; (cfw:ical-create-source "Moon" "~/moon.ics" "Gray")  ; ICS source1
      ;; (cfw:ical-create-source "gcal" "https://..../basic.ics" "IndianRed") ; google calendar ICS
      )))
  )

vterm

(use-package vterm
  :defer t
  :config
  (defun vterm-new()
    "Add a new vterm session with given name."
    (interactive)
    (let ((session-name (string-trim (read-string "Enter the name for the session: "))))
      (vterm session-name)
      )))
(use-package vterm-toggle
  :straight (:host github :repo "jixiuf/vterm-toggle")
  :config
  (global-set-key (kbd "C-c t") 'vterm-toggle)
  (global-set-key [C-f2] 'vterm-toggle-cd)

  ;; you can cd to the directory where your previous buffer file exists
  ;; after you have toggle to the vterm buffer with `vterm-toggle'.
  (define-key vterm-mode-map [(control return)]   #'vterm-toggle-insert-cd)

                                        ;Switch to next vterm buffer
  (define-key vterm-mode-map (kbd "s-n")   'vterm-toggle-forward)
                                        ;Switch to previous vterm buffer
  (define-key vterm-mode-map (kbd "s-p")   'vterm-toggle-backward)
  )

Sidebar

(use-package imenu-list
  :after (org)
  :demand
  :bind (("C-\"" . #'imenu-list-smart-toggle))
  :config
  (setq imenu-list-auto-resize nil)
  (setq imenu-list-position 'left)
  (setq org-imenu-depth 5)
  )
(use-package org-sidebar :defer t)

M-x and Auto-completion

M-x: Vertico

Alternatives (Check the selectrum repo README)

Ido
Helm
Ivy
Icomplete
Icicles
Snallet
Raven
Swiper
Selectrumhttps://github.com/raxod502/selectrum
verticohttps://github.com/minad/vertico
Snailshttps://github.com/manateelazycat/snails
For Selectrum/vertico
consulthttps://github.com/minad/consult
marginaliahttps://github.com/minad/marginaliaAlternative to ivy-rich
Embarkhttps://github.com/oantolin/embark/Minibuffer actions (ivy has builtin alternative)
mini-popup“minad/mini-popup”
mini-frame
(use-package vertico
  :init

  (setq vertico-scroll-margin 0)
  (setq vertico-count 20)  ; Show more candidates.
  (setq vertico-resize nil)  ; Do NOT grow and shrink the Vertico minibuffer.
  (setq vertico-cycle t)  ; Cycling the candidates. E.g., the next to the last is the first.

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

  (setq enable-recursive-minibuffers nil)
  (vertico-mode)
  )
(use-package orderless
  :init
  (setq completion-styles '(orderless))
  (setq completion-category-defaults nil)
  (setq completion-category-overrides '((file (styles partial-completion))))
  )
(use-package marginalia
  :init
  (marginalia-mode))

(use-package rg
  :ensure-system-package
  (rg . ripgrep))

(use-package consult
  :bind (
         ;; 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 r b" . consult-bookmark)            ;; orig. bookmark-jump
         ("C-x p b" . consult-project-buffer)      ;; orig. project-switch-to-buffer
         ;; Custom M-# bindings for fast register access
         ;; Other custom bindings
         ("M-g i" . consult-imenu)
         ("M-g I" . consult-imenu-multi)
         ;; M-s bindings (search-map)
         ("M-s d" . consult-find)
         ("M-s D" . consult-locate)
         ("M-s g" . consult-grep)
         ("M-s G" . consult-git-grep)
         ("M-s r" . consult-ripgrep)
         ("M-s l" . consult-line)
         ("M-s L" . consult-line-multi)
         ("M-s m" . consult-multi-occur)
         ("M-s k" . consult-keep-lines)
         ("M-s u" . consult-focus-lines)
         ;; Isearch integration
         ("M-s e" . consult-isearch-history)
         :map isearch-mode-map
         ("M-e" . consult-isearch-history)         ;; orig. isearch-edit-string
         ("M-s e" . consult-isearch-history)       ;; orig. isearch-edit-string
         ("M-s l" . consult-line)                  ;; needed by consult-line to detect isearch
         ("M-s L" . consult-line-multi))           ;; needed by consult-line to detect isearch

  :hook (completion-list-mode . consult-preview-at-point-mode)
  :init
  ;; Configure the register formatting
  (setq register-preview-delay 0)
  (setq register-preview-function #'consult-register-format)
  ;; Use Consult to select xref locations with preview
  (setq xref-show-xrefs-function #'consult-xref)
  (setq xref-show-definitions-function #'consult-xref)

  ;; 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-package all-the-icons-completion
;;   :after (all-the-icons marginalia)
;;   :init
;;   (all-the-icons-completion-mode)
;;   (add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup))

(use-package embark
  :demand
  :bind
  (("C-." . embark-act)         ;; pick some comfortable binding
   ("C-;" . embark-dwim)        ;; good alternative: M-.
   ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'
  :init
  ;; Optionally replace the key help with a completing-read interface
  (setq prefix-help-command #'embark-prefix-help-command)
  :config
  ;; Hide the mode line of the Embark live/completions buffers
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none)))))

;; Consult users will also want the embark-consult package.
(use-package embark-consult
  :after (embark consult)
  :demand t ; only necessary if you have the hook below
  ;; if you want to have consult previews as you move around an
  ;; auto-updating embark collect buffer
  :hook
  (embark-collect-mode . consult-preview-at-point-mode))

Auto-completion

company-modehttps://github.com/company-mode/company-mode
Corfuhttps://github.com/minad/corfu
Cape (use with Corfu)https://github.com/minad/cape
lsp-bridge
;; A few more useful configurations...
(use-package emacs
  :init
  ;; TAB cycle if there are only few candidates
  ;; (setq completion-cycle-threshold 3)

  ;; Enable indentation+completion using the TAB key.
  ;; `completion-at-point' is often bound to M-TAB.
  (setq tab-always-indent 'complete)

  ;; Emacs 30 and newer: Disable Ispell completion function. As an alternative,
  ;; try `cape-dict'.
  (setq text-mode-ispell-word-completion nil)

  ;; Hide commands in M-x which do not apply to the current mode.  Corfu
  ;; commands are hidden, since they are not used via M-x. This setting is
  ;; useful beyond Corfu.
  (setq read-extended-command-predicate #'command-completion-default-include-p))

Templating: Yasnippet

yasnippethttps://github.com/joaotavora/yasnippet
TempElhttps://github.com/minad/tempel
(use-package yasnippet
  :init (yas-global-mode 1))
(use-package yasnippet-snippets
  :after yasnippet)

LSP

lsp-mode
eglotBuilt-in since Emacs 29
nox
LSPCE
flycheckpopular alternative to flymake
flymakeThe rewritten built-in flymake is sufficient good
flyspellThis is the real spell checker
flycheck-languagetool
flycheck-grammarly
grammarlythe reverse-engineered API lib
flymake-grammarly
flymake-languagetool
lsp-ltex
languagetool
(use-package flymake
  :straight (:type built-in)  ; built-in
  :config
  (setq flymake-no-changes-timeout 2)
  )

(use-package flyspell-correct
  :after flyspell
  :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper)))

(use-package grammarly
  :straight (:host github :repo "emacs-grammarly/grammarly")
  :config
  (grammarly-load-from-authinfo)
  )
(use-package flymake-grammarly
  :straight (:host github :repo "emacs-grammarly/flymake-grammarly")
  :after grammarly
  :config
  )
(use-package lsp-grammarly
  :disabled t
  :ensure t
  :hook (text-mode . (lambda ()
                       (require 'lsp-grammarly)
                       (lsp))))  ; or lsp-deferred

(use-package lsp-bridge
  :straight '(lsp-bridge :type git :host github :repo "manateelazycat/lsp-bridge"
                         :files (:defaults "*.el" "*.py" "acm" "core" "langserver" "multiserver" "resources")
                         :build (:not compile))
  :init
  ;; (setq lsp-bridge-tex-lsp-server "texlab-grammarly")
  (setq lsp-bridge-enable-hover-diagnostic t)
  (setq acm-enable-capf t)
  (setq acm-enable-doc t)
  (setq acm-enable-doc-markdown-render 'async)
  (setq acm-enable-icon t)
  (setq acm-enable-tabnine t)
  (setq acm-enable-quick-access t)
  (setq acm-enable-citre t)
  (setq acm-backend-search-file-words-candidate-min-length 3)
  (setq acm-backend-lsp-show-progress t)
  (setq acm-backend-yas-candidate-min-length 2)
  (setq acm-backend-elisp-candidate-min-length 2)
  (setq acm-backend-search-file-words-enable-fuzzy-match t)
  (setq acm-backend-search-file-words-enable-fuzzy-match-threshold 1)

  (setq acm-backend-lsp-match-mode "prefix")
  (setq acm-backend-lsp-frontend-filter-p t)

  (global-lsp-bridge-mode))

Programming and Coding

Citre: Tag jumps

(use-package citre
  :defer t
  :after (evil)
  :init
  ;; This is needed in `:init' block for lazy load to work.
  (require 'citre-config)
  :config
  ;; Bind your frequently used commands.
  (global-set-key (kbd "C-x c j") 'citre-jump)
  (global-set-key (kbd "C-x c J") 'citre-jump-back)
  (global-set-key (kbd "C-x c p") 'citre-ace-peek)
  (global-set-key (kbd "C-]") 'citre-jump)
  (global-set-key (kbd "C-t") 'citre-jump-back)
  (define-key evil-motion-state-map (kbd "C-]") 'citre-jump)
  (define-key evil-motion-state-map (kbd "C-t") 'citre-jump-back)
  (define-key evil-normal-state-map (kbd "C-]") 'citre-jump)
  (define-key evil-normal-state-map (kbd "C-t") 'citre-jump-back)
  (setq citre-project-root-function
        #'(lambda ()
            (when-let ((project (project-current nil)))
              (expand-file-name (nth 2 project)))))
  )

Programming mode

;; Built-in native line number display
(use-package display-line-numbers
  :straight nil
  :hook (prog-mode . display-line-numbers-mode)
  :config
  ;; (setq-default display-line-numbers-width 3)
  )

(use-package ws-butler
  :delight ws-butler-mode
  :config (progn
            ;; adding it to prog-mode-hook causes problems for emacsclient
            (add-hook 'cython-mode-hook     #'ws-butler-mode)
            (add-hook 'LaTeX-mode-hook      #'ws-butler-mode)
            (add-hook 'emacs-lisp-mode-hook #'ws-butler-mode)))

C/C++

;; style I want to use in c++ mode
(c-add-style "my-style"
             '("stroustrup"
               (c-basic-offset . 4)            ; indent by four spaces
               (tab-width . 4)
               (indent-tabs-mode . t)        ; use tabs
               (c-offsets-alist . ((inline-open . 0)  ; custom indentation rules
                                   (brace-list-open . 0)
                                   (innamespace . [0])
                                   (statement-case-open . +)))))

(use-package c-ts-mode
  :bind (:map c-ts-base-mode-map
              ("M-<up>" . drag-stuff-up)
              ("M-<down>" . drag-stuff-down)
              ("<home>"  .  malb/beginning-of-line-dwim))
  :hook ((c-ts-base-mode . hs-minor-mode)
         (c-ts-base-mode . display-line-numbers-mode)
         (c-ts-base-mode . ws-butler-mode)
         ;; (c-ts-base-mode . ggtags-mode)
         ;; (c-ts-base-mode . helm-gtags-mode)
         (c-ts-base-mode . clang-format+-mode))
  :init (progn
          (add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode))
          (add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode))
          (add-to-list 'auto-mode-alist '("\\.inl\\'" . c++-ts-mode))))

(use-package clang-format :config (setq clang-format-executable "clang-format"))
(use-package clang-format+ :commands clang-format+-mode)

LaTeX

(use-package tex
  :straight auctex
  :defer t
  :init
  (setq TeX-source-correlate-method 'synctex)
  (setq TeX-source-correlate-mode t)
  (setq TeX-source-correlate-start-server t)
  (provide 'tex-buf)  ; We don't have tex-buf anymore, just add this to make some packages happy.

  :config
  ;; make latexmk available via C-c C-c
  ;; Note: SyncTeX is setup via ~/.latexmkrc (see below)
  ;; (add-to-list 'TeX-command-list '("latexmk" "latexmk -pdf -escape-shell %s" TeX-run-TeX nil t :help "Run latexmk on file"))
  (message "OK")
  (add-to-list 'TeX-command-list '("Make" "make" TeX-run-command nil t))
  (add-to-list 'TeX-command-list '("Make Clean" "make clean" TeX-run-command nil t))
  (add-to-list 'TeX-command-list '("Make Clean & Make" "make clean && make" TeX-run-command nil t))
  ;; "texcount article.tex -inc -incbib -sum"
  (add-to-list 'TeX-command-list '("Make Count" "make count" TeX-run-command nil t))
  ;; (setq-default TeX-command-default "Make")
  ;; from https://gist.github.com/stefano-meschiari/9217695
  (setq TeX-auto-save t)
  (setq Tex-parse-self t)
  ;; Guess/Ask for the master file.
  (setq-default TeX-master nil)


  ;; Thank https://tex.stackexchange.com/a/167097/122482
  (defun mk/shadow-iffalse-block ()
    (font-lock-add-keywords
     'latex-mode
     '(("\\\\iffalse\\(\\(.\\|\n\\)*\\)\\\\fi" 0 'font-lock-comment-face append))
     t))
  (add-hook 'latex-mode-hook #'mk/shadow-iffalse-block)

  (add-hook 'TeX-mode-hook (lambda () (setq TeX-command-default "Make")))
  (add-hook 'LaTeX-mode-hook (lambda()
                               (mkvoya/better-wrap)
                               (flyspell-mode)
                               ;; (add-hook 'after-save-hook #'flyspell-buffer)
                               (LaTeX-math-mode)
                               (darkroom-mode)
                               (setq buffer-face-mode-face '(:family "iA Writer Quattro V"))
                               (buffer-face-mode)
                               (visual-line-mode)
                               (visual-line-mode)
                               (darkroom-decrease-margins 0.8)
                               ))
  ;; (add-hook 'TeX-output-mode (lambda () (goto-char (point-max))))

  (setq reftex-refstyle "\\ref")
  (setq reftex-plug-into-AUCTeX t)
  (setq TeX-PDF-mode t)

  (setq TeX-view-program-selection '((output-pdf "PDF Viewer")))
  (setq TeX-view-program-list
        '(("PDF Viewer" "/Applications/Skim.app/Contents/SharedSupport/displayline -b -g %n %o %b")))

  (setq TeX-error-overview-open-after-TeX-run t)
  ;; (setq mkvoya/tex-auto-compile nil)
  ;; (defun mkvoya/tex-try-auto-compile ()
  ;;   (when (and (eq major-mode 'TeX-mode)
  ;;              (mkvoya/tex-auto-compile))
  ;;     (TeX-command-run))
  ;;   )
  ;; (add-hook 'after-save-hook #'mkvoya/tex-try-auto-compile)

  (add-hook 'TeX-after-compilation-finished-functions #'TeX-revert-document-buffer)

  (use-package reftex
    :defer t
    :config
    (add-hook 'LaTeX-mode-hook 'turn-on-reftex)   ; with AUCTeX LaTeX mode
    (add-hook 'latex-mode-hook 'turn-on-reftex)   ; with Emacs latex mode
    ;; (setq reftex-default-bibliography '("./references.bib"))
    )
  ;; (use-package auctex-latexmk :config (auctex-latexmk-setup))
  ;; https://emacs.stackexchange.com/a/63195/30542
  (defun my-LaTeX-mode-setup ()
    (font-latex-add-keywords '(("autoref" "*{") ("Autoref" "{") ("nameref" "*{"))
                             'reference))

  (add-hook 'LaTeX-mode-hook #'my-LaTeX-mode-setup)
  )

;; Show build progress in modeline
(use-package procress
  :straight (:host github :repo "haji-ali/procress")
  :commands procress-auctex-mode
  :init
  (add-hook 'LaTeX-mode-hook #'procress-auctex-mode)
  :config
  (procress-load-default-svg-images))

;; https://emacs.stackexchange.com/questions/45546/per-mode-value-for-fill-column
(defun mkvoya/tex-mode-hook ()
  (setq fill-column 1024))
(add-hook 'TeX-mode-hook #'mkvoya/tex-mode-hook)

PDF Tools

(use-package pdf-tools :defer t
  :if mk-feature/gui
  :init
  :mode ("\\.pdf\\'" . pdf-view-mode)
  :magic ("%PDF" . pdf-view-mode)
  :bind (:map pdf-view-mode-map
         ("<wheel-right>" . image-forward-hscroll)
         ("<wheel-left>" . image-backward-hscroll)
         ("<pinch>" . mk/pdf-tools-scale-pinch)
         )
  :config

  (defun mk/pdf-tools-scale-pinch (event)
    "Adjust the height of the default face by the scale in the pinch event EVENT."
    (interactive "e")
    (when (not (eq (event-basic-type event) 'pinch))
      (error "bad event type"))
    (let ((window (posn-window (nth 1 event)))
          (scale (nth 4 event))
          (dx (nth 2 event))
          (dy (nth 3 event))
          (angle (nth 5 event)))
      (with-selected-window window
        (when (< scale 1)
          (pdf-view-shrink 1.1))
        (when (> scale 1)
          (pdf-view-enlarge 1.1)))))
  (pdf-loader-install)
  (add-hook 'pdf-view-mode-hook #'(lambda () (pixel-scroll-precision-mode -1)))
  )

Tramp

(use-package tramp
  :straight nil
  :init
  (use-package tramp-sh :straight nil :defer t)
  ;; (setq tramp-debug-buffer t)
  (setq tramp-verbose 10)
  (setq tramp-ssh-controlmaster-options
        (concat
         "-o ControlPath=/Volumes/ramfs/ssh-ControlPath-%%r@%%h:%%p "
         "-o ControlMaster=auto -o ControlPersist=yes"))

  :defer t
  :config

  (setq tramp-remote-path
        (append tramp-remote-path
                '(tramp-own-remote-path)))

  ;; Speedup the C++ file over Tramp.
  (setq remote-file-name-inhibit-cache nil)
  (setq vc-ignore-dir-regexp
        (format "%s\\|%s"
                vc-ignore-dir-regexp
                tramp-file-name-regexp))
  (setq tramp-verbose 1)
  )

Mail Client

notmuch
WanderLust

Feeding (RSS & Atom)

elfeedhttps://github.com/skeeto/elfeed
(use-package elfeed
  :if mk-feature/news-mail
  :defer t
  :bind ("C-c f" . elfeed)
  :config
  ;; The feed list
  (setq elfeed-feeds
        '(("http://nullprogram.com/feed/" blog emacs)
          "http://www.50ply.com/atom.xml"  ; no autotagging
          ;; Apple news
          ("https://feeds.macrumors.com/MacRumors-All" apple)
          ;; storage news
          ("https://thessdguy.com/feed/" storage)
          ("https://thememoryguy.com/feed/" storage)
          ("https://blocksandfiles.com/feed/" storage)
          ;; ("https://thesanguy.com/feed/" storage) website down
          ;;
          ("https://www.nextplatform.com/feed/" it)
          ("https://devclass.com/feed/" it)
          ("https://www.theregister.com/headlines.atom" it)
          ("http://ithare.com/rssfeed/" it)
          ("http://nedroid.com/feed/" webcomic)
          "http://planet.emacsen.org/atom.xml"))
  (setq-default elfeed-search-filter "@1-week-ago +unread ")
  )

Language, Spelling and Writing

Input method

pyimEmacs input method
sisSmart input source
emacs-rime
(use-package rime
  :straight (rime :type git
                  :host github
                  :repo "DogLooksGood/emacs-rime"
                  :files ("*.el" "Makefile" "lib.c"))
  :custom
  (default-input-method "rime")
  (rime-librime-root "~/.emacs.d/librime/dist")
  (rime-share-data-dir "~/Library/Rime")
  (rime-user-data-dir "~/Library/Rime")
  (rime-emacs-module-header-root "/opt/homebrew/opt/emacs-plus@30/include")
  (rime-show-candidate 'posframe)
  (rime-posframe-properties
   (list :background-color "#000000"  ; 不要在这里设置字体,会影响后面 face 里字体的
         :foreground-color "#f33333"
         :internal-border-width 3
         :internal-border-color "#5fc187"))
  :config
  (set-face-attribute 'rime-default-face nil
                      :background "#000000"
                      :foreground "honeydew1"
                      :font "Hei-20")
  (set-face-attribute 'rime-highlight-candidate-face nil
                      :background "#5fc187"
                      :foreground "#efefef"
                      :font "Hei-20")
  (set-face-attribute 'rime-candidate-num-face nil
                      :background "#000000"
                      :foreground "#5fc187"
                      :font "Hei-20")
  (set-face-attribute 'rime-code-face nil
                      :background "#719ae7"
                      :foreground "#efefef"
                      :font "Hei-20")
  )

CJK font jumping

(setq word-wrap-by-category t)
(use-package jieba
  :disabled t
  :if (not is-android)
  :delight
  :after (evil)
  :straight (:host github :repo "mkvoya/jieba.el" :files ("*"))
  :init  ; We need to enable jieba during init so that it can construct the jieba in background, rather than when autoloading the functions.
  (jieba-mode)
  (defun mk/forward-word()
    "mk's better forward-word."
    (interactive)
    (let ((char (char-after)))
      (if (memq char (string-to-list " \n\r\\"))
          (re-search-forward "\\\s+")
        (jieba-forward-word))))
  (define-key evil-motion-state-map (kbd "w") #'mk/forward-word)
  (define-key evil-motion-state-map (kbd "b") #'jieba-backward-word)
  )

(use-package emt
  :if (not is-android)
  :straight (:host github :repo "roife/emt"
                   :files ("*.el" "module/*" "module"))
  :hook (after-init . emt-mode)
  :config
  (define-key evil-motion-state-map (kbd "w") #'emt-forward-word)
  (define-key evil-motion-state-map (kbd "b") #'emt-backward-word)
  )

CJK font alignment

(use-package valign
  :hook (org-mode . valign-mode)
  )

Word count

(load-file "~/.emacs.d/site-lisp/wc.el")
(provide 'init-writing)
(load-file "~/.emacs.d/site-lisp/tex-autogen.el")
(use-package svg-lib :ensure t)
(load-file "~/.emacs.d/site-lisp/big-timer.el")

Appearance and UI

(use-package emacs
  :straight nil
  :config
  (setq-default prettify-symbols-alist '(("#+BEGIN_SRC" . "λ")  ; previously ✎
                                         ("#+END_SRC" . "")
                                         ("#+begin_src" . "λ")
                                         ("#+end_src" . "")
                                         ("#+begin_quote" . )
                                         ("#+end_quote" . )
                                         ("#+BEGIN_QUOTE" . )
                                         ("#+END_QUOTE" . )
                                         ))
  (global-prettify-symbols-mode)

  (setq-default indicate-buffer-boundaries 'left)
  (setq window-divider-default-right-width 2)
  (setq window-divider-default-bottom-width 2)
  (setq window-divider-default-places t)
  (window-divider-mode 1))
(use-package doom-modeline
  :init (doom-modeline-mode 1)
  :config
  (setq inhibit-compacting-font-caches t)
  (setq mode-line-right-align-edge 'right-fringe)

  (setq doom-modeline-icon t)
  (setq doom-modeline-major-mode-icon t)
  (setq doom-modeline-major-mode-color-icon t)
  (setq doom-modeline-buffer-state-icon t)
  (setq doom-modeline-buffer-modification-icon t)

  (setq doom-modeline-time t)
  (setq doom-modeline-time-icon t)
  (setq doom-modeline-time-live-icon t)

  (setq doom-modeline-minor-modes nil)

  (setq doom-modeline-enable-word-count nil)
  (setq doom-modeline-modal t)
  (setq doom-modeline-modal-icon nil)
  (setq doom-modeline-modal-modern-icon t)
  (setq doom-modeline-unicode-fallback t)
  (setq doom-modeline-enable-word-count t)
  (setq doom-modeline-continuous-word-count-modes '(markdown-mode gfm-mode org-mode))
  (setq doom-modeline-always-show-macro-register t)
  (setq doom-modeline-support-imenu t)
  (setq doom-modeline-bar-width 2)

  ;; (setq doom-modeline-window-width-limit 85)
  (setq doom-modeline-height 1) ; optional
  (custom-set-faces
   '(mode-line ((t (:height 0.95))))
   '(mode-line-active ((t (:height 0.95)))) ; For 29+
   '(mode-line-inactive ((t (:height 0.95))))
   '(doom-modeline-evil-emacs-state ((t (:italic nil)))))
  )

(use-package ef-themes :straight (:host github :repo "protesilaos/ef-themes")
  :after (hl-todo doom-modeline)
  :config
  (setq ef-cyprus-palette-overrides '((bg-main "#fdfefd")))
  (setq ef-themes-to-toggle '(ef-cyprus ef-frost))
  (setq ef-themes-headings ; read the manual's entry or the doc string
        '((0 variable-pitch light 1.9)
          (1 variable-pitch light 1.8)
          (2 variable-pitch regular 1.7)
          (3 variable-pitch regular 1.6)
          (4 variable-pitch regular 1.5)
          (5 variable-pitch 1.4) ; absence of weight means `bold'
          (6 variable-pitch 1.3)
          (7 variable-pitch 1.2)
          (t variable-pitch 1.1)))
  (setq ef-themes-mixed-fonts t
        ef-themes-variable-pitch-ui t)

  (defun my-ef-themes-hl-todo-faces ()
    "Configure `hl-todo-keyword-faces' with Ef themes colors.
      The exact color values are taken from the active Ef theme."
    (ef-themes-with-colors
      (setq hl-todo-keyword-faces
            `(("HOLD" . ,yellow)
              ("TODO" . ,red)
              ("NEXT" . ,blue)
              ("THEM" . ,magenta)
              ("PROG" . ,cyan-warmer)
              ("OKAY" . ,green-warmer)
              ("DONT" . ,yellow-warmer)
              ("FAIL" . ,red-warmer)
              ("BUG" . ,red-warmer)
              ("DONE" . ,green)
              ("NOTE" . ,blue-warmer)
              ("KLUDGE" . ,cyan)
              ("HACK" . ,cyan)
              ("TEMP" . ,red)
              ("FIXME" . ,red-warmer)
              ("XXX+" . ,red-warmer)
              ("REVIEW" . ,red)
              ("DEPRECATED" . ,yellow)))))
  (add-hook 'ef-themes-post-load-hook #'my-ef-themes-hl-todo-faces)

  ;; Disable all other themes to avoid awkward blending:
  (mapc #'disable-theme custom-enabled-themes)
  (ef-themes-select 'ef-cyprus)
  )

(use-package hl-todo :straight (:host github :repo "tarsius/hl-todo"))

;; (use-package org-margin :straight (:host github :repo "rougier/org-margin")
;;   :disabled t
;;   :after (org)
;;   :hook (org-mode . org-margin-mode)
;;   )

;; (set-face-attribute 'org-level-1 nil :height 1.1)
;; (set-face-attribute 'fringe nil :background nil) ; Visually hide left-right margins

(use-package keycast :straight (:type git :host github :repo "tarsius/keycast")
  :disabled
  :init (keycast-mode))

Beacon

Use holo lyaer

Smooth scrolling

sublimity
smooth-scrolling
good-scroll
;; Mouse scrolling in terminal emacs
(unless (display-graphic-p)
  ;; activate mouse-based scrolling
  ;; ensure mouse
  (xterm-mouse-mode t)
  (global-set-key (kbd "<mouse-4>") 'scroll-down-line)
  (global-set-key (kbd "<mouse-5>") 'scroll-up-line))

Dashboard

(use-package xkcd :defer)
(use-package all-the-icons)
(use-package dashboard
  :if (< (length command-line-args) 2)
  :diminish dashboard-mode
  :init
  (use-package page-break-lines :ensure t :defer nil)
  :config
  (setq dashboard-banner-logo-title "What a nice day!")
  ;;(setq dashboard-startup-banner "/path/to/image")
  (setq dashboard-projects-backend 'project-el)
  (setq dashboard-items '((recents  . 10)
                          ;; (bookmarks . 10)
                          (projects . 5)
                          (agenda . 5)
                          ;; (registers . 5)
                          ))
  (setq dashboard-set-heading-icons t)
  (setq dashboard-set-file-icons t)
  (setq dashboard-agenda-sort-strategy '(time-up todo-state-up))
  (setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")))
  (dashboard-setup-startup-hook))

Symbol Overlay

;; Thank https://github.com/Eason0210/emacs.d
(use-package symbol-overlay
  :hook ((prog-mode html-mode yaml-mode conf-mode) . symbol-overlay-mode)
  :bind (:map symbol-overlay-mode-map
              ("M-i" . symbol-overlay-put)
              ("M-n" . symbol-overlay-jump-next)
              ("M-p" . symbol-overlay-jump-prev)))

Volatile highlights

(use-package volatile-highlights
  :delight
  :straight (:host github :repo "k-talo/volatile-highlights.el")
  :config
  ;;-----------------------------------------------------------------------------
  ;; Supporting evil-mode.
  ;;-----------------------------------------------------------------------------
  (vhl/define-extension 'evil 'evil-paste-after 'evil-paste-before
                        'evil-paste-pop 'evil-move)
  (vhl/install-extension 'evil)
  (volatile-highlights-mode t)
  )

GUI only configs

(use-package image-click-mode
  :if mk-feature/gui
  :delight
  :ensure t
  :after (org)
  :straight (:host github :repo "mkvoya/image-click-mode" :files ("*.el"))
  :config
  (setq org-image-actual-width 400)
  (add-hook 'org-mode-hook (lambda () (image-click-mode))))

Org mode

Org

apptMELPA, Appointment package
;; Enable Org mode
(use-package org
  :straight nil
  :defer 2
  :mode ("\\.org\\'" . org-mode)
  :bind (("C-c a" . #'org-agenda)
         ("C-c c" . #'org-capture)
         )
  :init
  ;; (setq org-latex-create-formula-image-program 'dvisvgm)
  ;; According to https://orgmode.org/manual/Hard-indentation.html#Hard-indentation
  ;; But I don't need the odd levels only
  (setq org-adapt-indentation t
        org-hide-leading-stars t)
  ;;org-odd-levels-only t
  (setq org-startup-indented t) ; disable org-indent-mode for org-margin
  (setq org-latex-create-formula-image-program 'dvisvgm)

  ;; (setq org-latex-create-formula-image-program 'dvipng)
  (setq org-support-shift-select t)  ; Use shift to select region when possible.
  (setq org-clock-idle-time 10)  ; Clock will prompt to stop after 10 min of idle.
  ;; Thanks! https://emacs.stackexchange.com/a/68321/30542
  (defun org-syntax-table-modify ()
    "Modify `org-mode-syntax-table' for the current org buffer."
    (modify-syntax-entry ?< "." org-mode-syntax-table)
    (modify-syntax-entry ?> "." org-mode-syntax-table))
  (add-hook 'org-mode-hook #'org-syntax-table-modify)

  ;; Thank https://emacs-china.org/t/org-link-echo-area-link/19927/2
  (defun org-show-link-when-idle()
    ;; 在echo area中显示链接详情
    (require 'help-at-pt)
    (setq help-at-pt-display-when-idle t) ;; 不会立即生效
    (setq help-at-pt-timer-delay 0.5)
    (help-at-pt-set-timer) ;; 调用才会生效
    )
  (add-hook 'org-mode-hook #'org-show-link-when-idle)

  (setq org-element-use-cache nil)  ; cache sometimes causes problems
  (use-package org-num-mode
    :defer t
    :straight nil  ; built-in with org-mode
    ;; :hook (org-mode . org-num-mode)
    )

  :config

  (setq org-display-remote-inline-images 'download)

  ;; Auto add DONE TIME, from https://orgmode.org/guide/Progress-Logging.html
  (setq org-log-done 'time)

  ;; Org mode TODO states
  (setq org-todo-keywords
        '((sequence
           "TODO(t)"     ; New task
           "知识(K)" ; pieces of knowledge
           "讨论(D)"  ; Discussion records
           "技术技巧(S)"
           "IDEA(I)"
           "PROJECT(p)"  ; Project
           "SUBMITTED(s)"; Project
           "ONGOING(g)"  ; Doing
           "WAIT(w)"     ; Procrastinated on purpose
           "LONG-TERM(l)"  ; Long-term
           "DELEGATE(z)"   ; Delegated
           "CONFDDL(C)"
           "GOAL(G)"
           "|"
           "ACCEPTED(a)" ; Project
           "DONE(d!)"      ; Done
           "CANCELED(c@)"  ; Eliminated
           )))
  ;; Always change the task to IN-PROGRESS.
  ;; (setq org-clock-in-switch-to-state "IN-PROGRESS")
  ;; (setq org-clock-out-switch-to-state #'(lambda (_)
  ;;           (completing-read "Finishing a clock, change task state to?" '("DONE" "TODO"))))
  ;; Keyword colors
  (setf org-todo-keyword-faces
        '(
          ;; Many styles from https://github.com/GTrunSec/my-profile/blob/master/dotfiles/doom-emacs/config.org
          ;; ("TODO" . (:foreground "#ff39a3" :weight bold))
          ("TODO" . (:foreground "#dfffff" :background "#ff19a3" :weight bold))
          ("ONGOING"  . "orangered")
          ("ACCEPTED"  . "darkgreen")
          ("SUBMITTED"  . "blue")
          ("WAIT" . "pink")
          ;; ("CANCELED" . (:foreground "white" :background "#4d4d4d" :weight bold :strike-through "#0d0d0d"))
          ("CANCELED" . (:foreground "white" :background "#4d4d4d"))
          ;; ("DONE" . "#008080")
          ("DONE" . (:foreground "#008080"))
          ("DELEGATE"  . "DeepSkyBlue")
          ))
  (setq org-log-into-drawer t)

  ;; Strike through the whole line with DONE entry
  ;; (font-lock-add-keywords
  ;;  'org-mode
  ;;  '(
  ;;    ("\\* \\<DONE .*" 0 'shr-strike-through append)
  ;;    ("\\* \\<CANCELED .*" 0 'shr-strike-through append))
  ;;  t)

  ;; …, ➡, ⚡, ▼, ↴, , ∞, ⬎, ⤷, ⤵ "↴▾▽▼↩↘↸"
  ;; (setq org-ellipsis "▾")
  (setq org-ellipsis "")
  ;; (setq org-ellipsis "...")
  (set-face-attribute 'org-ellipsis nil :foreground "grey86")
  ;; org-ellipsis " ••• "

  ;; https://stackoverflow.com/questions/17590784/how-to-let-org-mode-open-a-link-like-file-file-org-in-current-window-inste
  (defun org-force-open-current-window ()
    "Open at current window."
    (interactive)
    (let ((org-link-frame-setup (quote
                                 ((vm . vm-visit-folder)
                                  (vm-imap . vm-visit-imap-folder)
                                  (file . find-file)
                                  (wl . wl)))
                                ))
      (org-open-at-point)))

  ;; Depending on universal argument try opening link
  (defun org-open-maybe (&optional arg)
    "Open maybe ARG."
    (interactive "P")
    (if arg (org-open-at-point)
      (org-force-open-current-window)))
  ;; Redefine file opening without clobbering universal argument
  (define-key org-mode-map "\C-c\C-o" 'org-open-maybe)

  (org-babel-do-load-languages
   'org-babel-load-languages
   '((dot . t)
     (C . t)
     (python . t)
     (shell . t)))

  ;; https://emacs.stackexchange.com/questions/3302/live-refresh-of-inline-images-with-org-display-inline-images
  ;; Always redisplay inline images after executing SRC block
  (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images)


  (require 'color)

  (when mk-feature/gui
    (set-face-attribute 'org-block nil :background
                        (color-darken-name
                         (face-attribute 'default :background) 3))
    (set-face-attribute 'org-code nil :background
                        (color-darken-name
                         (face-attribute 'default :background) 3))
    (set-face-attribute 'org-quote nil :background
                        (color-darken-name
                         (face-attribute 'default :background) 3))
    (set-face-attribute 'org-block-begin-line nil :background
                        "#F1E6F8")
    (set-face-attribute 'org-block-end-line nil :background
                        (color-darken-name
                         (face-attribute 'default :background) 4))
    )
  (set-face-attribute 'outline-1 nil :foreground "firebrick")
  (set-face-attribute 'org-level-1 nil :height 1.1)
  (set-face-attribute 'outline-2 nil :foreground "purple2")
  (set-face-attribute 'outline-3 nil :foreground "violetRed2")
  (set-face-attribute 'outline-4 nil :foreground "cyan4")
  ;; (set-face-attribute 'outline-4 nil :foreground "springgreen4")

  (setq org-fontify-quote-and-verse-blocks t)

  (add-hook 'org-mode-hook
            (lambda ()
              (electric-indent-local-mode -1)
              (mkvoya/better-wrap)
              (prettify-symbols-mode)
              ;; (org-hide-properties)
              ))


  (use-package org-contrib :disabled)
  (use-package org-inline-pdf :defer t)
  (use-package org-super-agenda
    :init
    (org-super-agenda-mode)
    :config
    (setq org-super-agenda-groups
          '((:name "Next Items"
                   :time-grid t
                   :tag ("NEXT" "outbox"))
            (:name "Important"
                   :priority "A")
            (:name "Quick Picks"
                   :effort< "0:30")
            (:priority<= "B"
                         :scheduled future
                         :order 1)))
    )

  (setq org-hide-emphasis-markers nil)      ; don’t hide markers for like *foo*
  ;; (setq org-hide-emphasis-markers t)
  (setq org-emphasis-alist
        '(("*" bold)
          ("/" italic)
          ("_" underline)
          ("=" org-verbatim verbatim)
          ;; ("@" (:foreground "red" :background "black"))
          ("&" (:foreground "red"))
          ("~" org-code verbatim)
          ("+"
           (:strike-through t))))
  (use-package ov)
  (load-file "~/.emacs.d/site-lisp/org-colored-text.el")
  )

(use-package org-sticky-header
  :straight (:host github :repo "alphapapa/org-sticky-header")
  :defer t
  :after (org)
  )
;; Org Cite
(use-package oc
  :straight nil
  :ensure nil
  :after org)
(font-lock-add-keywords
 'org-mode
 '(("^[[:space:]]*\\(-\\) "
    (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) ""))))))

(use-package org-bars
  :straight (:host github :repo "tonyaldon/org-bars")
  :defer t
  :after (org)
  :config
  (setq org-bars-with-dynamic-stars-p nil)
  )
(use-package highlight-indent-guides)
(use-package nerd-icons
  :custom
  ;; The Nerd Font you want to use in GUI
  ;; "Symbols Nerd Font Mono" is the default and is recommended
  ;; but you can use any other Nerd Font if you want
  (nerd-icons-font-family "Symbols Nerd Font Mono")
  (nerd-icons-scale-factor 1.1)
  )

(use-package org-tag-beautify
  :ensure t
  :custom (org-tag-beautify-data-dir "~/.emacs.d/straight/repos/org-tag-beautify/data/")
  :init (org-tag-beautify-mode 1))
(use-package org-rainbow-tags
  :ensure t
  :custom
  (org-rainbow-tags-hash-start-index 10)
  (org-rainbow-tags-extra-face-attributes
   ;; Default is '(:weight 'bold)
   '(:inverse-video t :box t :weight 'bold))
  :hook
  (org-mode . org-rainbow-tags-mode))
;; agenda 里面时间块彩色显示
;; From: https://emacs-china.org/t/org-agenda/8679/3
(defun my:org-agenda-time-grid-spacing ()
  "Set different line spacing w.r.t. time duration."
  (save-excursion
    (let* ((background (alist-get 'background-mode (frame-parameters)))
           (background-dark-p (string= background "dark"))
           (colors (if background-dark-p
                       (list "#aa557f" "DarkGreen" "DarkSlateGray" "DarkSlateBlue")
                     (list "#F6B1C3" "#FFCF9D" "#BEEB9F" "#ADD5F7")))
           pos
           duration)
      (nconc colors colors)
      (goto-char (point-min))
      (while (setq pos (next-single-property-change (point) 'duration))
        (goto-char pos)
        (when (and (not (equal pos (point-at-eol)))
                   (setq duration (org-get-at-bol 'duration)))
          (let ((line-height (if (< duration 30) 1.0 (+ 0.5 (/ duration 60))))
                (ov (make-overlay (point-at-bol) (1+ (point-at-eol)))))
            (overlay-put ov 'face `(:background ,(car colors)
                                                :foreground
                                                ,(if background-dark-p "black" "white")))
            (setq colors (cdr colors))
            (overlay-put ov 'line-height line-height)
            (overlay-put ov 'line-spacing (1- line-height))))))))

(add-hook 'org-agenda-finalize-hook #'my:org-agenda-time-grid-spacing)
(setq org-agenda-start-with-log-mode t)

;; Paste Image From https://emacs-china.org/t/topic/6601/4
(defun org-insert-image ()
  "Insert a image from clipboard."
  (interactive)
  (let* ((buf-name (if (and (fboundp 'denote-file-is-note-p)
                            (fboundp 'denote-retrieve-filename-identifier)
                            (denote-file-is-note-p (buffer-file-name)))
                       (denote-retrieve-filename-identifier (buffer-name))
                     (buffer-name)))
         (path (concat default-directory
                       buf-name
                       ".assets/"))
         (image-file (concat
                      path
                      buf-name
                      (format-time-string "_%Y%m%d_%H%M%S.png"))))
    (if (not (file-exists-p path))
        (mkdir path))
    (do-applescript (concat
                     "set the_path to \"" image-file "\" \n"
                     "set png_data to the clipboard as «class PNGf» \n"
                     "set the_file to open for access (POSIX file the_path as string) with write permission \n"
                     "write png_data to the_file \n"
                     "close access the_file"))
    ;; (shell-command (concat "pngpaste " image-file))
    (org-insert-link nil
                     (concat "file:" image-file)
                     "")
    (message image-file))
  (org-display-inline-images)
  )

Org Exports

(use-package ox-html
  :straight nil
  :after (org)
  :defer t
  :config
  ;; Org export code style
  (setq org-html-htmlize-output-type 'css)
  (setq org-src-preserve-indentation nil)
  (setq-default org-html-doctype "html5")
  (setq-default org-html-html5-fancy t)
  (setq org-html-validation-link nil)

  ;; https://emacs.stackexchange.com/a/3512/30542
  (defun my-org-inline-css-hook (exporter)
    "Insert custom inline css"
    (when (eq exporter 'html)
      (let* ((dir (ignore-errors (file-name-directory (buffer-file-name))))
             (path (concat dir "style.css"))
             (homestyle (or (null dir) (null (file-exists-p path))))
             (final (if homestyle "~/.emacs.d/misc/ox-html-code-style.css" path)))
        (setq org-html-head-include-default-style t)
        (setq org-html-head (concat
                             "<style type=\"text/css\">\n"
                             "<!--/*--><![CDATA[/*><!--*/\n"
                             (with-temp-buffer
                               (insert-file-contents final)
                               (buffer-string))
                             "/*]]>*/-->\n"
                             "</style>\n")))))

  (add-hook 'org-export-before-processing-hook 'my-org-inline-css-hook)

  ;;; Add summary support, from Sachachua
  (setq org-babel-exp-code-template "#+begin_src %lang%switches%flags :summary %summary\n%body\n#+end_src")
  (defun my-org-html-src-block (src-block _contents info)
    (let* ((result (org-html-src-block src-block _contents info))
           (block-info
            (org-with-point-at (org-element-property :begin src-block)
              (org-babel-get-src-block-info)))
           (summary (assoc-default :summary (elt block-info 2))))
      (if (member summary '("%summary" ""))
          result
        (format "<details><summary>%s</summary>%s</details>"
                summary
                result))))
  (with-eval-after-load 'ox-html
    (map-put!
     (org-export-backend-transcoders (org-export-get-backend 'html))
     'src-block 'my-org-html-src-block))
  )
(use-package ox-twbs
  :after ox-html
  :config
  (defun my-org-html-src-block2 (src-block _contents info)
    (let* ((result (org-twbs-src-block src-block _contents info))
           (block-info
            (org-with-point-at (org-element-property :begin src-block)
              (org-babel-get-src-block-info)))
           (summary (assoc-default :summary (elt block-info 2))))
      (if (member summary '("%summary" ""))
          result
        (format "<details><summary>%s</summary>%s</details>"
                summary
                result))))
  (with-eval-after-load 'ox-twbs
    (map-put!
     (org-export-backend-transcoders (org-export-get-backend 'twbs))
     'src-block 'my-org-html-src-block2))
  )

Calender sync

(use-package ox-icalendar
  :defer t
  :straight nil
  :after (org)
  :config
  (setq org-icalendar-alarm-time 5)
  (setq org-icalendar-combined-agenda-file "~/Dropbox/Dreams/Org/org.ics"
        org-icalendar-include-todo 'all
        org-icalendar-store-UID t
        org-icalendar-timezone ""
        org-icalendar-use-deadline
        '(event-if-not-todo event-if-todo event-if-todo-not-done todo-due)
        org-icalendar-use-scheduled
        '(event-if-not-todo event-if-todo event-if-todo-not-done todo-start))
  )
(use-package org-caldav
  :defer t
  ;; :after (async)
  :init
  (require 'async)
  (setq org-caldav-url "https://dong.mk/radicale/mkvoya/")
  (setq org-caldav-todo-percent-states
        '(
          (0 "TODO")
          (100 "DONE")
          (0 "IDEA")
          (100 "CANCELED")))
  (setq org-caldav-calendars
        '(
          (
           :calendar-id "9d6f9f39-cba5-fe5b-bd49-c61168d64f81"
           ;; :calendar-id "OrgSync"
           :inbox "~/Dropbox/Dreams/Org/Caldav.inbox.org"
           :files ("~/Dropbox/Dreams/Org/Main.org"
                   "~/Dropbox/Dreams/Org/Inbox.org"
                   "~/Dropbox/Dreams/Org/Ebib-ReadingList.org"
                   ))
          ))
  (setq org-icalendar-timezone "Asia/Shanghai")
  )

Org-transclusion

Modes to embed one buffer in another buffer and keep them in sync

Freexhttps://github.com/gregdetre/emacs-freex
transclusion-minor-modehttp://github.com/whacked/transclusion-minor-mode
(use-package org-transclusion
  :after (org org-modern)
  :hook (org-mode . org-transclusion-mode)
  :config
  ;; (setq org-transclusion-fringe-bitmap 'empty-line)
  (setq org-transclusion-fringe-bitmap 'right-triangle)
  (set-face-attribute
   'org-transclusion-fringe nil
   :foreground "blue"
   :background "orange")
  (set-face-attribute
   'org-transclusion-source-fringe nil
   :foreground "lightblue"
   :background "blue")
  )
;; :bind (("<f12>" . #'org-transclusion-add))
;; ("C-n t" . #'org-transclusion-mode)

Notes (org-roam)

note takingorg-roam
org-roam-ui
org-roam-server(use org-roam-ui)
org-mindmapcreates graphviz directed graphs from headings of an org file
denote
note searchnotdefthttps://github.com/hasu/notdeft
consult-ripgrepconsult built-in
org-brain
(use-package websocket :defer t)
(use-package simple-httpd :defer t)
(use-package org-roam
  :ensure t
  :custom
  (org-roam-directory (file-truename "~/Dropbox/Dreams/Org/"))
  ;; (org-roam-dailies-directory "Journals/")
  ;; (org-roam-dailies-capture-templates '(("d" "default" entry
  ;;                                        "* %<%H:%M>: %?"
  ;;                                        :target (file+datetree "LatestJournal.org" week))))
  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n g" . org-roam-graph)
         ("C-c n i" . org-roam-node-insert)
         ("C-c n c" . org-roam-capture)
         ;; Dailies
         ;; ("C-c n j" . org-roam-dailies-capture-today)
         ;; ("C-c n J" . org-roam-dailies-goto-today)
         ;; ("C-c j" . org-roam-dailies-capture-today)
         ;; ("C-c J" . org-roam-dailies-goto-today)
         )
  :config
  ;; If you're using a vertical completion framework, you might want a more informative completion interface
  (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
  (org-roam-db-autosync-mode)
  ;; If using org-roam-protocol
  (require 'org-roam-protocol)
  )
(use-package org-journal
  :ensure t
  :bind (("C-c j" . org-journal-open-current-journal-file)
         ("C-c J" . org-journal-new-entry))
  :config
  (bind-key "C-c s" 'org-journal-search-forever org-journal-mode-map)
  (unbind-key "C-c C-s" org-journal-mode-map)
  (setq org-journal-file-format "%Y-%m-%d-w%V.org")
  (setq org-journal-enable-agenda-integration t)
  (setq org-journal-file-type 'weekly)
  (setq org-journal-dir "~/Dropbox/Dreams/Org/Journals/"
        org-journal-date-format "%A, %d %B %Y")

  ;; org capture integration
  (defun org-journal-find-location ()
    ;; Open today's journal, but specify a non-nil prefix argument in order to
    ;; inhibit inserting the heading; org-capture will insert the heading.
    (org-journal-new-entry t)
    (unless (eq org-journal-file-type 'daily)
      (org-narrow-to-subtree))
    (goto-char (point-max)))
  (defvar org-journal--date-location-scheduled-time nil)

  (defun org-journal-date-location (&optional scheduled-time)
    (let ((scheduled-time (or scheduled-time (org-read-date nil nil nil "Date:"))))
      (setq org-journal--date-location-scheduled-time scheduled-time)
      (org-journal-new-entry t (org-time-string-to-time scheduled-time))
      (unless (eq org-journal-file-type 'daily)
        (org-narrow-to-subtree))
      (goto-char (point-max))))

  (setq org-capture-templates '(("j" "Journal entry" plain (function org-journal-date-location)
                                 "** TODO %?\n <%(princ org-journal--date-location-scheduled-time)>\n"
                                 :jump-to-captured t)
                                ("J" "Journal entry" plain (function org-journal-find-location)
                                 "** %(format-time-string org-journal-time-format)%^{Title}\n%i%?"
                                 :jump-to-captured t :immediate-finish t)))
  )

(use-package org-roam-ui
  :straight
  (:host github :repo "org-roam/org-roam-ui" :branch "main" :files ("*.el" "out"))
  :after org-roam
  ;;         normally we'd recommend hooking orui after org-roam, but since org-roam does not have
  ;;         a hookable mode anymore, you're advised to pick something yourself
  ;;         if you don't care about startup time, use
  ;;  :hook (after-init . org-roam-ui-mode)
  :config
  (setq org-roam-ui-sync-theme t
        org-roam-ui-follow t
        org-roam-ui-update-on-save t
        org-roam-ui-open-on-start t))

(use-package org-capture
  :if mk-feature/noteman
  :straight nil
  :config
  (defvar mk/org-capture-people-path)
  (defun mk/org-capture-people ()
    (interactive)
    (format "* %s\n%%?" (read-string "姓名: " nil))
    )
  (setq org-capture-templates
        '(("p" "New People" entry (file+headline "~/Dropbox/Dreams/Org/People/General.org" "People")
           #'mk/org-capture-people
           )
          ("r" "New Research Snippet" entry (file+headline "~/Dropbox/Dreams/Research/Snippets.org" "Research Snippets")
           "* %?\n%i %a"
           )
          ))
  )
(use-package consult-notes
  :straight (:type git :host github :repo "mclear-tools/consult-notes")
  :commands (consult-notes
             consult-notes-search-in-all-notes)
  :bind ("C-c d f" . consult-notes)
  :config
  (setq consult-notes-sources
        '(("denote"          ?d "~/Dropbox/Dreams/Org")
          ("People"          ?d "~/Dropbox/Dreams/Org/People")
          ))
  )

Publish & Blog

(use-package ox-hugo
  :after ox
  :init
  (defun mk/sync-to-server (&optional all-subtrees async visible-only noerror)
    (async-shell-command "cd ~/Dropbox/Public/essay && hugo -D && rsync -rvP ~/Dropbox/Public/essay/public/ dong.mk:/srv/http/essay"))
  (advice-add 'org-hugo-export-wim-to-md :after #'mk/sync-to-server)
  )

Bibliography

;; Common
(setq mk/bib-main-file "~/Dropbox/Dreams/Research/Papers/Papers.bib")
(setq mk/bib-pdf-dir "~/Dropbox/Dreams/Research/Papers/")

(setq reftex-default-bibliography `("paper.bib" "references.bib" ,mk/bib-main-file))

Bibtex

(use-package bibtex
  :if mk-feature/bibliography
  :straight nil  ; built in
  :defer
  :init
  (setq bibtex-dialect 'biblatex)
  ;; Bibtex autokey is used by Ebib.
  (setq bibtex-autokey-year-length 4  ; Full year format
        bibtex-autokey-name-year-separator "-"
        bibtex-autokey-year-title-separator "-"
        bibtex-autokey-titleword-separator "-"
        bibtex-autokey-titlewords 2  ; Use two words from the title
        bibtex-autokey-titlewords-stretch 0
        bibtex-autokey-titleword-length nil  ; Use whole word
        )
  (setq bibtex-autokey-titleword-ignore
        '("A" "An" "On" "The" "Eine?" "Der" "Die" "Das"
          "The" "on"
          "a" "an"
          "and" "the" "of" ".*[^[:upper:][:lower:]0-9].*"))

  (setq bibtex-completion-bibliography `(,mk/bib-main-file)
        bibtex-completion-library-path nil  ; TODO
        bibtex-completion-notes-path nil)  ; TODO
  (setq bibtex-completion-notes-template-multiple-files
        "* ${author-or-editor}, ${title}, ${journal}, (${year}) :${=type=}: \n\nSee [[cite:&${=key=}]]\n"
        bibtex-completion-additional-search-fields '(keywords)
        bibtex-completion-display-formats
        '((article       . "${=has-pdf=:1}${=has-note=:1} ${year:4} ${author:36} ${title:*} ${journal:40}")
          (inbook        . "${=has-pdf=:1}${=has-note=:1} ${year:4} ${author:36} ${title:*} Chapter ${chapter:32}")
          (incollection  . "${=has-pdf=:1}${=has-note=:1} ${year:4} ${author:36} ${title:*} ${booktitle:40}")
          (inproceedings . "${=has-pdf=:1}${=has-note=:1} ${year:4} ${author:36} ${title:*} ${booktitle:40}")
          (t             . "${=has-pdf=:1}${=has-note=:1} ${year:4} ${author:36} ${title:*}")))
  (setq bibtex-completion-pdf-open-function
        (lambda (fpath) (call-process "open" nil 0 nil fpath)))
  :config
  (use-package bibtex-completion
    :defer
    :config
    (bibtex-completion-init)  ; This will set the XXX-format-internal variable
    )
  )

Citar

Org-refhttps://github.com/jkitchin/org-ref
Citarhttps://github.com/bdarcus/citarAlternative to org-ref
;; citar
(use-package citar
  :if mk-feature/bibliography
  :straight (:host github :repo "bdarcus/citar")
  :defer
  :demand
  :bind (;; ("C-c B" . citar-insert-citation)
         ;; :map minibuffer-local-map
         ;; ("M-b" . citar-insert-preset)
         )
  :init
  (setq citar-notes-paths '("~/Dropbox/Dreams/Org/PaperNotes"))
  (setq org-cite-global-bibliography `(,(expand-file-name mk/bib-main-file)))
  (setq org-cite-insert-processor 'citar)
  (setq org-cite-follow-processor 'citar)
  (setq org-cite-activate-processor 'citar)
  (setq citar-bibliography org-cite-global-bibliography)
  ;; (setq citar-symbols
  ;;       `((file ,(all-the-icons-faicon "file-o" :face 'all-the-icons-green :v-adjust -0.1) . " ")
  ;;         (note ,(all-the-icons-material "speaker_notes" :face 'all-the-icons-blue :v-adjust -0.3) . " ")
  ;;         (link ,(all-the-icons-octicon "link" :face 'all-the-icons-orange :v-adjust 0.01) . " ")))
  (setq citar-symbol-separator "  ")
  ;; (require 'embark)
  ;; (setq citar-at-point-function 'embark-act)
  ;; (use-package citar-embark
  ;;   :after citar embark
  ;;   :no-require
  ;;   :config (citar-embark-mode))
  :config
  ;; (use-package org-roam-bibtex
  ;;   :defer
  ;;   :after org-roam
  ;;   :config
  ;;   (setq orb-roam-ref-format 'org-cite)
  ;;   (setq orb-use-bibdesk-attachments 't)
  ;;   )
  ;; (require 'org-roam-bibtex)
  (setq citar-open-note-function #'(lambda (key entry) (orb-edit-note key)))
  ;; (citar-filenotify-setup '(LaTeX-mode-hook org-mode-hook))
  )

Biblio

bibliohttps://github.com/cpitclaudel/biblio.elLookup & import bib
(use-package biblio
  :if mk-feature/bibliography
  :defer
  :init

  (setq biblio-arxiv-bibtex-header "misc")
  (setq biblio-bibtex-use-autokey nil)  ; Don't use autokey of biblio

  ;; Some backends fail upon async queries.
  (setq biblio-synchronous t)

  :config

  ;; Override
  (defun biblio--completing-read-function ()
    "Override to always return the defualt one"
    completing-read-function)

  ;; Override to add url
  (defun biblio-arxiv--build-bibtex-1 (metadata)
    "Create an unformated BibTeX record for METADATA."
    (let-alist metadata
      (format "@%s{NO_KEY,
author = {%s},
title = {%s},
year = {%s},
url = {%s},
series = {arXiv %s},
archivePrefix = {arXiv},
eprint = {%s},
primaryClass = {%s}}"
              biblio-arxiv-bibtex-header
              (biblio-join-1 " AND " .authors)
              .title .year .url .year .identifier .category)))
  )

Ebib

Ebibhttps://github.com/joostkremers/ebibBib Manager
(use-package ebib
  :if mk-feature/bibliography
  :defer
  ;; :after (biblio bibtex citar)
  :init
  (require 'biblio)
  (require 'bibtex)
  (require 'citar)
  (require 'dbus)  ; A function from dbus is used in ebib.
  (defun mk/ebib-create-org-schedule (_key _db)
    (format "SCHEDULED: <%s>" (org-read-date nil nil "+1d"))
    )
  (setq ebib-reading-list-template-specifiers '((?K . ebib-reading-list-create-org-identifier)
                                                (?T . ebib-create-org-title)
                                                (?M . ebib-reading-list-todo-marker)
                                                (?L . ebib-create-org-link)
                                                (?F . ebib-create-org-file-link)
                                                (?D . ebib-create-org-doi-link)
                                                (?U . ebib-create-org-url-link)
                                                (?S . mk/ebib-create-org-schedule)))
  (setq ebib-reading-list-template "* %M %T\n%S\n:PROPERTIES:\n%K\n:END:\n%F\n")
  (setq ebib-autogenerate-keys t)  ; Use bibtex autokey.
  (setq ebib-uniquify-keys t)
  (setq ebib-file-associations '(("pdf" . "open -a \"PDF Expert\" %s")))
  (setq ebib-bibtex-dialect 'biblatex)  ; biblatex is better than xxx.
  (setq ebib-index-window-size 10)
  (setq ebib-preload-bib-files `(,mk/bib-main-file))
  (setq ebib-file-search-dirs `(,mk/bib-pdf-dir))
  (setq ebib-notes-storage 'one-file-per-note)
  (setq ebib-reading-list-file "~/Dropbox/Dreams/Org/Ebib-ReadingList.org")
  (setq ebib-notes-directory "~/Dropbox/Dreams/Org/PaperNotes/")
  (setq ebib-notes-locations `(,ebib-notes-directory))
  ;; ebib-keywords-file "~/Dropbox/Bibliography/ebib-keywords.txt"
  (setq ebib-keywords-field-keep-sorted t)
  (setq ebib-keywords-file-save-on-exit 'always)
  ;; ebib-file-associations '(("pdf")) "using Emacs to open pdf"
  (setq ebib-use-timestamp t)  ; recording the time that entries are added
  (setq ebib-notes-symbol "📘")
  (setq ebib-index-columns '(("Year" 4 t)
                             ("Entry Key" 30 t)
                             ("Note" 2 nil)
                             ("Title" 50 t)
                             ("Series/Journal" 20 t)
                             ("Author/Editor" 40 nil)))
  (setq ebib-index-default-sort '("timestamp" . descend))

  (defun mk/ebib-display-series-or-journal (field key db)
    "Return series/journal FIELD content from KEY and DB."
    (or (ebib-get-field-value "Series" key db 'noerror 'unbraced 'xref)
        (ebib-get-field-value "Journal" key db "(No Series/Journal)" 'unbraced 'xref))
    )
  (setq ebib-field-transformation-functions
        '(("Title" . ebib-clean-TeX-markup-from-entry)
          ("Doi" . ebib-display-www-link)
          ("Url" . ebib-display-www-link)
          ("Note" . ebib-notes-display-note-symbol)
          ("Series/Journal" . mk/ebib-display-series-or-journal)
          ))
  :config
  (setq ebib-index-mode-line '("%e"
                               mode-line-front-space
                               ebib--mode-line-modified
                               mode-line-buffer-identification
                               (:eval (if (and ebib--cur-db (ebib-db-dependent-p ebib--cur-db))
                                          (format " [%s]" (ebib-db-get-filename (ebib-db-get-main ebib--cur-db) t))))
                               (:eval (format "  (%s)" (ebib--get-dialect ebib--cur-db)))
                               (:eval (if (and ebib--cur-db (ebib--get-key-at-point))
                                          (format "     Entry %d/%d" (line-number-at-pos) (count-lines (point-min) (point-max)))
                                        "     No Entries"))
                               (:eval (if (and ebib--cur-db (ebib-db-get-filter ebib--cur-db))
                                          (format "  |%s|" (ebib--filters-pp-filter (ebib-db-get-filter ebib--cur-db)))
                                        ""))))
  (defun mk/ebib--clean-string (str)
    "Clean the format of STR."
    (or (substring-no-properties (remove ?\n (format "%s" str))) ""))
  (defun mk/ebib--clean-field (key db field)
    "Clean the format of FIELD of KEY in DB."
    (mk/ebib--clean-string (ebib-get-field-value field key db 'noerror 'unbraced 'xref)))

  (defun mk/read-file-content (filename)
    "Read the file content of FILENAME."
    (with-temp-buffer
      (insert-file-contents filename)
      (buffer-string)))
  (defun mk/ebib-complete-rest-note-content (key db)
    "Gerneate the rest content of the note template accroding to KEY in DB."
    (let ((template (mk/read-file-content "~/.emacs.d/snippets/ebib/ebib-notes-template.org"))
          (title (mk/ebib--clean-field key db "title"))
          (date (format-time-string "%FT%T%z"))
          (authors (mk/ebib--clean-field key db "author"))
          (series (mk/ebib--clean-field key db "series")))
      (setq template (string-replace "${citekey}" key template))
      (setq template (string-replace "${orgid}" (org-id-new) template))
      (setq template (string-replace "${title}" title template))
      (setq template (string-replace "${date}" date template))
      (setq template (string-replace "${authors}" authors template))
      (setq template (string-replace "${series}" series template))
      template))
  (setq ebib-notes-template-specifiers '((?K . ebib-create-org-identifier)
                                         (?T . ebib-create-org-description)
                                         (?X . ebib-create-org-title)
                                         (?C . ebib-create-org-cite)
                                         (?L . ebib-create-org-link)
                                         (?F . ebib-create-org-file-link)
                                         (?D . ebib-create-org-doi-link)
                                         (?U . ebib-create-org-url-link)
                                         (?P . mk/ebib-complete-rest-note-content)))
  (setq ebib-notes-template "%%?%P\n")

  )

(defun mk/ebib-reading-list-show-entry ()
  "Jump to the ebib entry from the current reading list item."
  (interactive)
  (let ((custom-id (org-entry-get (point) "Custom_id")))
    (when (string-prefix-p "reading_" custom-id)
      (let ((ebib-key (substring custom-id 8)))
        (message "Jumping to ebib entry with key: %s" ebib-key)
        (ebib nil ebib-key)
        ))))

(use-package ebib-biblio
  :if mk-feature/bibliography
  :after (ebib biblio)
  :straight nil
  :demand
  :bind (:map biblio-selection-mode-map
              ("e" . ebib-biblio-selection-import)))
(use-package zotra
  :config
  (setq zotra-backend 'zotra-server)
  (setq zotra-local-server-directory "~/.emacs.d/third-parties/zotra-server/")
  )

Paper and Research

(use-package emacs
  :if mk-feature/bibliography
  :after (ebib)
  :init
  ;; My source code for bib
  (setq paper-root-dir (expand-file-name "~/Dropbox/Dreams/Research/Papers"))
  (defun mk/normalize-paper-title (title)
    "Remove bad chars in the paper TITLE."
    (replace-regexp-in-string
     "[\s\n]+" " " (replace-regexp-in-string
                    "/" "" (replace-regexp-in-string
                            ":" "," title)))
    )

  (defun paper-root()
    "Open the paper root."
    (interactive)
    (find-file paper-root-dir))

  (defun paper-find (&optional initial)
    "Search a paper in your Dreamland, by title, with INITIAL input."
    (interactive "P")
    (let ((consult-find-args (concat
                              (expand-file-name "~/.emacs.d/bin/paperfind.sh")
                              " "
                              paper-root-dir)))
      (find-file (concat (file-name-as-directory paper-root-dir)
                         (consult--find "Dreamland's Paper Find: "
                                        #'consult--find-builder initial)))))

  (defun paper-open ()
    "Open the file in PDF Expert. Code borrowed from the crux package."
    (interactive)
    (let ((current-file-name
           (if (eq major-mode 'dired-mode)
               (dired-get-file-for-visit)
             buffer-file-name)))
      (call-process "open" nil 0 nil "-a" "/Applications/PDF Expert.app" current-file-name))
    )

  ;; Automatically choose the file to link with according to the selected text.
  (defvar autolink-directory "~/Dropbox/Dreams")
  (defun autolink--get-candidates (text)
    "Search for the file name with TEXT."
    (let* ((cmd (concat "find " autolink-directory " -iname \"*" (string-replace ":" "?" text) "*\""))
           (candidates (mapcar 'abbreviate-file-name (delete "" (split-string (shell-command-to-string cmd) "\n")))))
      (completing-read "Choose the one to link: " candidates)))
  (defun paper-link (start end)
    "Try to guess the file to link according to the region between START and END."
    (interactive "r") ; The "r" here will fill the start and end automatically.
    (let* ((text (buffer-substring start end))
           (file (autolink--get-candidates text)))
      (goto-char end)
      (insert "]]")
      (goto-char start)
      (insert (concat "[[" file "]["))))

  (setq mk/ebib-dir-root "~/Dropbox/Dreams/Research/Papers")

  (defun mk/ebib--format-full-dir (dir title)
    "Get the full dir name from DIR and TITLE."
    (let ((clean-title
           (string-replace "}" "" (string-replace "{" "" title))))
      (format "%s/%s/%s" mk/ebib-dir-root dir clean-title)))

  (defun mk/ebib-get-series-dirname-candidate (title series journal year publisher)
    "Form the name of given TITLE, SERIES, JOURNAL, YEAR, PUBLISHER"
    (cond
     ;; Use series if set
     ((not (string= series "no-series")) (string-replace " " "." (string-replace " '" "" series)))
     ;; Hard coded
     ((string= journal "scientific reports") (format "nat.sci.rep.%s" year))
     ((string= journal "science") (format "science.%s" year))
     ((string= journal "commun. acm") (format "commun.acm.%s" year))
     ((string= journal "nature communications") (format "nat.comm.%s" year))
     ((string= journal "nature") (format "nature.%s" year))
     ((string= journal "advanced science") (format "advs.%s" year))
     ((string= journal "acs nano") (format "acs.nano.%s" year))
     ((string= journal "nano select") (format "nano.%s" year))
     ((string= journal "bmc bioinformatics") (format "bioinfo.%s" year))
     ((string= journal "ieee transactions on computer-aided design of integrated circuits and systems") (format "tcad.%s" year))
     ((string= journal "ieee transactions on parallel and distributed systems") (format "tpds.%s" year))
     ((string= journal "ieee transactions on computers") (format "tc.%s" year))
     ((string= journal "ieee transactions on information theory") (format "tit.%s" year))
     ((string= journal "briefings in bioinformatics") (format "bib.%s" year))
     ((string= journal "acs synthetic biology") (format "acs.syn.bio.%s" year))
     ((string= journal "angewandte chemie international edition") (format "anie.%s" year))
     ((string= journal "computational and structural biotechnology journal") (format "csbj.%s" year))
     ((string= journal "the australian universities' review") (format "aur.%s" year))
     ((string= journal "nature computational science") (format "nat.comput.sci.%s" year))
     ((string= journal "nature reviews genetics") (format "nat.rev.genet.%s" year))

     ;; arXiv
     ((string= publisher "arxiv") (format "arxiv%s" year))
     (t "XXXX")))

  (defun mk/ebib-get-dir (title series journal year publisher)
    "Calculate the directory for TITLE and SERIES and JOURNAL and PUBLISHER."
    (let* ((series-dir (mk/ebib-get-series-dirname-candidate title series journal year publisher))
           (fulldir (mk/ebib--format-full-dir series-dir title)))
      (if (file-exists-p fulldir) fulldir nil)
      ))

  (defun mk/ebib-open-dir (key)
    "Open the directory for KEY."
    (interactive (list (ebib--get-key-at-point)))
    (ebib--execute-when
      (entries
       (let* ((title (mk/normalize-paper-title (ebib-get-field-value "title" key ebib--cur-db nil t)))
              (series (downcase (ebib-get-field-value "series" key ebib--cur-db "no-series" t)))
              (publisher (downcase (ebib-get-field-value "publisher" key ebib--cur-db "no-publisher" t)))
              (journal (downcase (ebib-get-field-value "journal" key ebib--cur-db "no-journal" t)))
              (year (ebib-get-field-value "year" key ebib--cur-db "0000" t))
              (series-dirname (mk/ebib-get-series-dirname-candidate title series journal year publisher))
              (cand (mk/ebib-get-dir title series journal year publisher)))
         (if cand (find-file cand)
           (print "No such dir, creating with prompt...")
           (let* ((conf (string-trim (read-string "The conf abbr: " series-dirname)))
                  (target (mk/ebib--format-full-dir conf title)))
             (make-directory target t)
             (find-file target)
             ))))
      (default
       (beep))))

  (define-key ebib-index-mode-map (kbd "O") #'mk/ebib-open-dir)

  (defun mk/paper-get-dirs ()
    "Get all conf dirs."
    (let* ((cmd (format "find %s -type d -maxdepth 1 -exec realpath --relative-to %s {} \\;" mk/ebib-dir-root mk/ebib-dir-root))
           (candidates (mapcar 'abbreviate-file-name (delete "" (split-string (shell-command-to-string cmd) "\n"))))
           (choice (completing-read "Choose the one to link: " candidates)))
      (print choice)
      ))

  (defun mk/ebib-open-file (key)
    "Open files for KEY."
    (interactive (list (ebib--get-key-at-point)))
    (ebib--execute-when
      (entries
       (let* ((title (mk/normalize-paper-title (ebib-get-field-value "title" key ebib--cur-db nil t)))
              (cmd (format "find %s -type d -iname \"%s\"" mk/ebib-dir-root title))
              (candidates (mapcar 'abbreviate-file-name (delete "" (split-string (shell-command-to-string cmd) "\n"))))
              (cand (cond
                     ((= 0 (length candidates)) nil)
                     ((= 1 (length candidates)) (car candidates))
                     (t (completing-read "Choose the one to link: " candidates)))))
         (if cand (find-file cand)
           ())))
      (default
       (beep))))
  )

Fancy Misc Things

Popweb

(use-package popweb
  :if mk-feature/gui
  :defer t
  :disabled t
  :straight (:type git :host github :repo "manateelazycat/popweb" :files ("*"))
  :init
  (setq popweb-root (file-name-directory (locate-library "popweb.el")))
  (add-to-list 'load-path (concat popweb-root "extension/latex"))
  (require 'popweb-latex)
  (add-to-list 'load-path (concat popweb-root "extension/dict"))
  (require 'popweb-dict)
  )

Less (if ever) used

(use-package chronos :defer t)
(use-package elquery :defer)
(use-package citeproc :defer)
(use-package org-download :defer)
(use-package symbol-overlay :defer)
(use-package read-aloud
  :disabled
  :config
  (setq read-aloud-engine "say"))
(use-package emacs-badge
  :if (not is-android)
  :defer t
  :straight (:type git :host github :repo "mkvoya/emacs-badge" :files ("*"))
  :config
  (require 'emacs-badge)
  (setq emacs-badge-timer
        (run-with-timer
         30 30
         '(lambda()
            (emacs-badge-update (format "%s" (mk/count-today-todos))))))

  )
(use-package elnode
  :defer
  :straight (:type git :host github :repo "jcaw/elnode"))
(use-package multiple-cursors
  :bind (("C-!" . mc/mark-next-like-this)))
;; (load-file "~/.emacs.d/site-lisp/wc.el")
(use-package motd
  :if mk-feature/noteman
  :straight nil
  :ensure nil
  :load-path "~/.emacs.d/site-lisp/"
  :config
  (if mk-feature/light
      (progn
        (setq motd-background-color "#EFE0C0")
        (setq motd-border-color "#910471")
        )
    (setq motd-background-color "#204230")
    (setq motd-border-color "#444444")
    )
  (setq motd--git-commit-dir "~/Dropbox/Dreams")
  ;; (motd-start-timer)
  )
(use-package xwidget-apps
  :if mk-feature/noteman
  :straight nil
  :ensure nil
  :load-path "~/.emacs.d/site-lisp/xwidget-apps/"
  :config
  (xwidget-dict-mode)
  )
(defun mk/--pick-project ()
  "Pick a project to do."
  (seq-random-elt
   (mapcar #'(lambda (h)
               (let* ((headline (plist-get h 'headline))
                      (title (substring-no-properties (car (plist-get headline :title)))))
                 title))
           (org-ql-query
             :select 'element
             :from "~/Dropbox/Dreams/Org/Projects.org"
             :where '(todo "PROJECT")
             :order-by 'deadline))))

(defun mk/pick-project ()
  "Pick a project to do."
  (interactive)
  (message (mk/--pick-project)))
(setq python-shell-completion-native-disabled-interpreters nil)
(use-package ox-pandoc)
(use-package treesit-auto
  :custom
  (treesit-auto-install 'prompt)
  :config
  (setq treesit-font-lock-level 4)
  (treesit-auto-add-to-auto-mode-alist 'all)
  (global-treesit-auto-mode))
(use-package org-timeline
  :after org
  :config
  (add-hook 'org-agenda-finalize-hook 'org-timeline-insert-timeline :append)
  )
(use-package darkroom
  :config
  (setq darkroom-keep-lines t)
  )

Anki-like

(use-package org-drill
  :disabled t)

(use-package org-anki
  :after (org)
  :config
  ;; Override the cloze function
  ;; The below function does not work since Anki does not show the back of the card for clozes.
  ;; (defun org-anki--region-to-cloze (begin end arg hint)
  ;;   "Cloze region from BEGIN to END with number ARG."
  ;;   (let ((region (buffer-substring begin end)))
  ;;     (save-excursion
  ;;       (delete-region begin end)
  ;;       (insert (with-output-to-string
  ;;                 (princ (format "{{c%d::%s" (or arg 1) region))
  ;;                 (unless (string-blank-p hint) (princ (format "::%s" hint)))
  ;;                 (princ "}}")))
  ;;       (org-end-of-subtree)
  ;;       (insert "\n" region ": " hint)
  ;;       )))
  )
(use-package define-word)
(use-package sdcv :disabled t)

;; via http://www.emacswiki.org/emacs/ThesauriAndSynonyms
;; The file names are absolute, not relative, locations
;;     - e.g. /foobar/mthesaur.txt.cache, not mthesaur.txt.cache
(use-package synonyms
  :ensure t ;; install package if not found
  :init ;; executed before loading package
  (setq synonyms-file        "~/.emacs.d/data/mthesaur.txt")
  (setq synonyms-cache-file  "~/.emacs.d/data/synonyms.cache")
  :config
  (defun my-synonym-current-word ()
    "Lookup synonyms for current word."
    (interactive)
    (synonyms-lookup (thing-at-point 'word) nil nil))
  :bind (:map my-map ("s" . my-synonym-current-word))
  )
(use-package org-pomodoro)
(use-package wwg
  :straight (:type git :host github :repo "ag91/writer-word-goals")
  :config
  )
(defun how-many-str (regexp str)
  (cl-loop with start = 0
           for count from 0
           while (string-match regexp str start)
           do (setq start (match-end 0))
           finally return count))
(defun how-many-checked (str)
  (+ (how-many-str "\\[[^[:blank:]]\\]" str)
     (how-many-str "([^[:blank:]])" str)))
(defun how-many-unchecked (str)
  (+ (how-many-str "\\[ \\]" str)
     (how-many-str "( )" str)))
(defun mk/org-columns--summary-pomodoro-count (check-boxes _)
  "Summarize pomodoro CHECK-BOXES with a check-box cookie."
  (let ((checked (cl-reduce '+ (cl-mapcar #'how-many-checked check-boxes)))
        (unchecked (cl-reduce '+ (cl-mapcar #'how-many-unchecked check-boxes))))
    (format "[%d/%d]" checked (+ checked unchecked))))
(setq org-columns-summary-types
      '(("P/" . mk/org-columns--summary-pomodoro-count))
      )

(defun mk/org-clocking-on-state-change ()
  "Auto clock-in/-out when state changes."
  (unless (string= org-last-state org-state)
    (cond
     ((string= org-state "ONGOING")
      (org-clock-in))
     ((string= org-last-state "ONGOING")
      (org-clock-out)
      ))))
(add-hook 'org-after-todo-state-change-hook #'mk/org-clocking-on-state-change)
(use-package format-all)
(use-package unkillable-scratch
  :config (progn (unkillable-scratch 1)))
(use-package scratch)

;; Speedy reading
(use-package spray
  :config (progn
            (setq spray-wpm 400
                  spray-margin-left 4
                  spray-margin-top 12)
            (bind-key "+" 'spray-faster spray-mode-map)
            (bind-key "-" 'spray-slower spray-mode-map)
            (add-to-list 'spray-unsupported-minor-modes 'beacon-mode)))

(use-package synosaurus
  :ensure-system-package ((wn . wordnet))
  ;; :bind (("C-c w s" . synosaurus-lookup)
  ;;        ("C-c w S" . synosaurus-choose-and-replace))
  :custom
  (synosaurus-prefix (kbd "C-c S"))
  :config (progn
            (setq synosaurus-choose-method 'popup)
            (unbind-key "C-c s l" synosaurus-mode-map)
            (unbind-key "C-c s r" synosaurus-mode-map)
            (add-hook 'org-mode-hook #'synosaurus-mode)
            (add-hook 'LaTeX-mode-hook #'synosaurus-mode)))
(use-package powerthesaurus
  ;; :bind ("C-c w p" . powerthesaurus-lookup-dwim)
  :config (add-to-list 'display-buffer-alist
                       `(,(rx bos "*Powerthesaurus - " (0+ any) "*" eos)
                         (display-buffer-in-side-window)
                         (side . right)
                         (slot . 0)
                         (window-width . 80))))

(use-package focus)
(use-package org-tidy
  :disabled t
  :ensure t
  :hook (org-mode . org-tidy-mode)
  :config
  (setq org-tidy-top-property-style 'keep
        org-tidy-properties-style 'fringe)
  )
beaconhttps://github.com/Malabarba/beacon
(use-package holo-layer
  :disabled t
  :if (not is-android)
  :straight (:type git :host github :repo "manateelazycat/holo-layer" :files ("*"))
  :config
  (setq holo-layer-enable-cursor-animation t)
  (setq holo-layer-enable-place-info nil)
  (setq holo-layer-cursor-animation-color-gradient-start-value 200)
  (setq holo-layer-enable-indent-rainbow nil)
  (setq holo-layer-enable-type-animation t)
  (setq holo-layer-type-animation-style "lightning")
  ;; (setq holo-layer-type-animation-style "balloon")
  ;; (setq holo-layer-type-animation-style 'supernova)
  ;; (setq holo-layer-type-animation-style 'flame)
  ;; (setq holo-layer-sort-tab-ui t)
  ;; (setq holo-layer-enable-indent-rainbow t)
  ;; (setq holo-layer-cursor-color "Goldenrod")
  (holo-layer-enable)
  )
;; (use-package sort-tab :ensure t :init (sort-tab-mode 1))
(defun mk/count-today-todos ()
  "Count the number of today's to-do tasks."
  (interactive)
  (let ((count 0)
        (today (format-time-string "%Y-%m-%d")))
    (org-compile-prefix-format 'todo)
    (org-map-entries
     (lambda ()
       (when (and (string= (org-get-todo-state) "TODO")
                  (or (string= (org-entry-get nil "SCHEDULED") today)
                      (and (org-entry-get nil "DEADLINE")
                           (string< today (org-entry-get nil "DEADLINE")))
                      ))
         (setq count (1+ count))))
     nil 'agenda)
    count)
  )
(use-package dirvish)
(use-package htmlize)
(setq org-tags-column 0)
(defun org-babel-C-execute/filter-args (args)
  (when-let* ((params (cadr args))
              (stdin (cdr (assoc :stdin params)))
              (res (org-babel-ref-resolve stdin))
              (stdin (org-babel-temp-file "c-stdin-")))
    (with-temp-file stdin (insert res))
    (let* ((cmdline (assoc :cmdline params))
           (cmdline-val (or (cdr cmdline) "")))
      (when cmdline (setq params (delq cmdline params)))
      (setq params
            (cons (cons :cmdline (concat cmdline-val " <" stdin))
                  params))
      (setf (cadr args) params)))
  args)

(with-eval-after-load 'ob-C
  (advice-add 'org-babel-C-execute :filter-args
              #'org-babel-C-execute/filter-args))

Interactive Utilities

(defun mk/insert-datetime()
  "Insert the current date and time."
  (interactive)
  (insert (format-time-string "%F %T")))
;; From https://emacs.stackexchange.com/questions/47627/identify-buffer-by-part-of-its-name
(defun switch-to-existing-buffer-other-window (part)
  "Switch to buffer with PART in its name."
  (interactive
   (list (read-buffer-to-switch "Switch to buffer in other window: ")))
  (let ((candidates
         (cl-remove
          nil
          (mapcar (lambda (buf)
                    (let ((pos (string-match part (buffer-name buf))))
                      (when pos
                        (cons pos buf))))
                  (buffer-list)))))
    (unless candidates
      (user-error "There is no buffers with %S in its name." part))
    (setq candidates (cl-sort candidates #'< :key 'car))
    (switch-to-buffer-other-window (cdr (car candidates)))))

(defun mk/open-orgroam-panel()
  "Open the Org-roam client at [http://127.0.0.1:35901]."
  (interactive)
  ;; Ensure the server is running.
  (unless org-roam-ui-mode (org-roam-ui-mode))
  ;; Ensure the session is running.
  (xwidget-webkit-browse-url "http://127.0.0.1:35901" nil)
  ;; Switch to the buffer
  (switch-to-existing-buffer-other-window "Roam Server")
  )
(defun mk/webkit-new-url (url &optional new-session)
  "Create a new session to browse the URL."
  (interactive (progn
                 (require 'browse-url)
                 (browse-url-interactive-arg "xwidget-webkit URL: ")))
  (xwidget-webkit-browse-url url t)
  )

Custom key-bindings

;; from https://stackoverflow.com/questions/1250846/wrong-type-argument-commandp-error-when-binding-a-lambda-to-a-key
(global-set-key (kbd "C-h c") #'describe-char)
(global-set-key (kbd "C-c h") (lambda () (interactive) (find-file "~/Dropbox/Dreams/Org/Main.org")))
(global-set-key (kbd "C-c i") (lambda () (interactive) (find-file "~/Dropbox/Dreams/Org/Inbox.org")))
(global-set-key (kbd "C-c r") (lambda () (interactive) (find-file "~/.emacs.d/emacs-config.org")))
(global-set-key (kbd "C-c p") (lambda () (interactive) (find-file "~/Dropbox/Dreams/Org/Projects.org")))
(global-set-key (kbd "M-s-<left>") 'tab-previous)
(global-set-key (kbd "M-s-<right>") 'tab-next)
(global-set-key (kbd "M-s-n") 'tab-new)
(global-set-key (kbd "C-c w") (lambda () (interactive) (find-file "~/Dropbox/Dreams/Org/Weights.org")))
;; Open ibuffer upon "C-c i"
(global-set-key (kbd "C-c b") 'ibuffer)
;; (global-set-key (kbd "C-c C-m e") (lambda () (interactive) (find-file "~/.emacs.d/emacs-config.org")))
;; (global-unset-key [mouse-3])
;; (global-set-key [down-mouse-3]
;;                 `(menu-item ,(purecopy "Menu Bar") ignore
;;                             :filter (lambda (_)
;;                                       (if (zerop (or (frame-parameter nil 'menu-bar-lines) 0))
;;                                           (mouse-menu-bar-map)
;;                                         (mouse-menu-major-mode-map)))))

AI Tools

(use-package copilot
  :straight (:host github :repo "copilot-emacs/copilot.el" :files ("*.el"))
  :ensure t
  :config
  (define-key copilot-completion-map (kbd "<tab>") 'copilot-accept-completion)
  (define-key copilot-completion-map (kbd "TAB") 'copilot-accept-completion)
  )
;; you can utilize :map :hook and :config to customize copilot
(setq-default
   header-line-format
   '("GC: " (:eval (number-to-string gcs-done)) " - " (:eval (number-to-string gc-elapsed)) "s"))
(defun mk/org-archive-to-specified-file ()
  "Archive the current org entry to a user-specified file."
  (interactive)
  (let ((file (read-file-name "Archive to file: ")))
    (let ((org-archive-location (concat file "::")))
      (org-archive-subtree))
    (message "Archived to %s" file)))

Cursor-like

(use-package elysium
  :straight
  (:host github :repo "lanceberge/elysium" :branch "main" :files ("*.el"))
  :custom
  ;; Below are the default values
  (elysium-window-size 0.33) ; The elysium buffer will be 1/3 your screen
  (elysium-window-style 'vertical)) ; Can be customized to horizontal
(use-package smerge-mode
  :hook
  (prog-mode . smerge-mode))

(use-package gptel
  :config
  (defun remove-trailing-newline (str)
    "Remove the trailing newline character from STR, if it exists."
    (if (string-suffix-p "\n" str)
        (substring str 0 -1)
      str))
  (defun read-file-contents (file-path)
    "Read the contents of FILE-PATH and return it as a string."
    (with-temp-buffer
      (insert-file-contents file-path)
      (buffer-string)))
  (defun gptel-api-key ()
    (remove-trailing-newline (read-file-contents "~/.secrets/ipads-chatgpt.key")))
  (setq gptel-use-curl nil)
  (setq
   ;; gptel-model "gpt-4o-2024-05-13"
   gptel-model "claude-3-5"
   gptel-backend
   (gptel-make-openai "IPADS GPT"
     :host "ipads.chat.gpt:3006"
     :protocol "http"
     :stream t
     :key #'gptel-api-key
     :models '("claude-3-5"
               "gpt-4o-2024-05-13"
               "gpt-4o"))))

Scrolling

;; Let's disable the precision mode since it brings some troubles with the precision mode
;; (pixel-scroll-precision-mode)
(setq scroll-preserve-screen-position 'always)

Dired

(defun mk/dired-open-pdf ()
  "In dired, open the file named on this line."
  (interactive)
  (let* ((file (dired-get-filename nil t)))
    (message "Opening %s..." file)
    (call-process "open" nil 0 nil "-a" "PDF Expert" file)
    (message "Opening %s done" file)))
(define-key dired-mode-map "E" 'mk/dired-open-pdf)

(defun mk/dired-curl ()
  "Get file from url to dired."
  (interactive)
  (when (equal major-mode 'dired-mode)
    (let* ((url (read-string "URL: "))
           (cwd (dired-current-directory))
           (target (concat (file-name-as-directory cwd) (file-name-nondirectory url))))
      (url-copy-file url target)
      )))

(use-package diredfl :config (diredfl-global-mode))
(use-package dired+ :config (setq diredp-hide-details-propagate-flag t))
(use-package dired-preview
  :config
  ;; Default values for demo purposes
  (setq dired-preview-delay 0.7)
  (setq dired-preview-max-size (expt 2 20))
  (setq dired-preview-ignored-extensions-regexp
        (concat "\\."
                "\\(mkv\\|webm\\|mp4\\|mp3\\|ogg\\|m4a"
                "\\|gz\\|zst\\|tar\\|xz\\|rar\\|zip"
                "\\|iso\\|epub\\|pdf\\)"))
  )

A list of interesting packges

(use-package infinite
  :disabled t
  :straight (:host gitlab :repo "andreyorst/infinite.el")
  )
(use-package eee
  :disabled t
  :straight (:type git :host github :repo "eval-exec/eee.el"
                   :files (:defaults "*.el" "*.sh"))
  :config
  (setq ee-terminal-command "wezterm")
  )
(use-package maple-explorer :disabled t)
(use-package org-real :disabled t) ; https://gitlab.com/tygrdev/org-real
(use-package explain-pause-mode :disabled t)
(use-package keystrokes :disabled t
  :straight (:type git :host gitlab :repo "marcowahl/keystrokes"))
(use-package ns-auto-titlebar :disabled t)  ; We used a better patch.
(use-package elgantt :disabled t
  :straight (:type git :host github :repo "legalnonsense/elgantt"))
(use-package paper :disabled t
  :straight (:host github :repo "ymarco/paper-mode" :files("*.el" "*.so")))

Misc major modes

(use-package gitlab-ci-mode :defer t)
(use-package dockerfile-mode :mode "Dockerfile" :defer t)
(use-package lua-mode :defer)
(use-package swift-mode :disabled t)
(use-package typescript-mode)
(use-package adoc-mode :defer t :straight (:host github :repo "sensorflo/adoc-mode"))
(use-package elm-mode)
(use-package jinja2-mode :mode "\\.jinja2\\'" :defer t)
(use-package vue-mode :mode "\\.vue\\'" :defer t)
;; Python Support
(use-package elpy :defer t)
(use-package py-autopep8 :defer t :config (setq py-autopep8-options '("--max-line-length=120")))
(use-package blacken :defer t :config (setq blacken-line-length 120))
(use-package ein :defer t)
(use-package live-py-mode :defer t)
;; Markdown Support
(use-package markdown-mode :defer t
  :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'" . markdown-mode)
         ("\\.markdown\\'" . markdown-mode))
  :config
  ;; (setq markdown-command "multimarkdown")
  (setq markdown-command "/usr/local/bin/pandoc")
  (setq markdown-preview-stylesheets (list "https://raw.githubusercontent.com/sindresorhus/github-markdown-css/gh-pages/github-markdown.css"))
  ;;"http://thomasf.github.io/solarized-css/solarized-light.min.css"
  )
(use-package flymd :after (markdown-mode))

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published