commit 0741c6642d145f6e724c6344aa911642c8281f29
Author: Andsy10 <andsy1016@gmail.com>
Date: Wed, 22 Jul 2026 08:14:08 +0800
Initial commit
Diffstat:
28 files changed, 3655 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,12 @@
+*
+
+!init.el
+!early-init.el
+!lisp/
+!lisp/**/
+!lisp/**/*.el
+
+!.gitignore
+
+/lisp/init-proxy.el
+/lisp/init-local.el
diff --git a/early-init.el b/early-init.el
@@ -0,0 +1,18 @@
+;;; early-init.el --- early-init.el -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(setq package-enable-at-startup nil)
+
+(setq inhibit-startup-screen t)
+(when (fboundp 'tool-bar-mode)
+ (tool-bar-mode -1)
+ (scroll-bar-mode -1))
+(menu-bar-mode -1)
+
+(prefer-coding-system 'utf-8)
+
+(setq frame-background-mode 'dark)
+;;; early-init.el ends here
diff --git a/init.el b/init.el
@@ -0,0 +1,43 @@
+;;; init.el --- init.el -*- lexical-binding: t -*-
+
+;;; Commentary:
+;; trogloxene's Emacs
+
+;;; Code:
+
+(add-to-list 'load-path
+ (expand-file-name (concat user-emacs-directory "lisp")))
+
+(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
+(load custom-file t)
+
+(require 'init-const)
+
+(if (or (display-graphic-p) *is-android*)
+ (progn
+ (require 'init-proxy nil t)
+ (require 'init-startup)
+ (require 'init-elpa)
+ (require 'init-base)
+ (require 'init-edit)
+ (require 'init-completion)
+ (require 'init-package)
+ (require 'init-org)
+ (require 'init-prog)
+ (require 'init-window)
+ (require 'init-exwm)
+ (require 'init-dired)
+ (require 'init-gptel)
+ (require 'init-ui)
+ (require 'init-kbd-func)
+ (require 'init-kbd)
+ (require 'init-segmentation)
+ (require 'init-local nil t))
+ (progn
+ (require 'init-terminal-startup)
+ (require 'init-proxy nil t)
+ (require 'init-elpa)
+ (require 'init-terminal-package)
+ (require 'init-terminal-ui)
+ (require 'init-terminal-kbd)))
+;;; init.el ends here
diff --git a/lisp/init-base.el b/lisp/init-base.el
@@ -0,0 +1,268 @@
+;;; init-base.el --- base config -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; keybindings
+(use-package general)
+
+;; mode names in mode line
+(use-package delight
+ :config
+ (delight
+ `((eldoc-mode nil eldoc)
+ (org-indent-mode nil org-indent)
+ (desktop-environment-mode nil desktop-environment)
+ (hs-minor-mode nil hideshow)
+ (rainbow-delimiters-mode ,(propertize " Rdelimiters" 'face 'rainbow-delimiters-depth-1-face) rainbow-delimiters))))
+
+;; garbage collection
+(use-package gcmh
+ :delight
+ :init
+ (setq gcmh-idle-delay 'auto
+ gcmh-auto-idle-delay-factor 10
+ gcmh-high-cons-threshold #x4000000)
+ (gcmh-mode))
+
+;; benchmark
+(use-package benchmark-init
+ :init
+ (benchmark-init/activate)
+ :hook
+ (after-init . benchmark-init/deactivate))
+
+;; server-mode
+(use-package server
+ :demand t
+ :hook
+ (emacs-startup . (lambda ()
+ (unless (server-running-p)
+ (server-mode 1)))))
+
+;; recently opened files
+(if (or (display-graphic-p) *is-android*)
+ (use-package recentf
+ :hook
+ (after-init . recentf-mode)
+ :init
+ (setq recentf-max-saved-items 30)
+ :config
+ (if *is-android*
+ (add-to-list 'recentf-exclude "~/storage/shared/my-org-note/journal/.*\\.org\\'")
+ (add-to-list 'recentf-exclude "~/org/my-org-note/journal/.*\\.org\\'")
+ (add-to-list 'recentf-exclude "~/org/my-org-note/20260509T232442==agenda--all-my-todos__org\\.org"))
+ (add-to-list 'recentf-exclude "~/.emacs.d/emms/history")
+ (add-to-list 'recentf-exclude "~/.emacs.d/bookmarks")))
+
+;; save minibuffer history
+(use-package savehist
+ :hook
+ (after-init . savehist-mode)
+ :init
+ (setq enable-recursive-minibuffers t
+ history-length 50
+ savehist-additional-variables '(mark-ring
+ global-mark-ring
+ search-ring
+ regexp-search-ring
+ extended-command-history)
+ savehist-autosave-interval 300))
+
+;; save cursor place
+(use-package saveplace
+ :hook
+ (after-init . save-place-mode))
+
+;; restart emacs
+(use-package restart-emacs)
+
+;; async
+(unless *is-android*
+ (use-package async
+ :hook
+ (after-init . dired-async-mode)
+ (after-init . async-bytecomp-package-mode)))
+
+;; autorevert buffer
+(use-package autorevert
+ :delight
+ :hook
+ (after-init . global-auto-revert-mode))
+
+;; display keybindings
+(use-package which-key
+ :straight nil
+ :delight
+ :hook
+ (after-init . which-key-mode))
+
+;; save window changes
+(use-package winner
+ :hook
+ (after-init . winner-mode))
+
+;; ibuffer
+(use-package ibuffer
+ :config
+ (setq ibuffer-saved-filter-groups
+ '(("Main"
+ ("App" (mode . exwm-mode))
+ ("Scratch" (or
+ (name . "^*scratch")))
+ ("Tramp"(or
+ (name . "^\\*tramp")))
+ ("eww" (or
+ (mode . eww-mode)
+ (mode . eww-bookmark-mode)
+ (mode . eww-buffers-mode)
+ (mode . eww-history-mode)))
+ ("AI" (or
+ (name . "^\\*OpenCode")
+ (name . "\\*opencode-serve\\*")
+ (name . "^\\*gptel")))
+ ("Calc" (or
+ (mode . calc-mode)
+ (mode . calc-trail-mode)))
+ ("Text" (or
+ (mode . org-mode)
+ (mode . markdown-mode)
+ (name . "^\\*\\[D\\] FILE backlinks for")))
+ ("Shell" (or
+ (mode . eshell-mode)
+ (mode . eat-mode)
+ (mode . vterm-mode)))
+ ("Scripts" (or
+ (mode . shell-script-mode)
+ (mode . shell-mode)
+ (mode . sh-mode)
+ (mode . lua-mode)
+ (mode . bat-mode)))
+ ("Config" (or
+ (mode . conf-mode)
+ (mode . conf-desktop-mode)
+ (mode . conf-toml-mode)
+ (mode . conf-xdefaults-mode)
+ (mode . conf-javaprop-mode)
+ (mode . conf-unix-mode)
+ (mode . toml-ts-mode)
+ (mode . yaml-ts-mode)
+ (mode . json-ts-mode)))
+ ("Elisp" (mode . emacs-lisp-mode))
+ ("Scheme" (or
+ (mode . scheme-mode)))
+ ("Geiser" (or
+ (name . "^Geiser")
+ (mode . geiser-repl-mode)
+ (mode . geiser-debug-mode)
+ (mode . geiser-messages-mode)
+ (mode . geiser-debug-mode)
+ (mode . geiser-doc-mode)
+ (mode . geiser-autodoc-mode)))
+ ("Common-lisp" (or
+ (mode . common-lisp-mode)
+ (mode . lisp-mode)))
+ ("Sly" (or
+ (mode . lisp-data-mode)
+ (mode . sly-db-mode)
+ (mode . sly-mrepl-mode)
+ (name . "\\*sly-compilation\\*")
+ (name . "^\\*img-cache\\*")))
+ ("Help" (or
+ (mode . help-mode)
+ (mode . helpful-mode)))
+ ("Info" (or
+ (name . "^\\*info")))
+ ("Magit" (or
+ (mode . magit-blame-mode)
+ (mode . magit-cherry-mode)
+ (mode . magit-diff-mode)
+ (mode . magit-log-mode)
+ (mode . magit-process-mode)
+ (mode . magit-status-mode)
+ (mode . magit-revision-mode)
+ (mode . magit-refs-mode)))
+ ("Directories" (or
+ (mode . dired-mode)
+ (name . "^*dirvish")
+ (mode . trashed-mode)))
+ ("Grep" (or
+ (mode . grep-mode)
+ (mode . rg-mode)
+ (mode . xref--xref-buffer-mode)
+ (mode . xref-edit-mode)
+ (mode . occur-mode)
+ (mode . occur-edit-mode)))
+ ("Diff" (or
+ (name . "^*Diff")
+ (mode . ediff-mode)
+ (mode . vundo-diff-mode)))
+ ("Emacs" (or
+ (name . "^\\*Help\\*$")
+ (name . "^\\*Custom.*")
+ (name . "^\\*EMMS Playlist\\*")
+ (name . "^\\*Messages\\*$")
+ (name . "*Chinese-word-segmentation*")
+ (name . "^*Buffer List*")
+ (name . "\\*discomfort\\*")
+ (mode . calendar-mode)
+ (mode . grep-mode)
+ (mode . proced-mode)
+ (mode . syncthing-mode))))))
+
+ (add-hook 'ibuffer-hook
+ (lambda () (ibuffer-switch-to-saved-filter-groups "Main")
+ (unless (eq ibuffer-sorting-mode 'alphabetic)
+ (ibuffer-do-sort-by-alphabetic))))
+
+ (setq ibuffer-show-empty-filter-groups nil
+ ibuffer-use-other-window t
+ ibuffer-default-sorting-mode 'filename))
+
+(use-package simple
+ :straight nil
+ :hook
+ (after-init . size-indication-mode)
+ (after-init . column-number-mode)
+ :config
+ (setq kill-whole-line t
+ set-mark-command-repeat-pop t)) ;easier to pop marks
+
+;; scroll
+(unless *is-mac*
+ (use-package pixel-scroll
+ :straight nil
+ :hook
+ (after-init . pixel-scroll-precision-mode)
+ :init
+ (setq scroll-preserve-screen-position t
+ scroll-conservatively 101)
+ :config
+ (advice-add 'pixel-scroll-precision :around
+ (lambda (orig event)
+ (cl-letf (((symbol-function 'device-class)
+ (lambda (&rest _) 'mouse)))
+ (funcall orig event))))))
+
+;; eww
+(use-package eww
+ :config
+ (setq eww-auto-rename-buffer t))
+
+;; tramp
+(use-package tramp
+ :config
+ (setq tramp-default-method 'ssh
+ tramp-auto-save-directory "~/.emacs.d/tramp-auto-save")
+ (add-to-list 'tramp-remote-path 'tramp-own-remote-path)
+ (connection-local-set-profile-variables
+ 'remote-dirvish-fix
+ '((insert-directory-program . "ls")
+ (tramp-direct-async-process . t)))
+ (connection-local-set-profiles
+ '(:application tramp :protocol "ssh")
+ 'remote-dirvish-fix))
+
+(provide 'init-base)
+;;; init-base.el ends here
diff --git a/lisp/init-completion.el b/lisp/init-completion.el
@@ -0,0 +1,203 @@
+;;; init-completion.el --- completion config -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; minibuffer completion
+(use-package vertico
+ :hook
+ (after-init . vertico-mode))
+
+;; orderless completion
+(use-package orderless
+ :custom
+ (completion-styles '(orderless basic)))
+
+;; marginalia in minibuffer
+(use-package marginalia
+ :hook
+ (after-init . marginalia-mode))
+
+;; search and navigation
+(use-package consult
+ :config
+ ;; set locate arguments
+ (cond
+ (*is-windows*
+ (setq consult-locate-args (encode-coding-string "es.exe -i -p -r" 'gbk)
+ consult-ripgrep-args (encode-coding-string
+ "rg --null --line-buffered --color=never --max-columns=1000 --path-separator / --smart-case --no-heading --line-number"
+ 'gbk))
+ (add-to-list 'process-coding-system-alist '("es" gbk . gbk)))
+ (*is-mac*
+ (setq consult-locate-args "mdfind -name"))
+ (*is-linux*
+ (setq consult-locate-args "plocate --basename --ignore-case")))
+
+ ;; help
+ (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)
+ (setq consult-narrow-key "<")
+
+ ;; xref
+ (setq xref-show-definitions-function #'consult-xref)
+ (setq xref-show-xrefs-function #'consult-xref)
+
+ ;; set some buffer filter
+ (setq consult-buffer-filter
+ (cl-union consult-buffer-filter
+ '("^\\*dirvish"
+ "^PREVIEW"
+ "^\\*helpful"
+ "^\\*Help"
+ "Diff"
+ "straight"
+ "\\*Messages\\*"
+ "\\*Chinese-word-segmentation\\*"
+ "\\*gptel-reasoning\\*"
+ "\\*gptel-log\\*")
+ :test 'equal)))
+
+;; right-click
+(use-package embark
+ :commands
+ embark-prefix-help-command
+ :init
+ (setq prefix-help-command 'embark-prefix-help-command)
+ :config
+ (defun my-embark-preview ()
+ "Previews candidate in vertico buffer, unless it's a consult command."
+ (interactive)
+ (unless (bound-and-true-p consult--preview-function)
+ (save-selected-window
+ (let ((embark-quit-after-action nil))
+ (embark-dwim)))))
+
+ (add-to-list 'display-buffer-alist
+ '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
+ nil
+ (window-parameters (mode-line-format . none))))
+
+ (with-no-warnings
+ (with-eval-after-load 'which-key
+ (defun embark-which-key-indicator ()
+ "An embark indicator that displays keymaps using which-key.
+The which-key help message will show the type and value of the
+current target followed by an ellipsis if there are further
+targets."
+ (lambda (&optional keymap targets prefix)
+ (if (null keymap)
+ (which-key--hide-popup-ignore-command)
+ (which-key--show-keymap
+ (if (eq (plist-get (car targets) :type) 'embark-become)
+ "Become"
+ (format "Act on %s '%s'%s"
+ (plist-get (car targets) :type)
+ (embark--truncate-target (plist-get (car targets) :target))
+ (if (cdr targets) "…" "")))
+ (if prefix
+ (pcase (lookup-key keymap prefix 'accept-default)
+ ((and (pred keymapp) km) km)
+ (_ (key-binding prefix 'accept-default)))
+ keymap)
+ nil nil t (lambda (binding)
+ (not (string-suffix-p "-argument" (cdr binding))))))))
+
+ (setq embark-indicators
+ '(embark-which-key-indicator
+ embark-highlight-indicator
+ embark-isearch-highlight-indicator))
+
+ (defun embark-hide-which-key-indicator (fn &rest args)
+ "Hide the which-key indicator immediately when using the completing-read prompter."
+ (which-key--hide-popup-ignore-command)
+ (let ((embark-indicators
+ (remq #'embark-which-key-indicator embark-indicators)))
+ (apply fn args)))
+
+ (advice-add #'embark-completing-read-prompter
+ :around #'embark-hide-which-key-indicator))))
+
+;; embark-consult
+(use-package embark-consult)
+
+;; eglot
+(use-package eglot
+ :config
+ (setq eglot-send-changes-idle-time 0.25))
+
+;; corfu
+(use-package corfu
+ :autoload
+ (corfu-quit consult-completion-in-region)
+ :bind
+ (:map corfu-map
+ ("M-d" . corfu-popupinfo-documentation))
+ :custom
+ (corfu-auto t)
+ (corfu-auto-prefix 2)
+ (corfu-count 12)
+ (corfu-preview-current nil)
+ (corfu-on-exact-match nil)
+ (corfu-auto-delay 0.2)
+ (corfu-popupinfo-delay '(0.4 . 0.2))
+ (global-corfu-modes '((not erc-mode
+ circe-mode
+ help-mode
+ gud-mode
+ vterm-mode)
+ t))
+ :hook
+ (after-init . global-corfu-mode)
+ (after-init . corfu-popupinfo-mode)
+ (after-init . corfu-history-mode)
+ :config
+ ;;Quit completion before saving
+ (add-hook 'before-save-hook #'corfu-quit)
+ (add-hook 'eshell-mode-hook
+ (lambda ()
+ (setq-local corfu-auto nil)
+ (local-set-key (kbd "TAB") 'completion-at-point)))
+ :bind
+ (:map corfu-map
+ ("RET" . nil)))
+
+(if (not (and (display-graphic-p)
+ (>= emacs-major-version 31)))
+ (use-package corfu-terminal
+ :hook
+ (after-init . corfu-terminal-mode)))
+
+(use-package emacs
+ :custom
+ (tab-always-indent 'complete)
+
+ ;; Emacs 30 and newer: Disable Ispell completion function.
+ ;; Try `cape-dict' as an alternative.
+ (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.
+ (read-extended-command-predicate #'command-completion-default-include-p))
+
+;; cape
+(use-package cape
+ :commands (cape-file cape-elisp-block cape-keyword)
+ :autoload (cape-wrap-noninterruptible cape-wrap-nonexclusive cape-wrap-buster)
+ :autoload (cape-wrap-silent)
+ :init
+ ;; (add-to-list 'completion-at-point-functions #'cape-dabbrev)
+ (add-to-list 'completion-at-point-functions #'cape-file)
+ (add-to-list 'completion-at-point-functions #'cape-elisp-block)
+ (add-to-list 'completion-at-point-functions #'cape-keyword)
+ ;; (add-to-list 'completion-at-point-functions #'cape-abbrev)
+
+ ;; Make these capfs composable.
+ (advice-add 'comint-completion-at-point :around #'cape-wrap-nonexclusive)
+ (advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)
+ (advice-add 'eglot-completion-at-point :around #'cape-wrap-nonexclusive)
+ (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-nonexclusive))
+
+(provide 'init-completion)
+;;; init-completion.el ends here
diff --git a/lisp/init-const.el b/lisp/init-const.el
@@ -0,0 +1,13 @@
+;;; init-const.el --- constant and system stuff -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(defconst *is-mac* (eq system-type 'darwin))
+(defconst *is-linux* (eq system-type 'gnu/linux))
+(defconst *is-windows* (or (eq system-type 'ms-dos) (eq system-type 'windows-nt)))
+(defconst *is-android* (if (getenv "TERMUX_VERSION") t nil))
+
+(provide 'init-const)
+;;; init-const.el ends here
diff --git a/lisp/init-dashboard.el b/lisp/init-dashboard.el
@@ -0,0 +1,24 @@
+;;; init-dashboard.el --- dashboard -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(use-package dashboard
+ :autoload dashboard-setup-startup-hook
+ :hook after-init
+ :config
+ (setq dashboard-banner-logo-title (format "%s" emacs-version)
+ dashboard-banner-ascii " ##### # # # # ####### # # # ##### ##### \n# # ## # # # # ## ## # # # # # # \n# # # # # # # # # # # # # # # \n# #### # # # # # ##### # # # # # # ##### \n# # # # # # # # # # ####### # # \n# # # ## # # # # # # # # # # # \n ##### # # ##### ####### # # # # ##### ##### "
+ dashboard-startup-banner 'ascii
+ dashboard-footer-messages '("hello")
+ dashboard-center-content t
+ dashboard-navigation-cycle t
+ dashboard-items '((recents . 8)
+ (bookmarks . 5)
+ (projects . 5))
+ dashboard-item-shortcuts '((recents . "r") (bookmarks . "b") (projects . "p") (agenda . "a") (registers . "e")))
+ (dashboard-setup-startup-hook))
+
+(provide 'init-dashboard)
+;;; init-dashboard.el ends here
diff --git a/lisp/init-dired.el b/lisp/init-dired.el
@@ -0,0 +1,143 @@
+;;; init-dired.el --- dired & dirvish -*-lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(use-package dired
+ :straight nil
+ :config
+ (when *is-mac*
+ (setq insert-directory-program "gls"
+ dired-use-ls-dired t))
+ (setq dired-dwim-target t
+ dired-listing-switches
+ "-l --almost-all --human-readable --group-directories-first --no-group"
+ dired-recursive-deletes 'always
+ dired-recursive-copies 'always
+ dired-mouse-drag-files t
+ mouse-drag-and-drop-region-cross-program t
+ dired-compress-file-default-suffix ".zip"
+ dired-kill-when-opening-new-dired-buffer nil
+ dired-auto-revert-buffer t
+ dired-create-destination-dirs 'ask
+ dired-create-destination-dirs-on-trailing-dirsep t
+ remote-file-name-inhibit-delete-by-moving-to-trash t)
+ (put 'dired-find-alternate-file 'disabled nil))
+
+;; dirvish
+(use-package dirvish
+ :straight
+ (dirvish :fork (:host github :repo "latiagertrutis/dirvish"))
+ :init
+ (dirvish-override-dired-mode)
+ :config
+ (require 'vc)
+
+ (if (or *is-mac* *is-android*)
+ (setq dirvish-hide-details t)
+ (setq dirvish-hide-details '(dirvish-side)))
+
+ (if *is-android*
+ (setq dirvish-default-layout nil
+ dirvish-layout-recipes '((1 0.6)))
+ (setq dirvish-default-layout nil
+ dirvish-layout-recipes '((1 0.15 0.45))))
+
+ (setq dirvish-use-mode-line t
+ dirvish-mode-line-format '(:left (sort omit symlink) :right (free-space index))
+ dirvish-attributes '(file-time file-size)
+ dirvish-yank-sources 'session
+ dirvish-hide-cursor nil)
+
+ :custom
+ (dirvish-quick-access-entries
+ (cond
+ (*is-windows*
+ '(("h" "~/" "Home")
+ ("e" "~/.emacs.d/" "Emacs config")
+ ("p" "c:/Users/gaozh/Pictures/Screenshots/" "Pictures")
+ ("d" "f:/下载25-2-10/" "Download")
+ ("v" "f:/luping26-1-11/" "Videos")
+ ("n" "h:/emacs/my-org-note/" "Notes")))
+
+ (*is-mac*
+ '(("h" "~/" "Home")
+ ("e" "~/.emacs.d/" "Emacs config")
+ ("p" "~/Pictures/" "Pictures")
+ ("d" "~/Downloads/" "Download")
+ ("v" "~/Movies/" "Videos")
+ ("n" "~/org/my-org-note/" "Notes")
+ ("g" "~/gptel/" "gptel sessions")))
+
+ (*is-linux*
+ '(("h" "~/" "Home")
+ ("e" "~/.emacs.d/" "Emacs config")
+ ("s" "~/.config/guix/" "System config")
+ ("p" "~/Pictures/" "Pictures")
+ ("d" "~/downloads/" "Downloads")
+ ("v" "~/视频/" "Videos")
+ ("n" "~/org/my-org-note/" "Notes")
+ ("g" "~/gptel/" "gptel sessions")))
+
+ (*is-android*
+ '(("h" "~/" "Home")
+ ("e" "~/.emacs.d" "Emacs")
+ ("n" "~/storage/shared/my-org-note/" "Notes")
+ ("g" "~/gptel/" "gptel sessions")))
+ (t nil))))
+
+;; gitignore
+(use-package dired-gitignore
+ :after
+ (dirvish dirvish-vc transient)
+ :demand t
+ :config
+ (transient-define-suffix dirvish-toggle-gitignore ()
+ "Toggle `dired-gitignore-mode' in current Dirvish buffer."
+ :description
+ (lambda ()
+ (format "Gitignore filter (%s)"
+ (if dired-gitignore-mode
+ (propertize "+" 'face 'transient-value)
+ (propertize "-" 'face 'transient-inactive-value))))
+ :transient t
+ (interactive)
+ (dired-gitignore-mode 'toggle))
+
+ (transient-append-suffix 'dirvish-vc-menu "v"
+ '("i" dirvish-toggle-gitignore)))
+
+;; trashed
+(unless *is-mac*
+ (use-package trashed
+ :commands
+ (trashed)
+ :config
+ (setq trashed-action-confirmer 'y-or-n-p
+ trashed-use-header-line t
+ trashed-sort-key '("Date deleted" . t)
+ trashed-date-format "%Y-%m-%d %H:%M:%S")))
+
+;; dired-async
+(use-package dired-rsync
+ :config
+ (setq dired-rsync-options "-az -e ssh"))
+
+;; mount disk
+(when *is-linux*
+ (use-package debase
+ :straight
+ (debase :type git
+ :host codeberg
+ :repo "emacs-weirdware/debase"))
+
+ (use-package discomfort
+ :commands discomfort
+ :straight
+ (discomfort :type git
+ :host codeberg
+ :repo "emacs-weirdware/discomfort")))
+
+(provide 'init-dired)
+;;; init-dired.el ends here
diff --git a/lisp/init-edit.el b/lisp/init-edit.el
@@ -0,0 +1,114 @@
+;;; init-edit.el --- edit and navigate -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; delete select
+(use-package delsel
+ :hook
+ (after-init . delete-selection-mode))
+
+;; insert paris
+(use-package elec-pair
+ :config
+ (setq electric-pair-inhibit-predicate 'electric-pair-conservative-inhibit
+ electric-pair-pairs (append '((?\= . ?\=)) electric-pair-pairs)))
+
+;; multiple cursors
+(use-package multiple-cursors
+ :custom
+ (mc/insert-numbers-default 1)
+ (mc/always-run-for-all t)
+ :init
+ (setq mc/cmds-to-run-once
+ '(god-mode-all
+ hydra-multiple-cursors/body
+ hydra-multiple-cursors/mc/edit-lines
+ hydra-multiple-cursors/mc/insert-numbers
+ hydra-multiple-cursors/mc/mark-all-dwim
+ hydra-multiple-cursors/mc/mark-next-like-this
+ hydra-multiple-cursors/mc/mark-next-like-this-symbol
+ hydra-multiple-cursors/mc/mark-next-like-this-word
+ hydra-multiple-cursors/mc/mark-previous-like-this
+ hydra-multiple-cursors/mc/mark-previous-like-this-symbol
+ hydra-multiple-cursors/mc/mark-previous-like-this-word
+ hydra-multiple-cursors/mc/unmark-next-like-this
+ hydra-multiple-cursors/mc/unmark-previous-like-this
+ hydra-multiple-cursors/nil)))
+
+;; useful commands
+(use-package crux)
+
+;; hungry-delete
+(use-package hungry-delete)
+
+;; drag-stuff
+(use-package drag-stuff)
+
+;; better undo/redo
+(use-package undo-fu
+ :config
+ (setq undo-in-region t
+ undo-fu-allow-undo-in-region t))
+
+;; save undo history across sessions
+(use-package undo-fu-session
+ :hook
+ (after-init . undo-fu-session-global-mode))
+
+;; undo tree
+(use-package vundo
+ :init
+ (setq undo-limit 800000
+ undo-strong-limit 1200000
+ undo-outer-limit 12000000))
+
+;; expand-region
+(use-package expand-region
+ :commands
+ (er/mark-symbol er/mark-word)
+ :config
+ (setq expand-region-smart-cursor t))
+
+;; Chinese support for avy
+(use-package ace-pinyin
+ :delight
+ :hook
+ (after-init . ace-pinyin-global-mode))
+
+;; avy-zap
+(use-package avy-zap
+ :bind
+ (("M-z" . avy-zap-to-char-dwim)
+ ("M-Z" . avy-zap-up-to-char-dwim)))
+
+;; modal editing
+(use-package god-mode
+ :init
+ (if *is-android* (add-hook 'after-init-hook 'god-mode-all))
+ :config
+ (unless (or *is-android* (not use-package-always-defer)) (which-key-enable-god-mode-support))
+ (setq god-mode-enable-function-key-translation nil
+ god-exempt-major-modes
+ (cl-union '(diff-mode exwm-mode) god-exempt-major-modes :test 'equal)
+ god-mode-lighter-string "THANK-GOD-MODE")
+
+ (defun my-sync-god-mode-lighter-face (&rest _)
+ (set-face-attribute 'god-mode-lighter nil
+ :inherit 'isearch-fail
+ :background (face-attribute 'mode-line :background nil t)
+ :weight 'bold))
+ (my-sync-god-mode-lighter-face)
+ (add-hook 'enable-theme-functions #'my-sync-god-mode-lighter-face)
+
+ (defun my-sync-line-numbers-with-god-mode ()
+ (let ((desired (if (bound-and-true-p god-local-mode)
+ 'relative
+ t)))
+ (unless (or (eq display-line-numbers desired) (bound-and-true-p olivetti-mode))
+ (setq display-line-numbers desired))))
+ (add-hook 'post-command-hook #'my-sync-line-numbers-with-god-mode))
+
+(provide 'init-edit)
+;;; init-edit.el ends here
diff --git a/lisp/init-elpa.el b/lisp/init-elpa.el
@@ -0,0 +1,46 @@
+;;; init-elpa.el --- package manager -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; straight.el
+
+(defvar bootstrap-version)
+(let ((bootstrap-file
+ (expand-file-name
+ "straight/repos/straight.el/bootstrap.el"
+ (or (bound-and-true-p straight-base-dir)
+ user-emacs-directory)))
+ (bootstrap-version 7))
+ (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))
+
+(setq straight-repository-branch t)
+
+;; el-patch
+(use-package el-patch
+ :straight t)
+
+;; install use-package
+(if (< emacs-major-version 29)
+ (straight-use-package 'use-package))
+
+;; configure use-package
+(setq use-package-always-defer (if *is-windows* nil t)
+ use-package-expand-minimally t
+ use-package-verbose t
+ straight-use-package-version t
+ straight-use-package-by-default t)
+
+;; imenu
+(setopt use-package-enable-imenu-support t)
+
+(provide 'init-elpa)
+;;; init-elpa.el ends here
diff --git a/lisp/init-exwm.el b/lisp/init-exwm.el
@@ -0,0 +1,159 @@
+;;; init-exwm.el --- exwm config -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(when *is-linux*
+ (use-package exwm
+ :hook
+ (exwm-init . restart-fcitx5)
+ (exwm-init . my-desktop-init)
+ :config
+ (setq pop-up-windows nil)
+ (setq exwm-workspace-number 1)
+ (exwm-input-set-key (kbd "s-&")
+ (lambda (command)
+ (interactive (list (read-shell-command "$ ")))
+ (let ((display-buffer-alist
+ '((".*" . (display-buffer-no-window . nil)))))
+ (async-shell-command command))))
+
+ (defun my--exwm-switch-to-workspace (delta)
+ (let ((target
+ (mod (+ exwm-workspace-current-index delta)
+ (length exwm-workspace--list))))
+ (exwm-workspace-switch target)))
+
+ (defun my-exwm-next-workspace ()
+ "Switch to next exwm workspace."
+ (interactive)
+ (my--exwm-switch-to-workspace 1)
+ (if (= 1 (length exwm-workspace--list))
+ (message "No next workspace")))
+
+ (defun my-exwm-previous-workspace ()
+ "Switch to previous exwm workspace."
+ (interactive)
+ (my--exwm-switch-to-workspace -1)
+ (if (= 1 (length exwm-workspace--list))
+ (message "No previous workspace")))
+
+ (global-set-key (kbd "s-]") 'my-exwm-next-workspace)
+ (global-set-key (kbd "s-[") 'my-exwm-previous-workspace)
+
+ (add-to-list 'global-mode-string
+ '(:eval (propertize (format " WS:%d " exwm-workspace-current-index)
+ 'face 'mode-line-emphasis))
+ t)
+
+ (setq exwm-input-prefix-keys
+ '(?\C-x
+ ?\C-u
+ ?\C-c
+ ?\C-h
+ ?\M-x
+ ?\M-o
+ ?\M-[
+ ?\M-]
+ ?\s-[
+ ?\s-]
+ ?\s-
+ XF86AudioLowerVolume
+ XF86AudioRaiseVolume
+ XF86AudioMute
+ ))
+ (define-key exwm-mode-map [?\C-q] 'exwm-input-send-next-key)
+
+ (setq exwm-input-global-keys
+ `(([?\s-r] . exwm-reset)
+ ([?\s-b] . windmove-left)
+ ([?\s-f] . windmove-right)
+ ([?\s-p] . windmove-up)
+ ([?\s-n] . windmove-down)
+ ([?\s-S] . desktop-environment-screenshot)
+ ([?\s-s] . desktop-environment-screenshot-part)
+ ([?\s-w] . exwm-workspace-switch)
+ ([?\s-o] . other-window)
+ ([?\s-m] . exwm-layout-toggle-mode-line)
+ ([?\s-`] . (lambda () (interactive) (exwm-workspace-switch-create 0)))
+ ,@(mapcar (lambda (i)
+ `(,(kbd(format "s-%d" i)) .
+ (lambda ()
+ (interactive)
+ (exwm-workspace-switch-create ,i))))
+ (number-sequence 0 9))))
+
+ (setq exwm-input-simulation-keys
+ `((,(kbd "C-f") . [right])
+ (,(kbd "C-b") . [left])
+ (,(kbd "C-p") . [up])
+ (,(kbd "C-n") . [down])
+ (,(kbd "C-a") . [home])
+ (,(kbd "C-e") . [end])
+ (,(kbd "M-f") . [C-right])
+ (,(kbd "A-f") . [C-right])
+ (,(kbd "M-b") . [C-left])
+ (,(kbd "A-b") . [C-left])
+ (,(kbd "C-d") . [delete])
+ (,(kbd "C-k") . [S-end delete])
+ (,(kbd "M-<backspace>") . ,(kbd "C-<backspace>"))
+ (,(kbd "M-d") . ,(kbd "C-<delete>"))
+ (,(kbd "M-w") . [?\C-c])
+ (,(kbd "C-y") . [?\C-v])
+ (,(kbd "C-w") . [?\C-x])
+ (,(kbd "C-/") . [?\C-z])
+ (,(kbd "C-?") . ,(kbd "C-S-z"))))
+
+ (defun my-exwm-update-class ()
+ (exwm-workspace-rename-buffer exwm-class-name))
+ (add-hook 'exwm-update-class-hook #'my-exwm-update-class)
+
+ (require 'exwm-xim)
+ (exwm-xim-mode)
+ (exwm-wm-mode))
+
+ (use-package desktop-environment
+ :after exwm
+ :demand t
+ :init
+ (add-hook 'exwm-wm-mode-hook 'desktop-environment-mode)
+ :config
+ (advice-add 'desktop-environment-screenshot :after
+ (lambda (&rest _) (message "Saved fullscreen screenshot.")))
+ (advice-add 'desktop-environment-screenshot-part :after
+ (lambda (&rest _) (message "Saved partial screenshot.")))
+ :custom
+ (desktop-environment-screenshot-command
+ "import -window root ~/Pictures/screenshot-$(date +%Y%m%d-%H%M%S).png")
+ (desktop-environment-screenshot-partial-command
+ "import ~/Pictures/screenshot-$(date +%Y%m%d-%H%M%S).png"))
+
+ (use-package xdg-launcher
+ :demand t
+ :after exwm
+ :straight
+ (xdg-launcher :type git
+ :host github
+ :repo "emacs-exwm/xdg-launcher")
+ :bind
+ (("s-SPC" . xdg-launcher-run-app))
+ :init
+ (with-eval-after-load 'consult
+ (unless (memq 'xdg-launcher-consult-source consult-buffer-sources)
+ (setq consult-buffer-sources
+ (append consult-buffer-sources '(xdg-launcher-consult-source)))))))
+
+(when *is-mac*
+ ;; launcher
+ (use-package launcher
+ :straight
+ (launcher
+ :type git
+ :host github
+ :repo "xiaoxinghu/launcher.el")
+ :bind
+ ("s-SPC" . launcher)))
+
+(provide 'init-exwm)
+;;; init-exwm.el ends here
diff --git a/lisp/init-gptel.el b/lisp/init-gptel.el
@@ -0,0 +1,186 @@
+;;; init-gptel.el --- ai -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(use-package gptel
+ :config
+ (setq gptel-log-level t
+ gptel-default-mode 'org-mode
+ gptel-include-reasoning "*gptel-reasoning*")
+ (add-hook 'gptel-post-response-functions 'gptel-end-of-response)
+ (add-hook 'gptel-post-stream-hook 'gptel-auto-scroll)
+ (setq gptel-prompt-prefix-alist '((markdown-mode . "## User: ") (org-mode . "** User: ") (text-mode . "## User: ")))
+
+ (gptel-make-tool
+ :name "read_buffer" ; javascript-style snake_case name
+ :function (lambda (buffer) ; the function that will run
+ (unless (buffer-live-p (get-buffer buffer))
+ (error "error: buffer %s is not live." buffer))
+ (with-current-buffer buffer
+ (buffer-substring-no-properties (point-min) (point-max))))
+ :description "return the contents of an emacs buffer"
+ :args (list '(:name "buffer"
+ :type string ; :type value must be a symbol
+ :description "the name of the buffer whose contents are to be retrieved"))
+ :category "emacs") ; An arbitrary label for grouping
+
+ (gptel-make-openai "gptel-Kimi-Code"
+ :host "api.kimi.com"
+ :endpoint "/coding/v1/chat/completions"
+ :protocol "https"
+ :key (lambda ()
+ (auth-source-pick-first-password :host "api.kimi.com" :user "apikey"))
+ :stream t
+ :models '(kimi-k3)
+ :header (lambda (_)
+ (when-let* ((key (gptel--get-api-key)))
+ `(("User-Agent" . "RooCode/3.30.3")
+ ("HTTP-Referer" . "https://github.com/RooVetGit/Roo-Cline")
+ ("X-Title" . "Roo Code")
+ ("Authorization" . ,(concat "Bearer " key))))))
+
+ (setq gptel-model 'kimi-k3
+ gptel-backend (gptel-get-backend "gptel-Kimi-Code"))
+
+ (defun my-gptel--sanitize-filename (name)
+ "Clean NAME into a safe kebab-case filename string."
+ (let ((clean (downcase name)))
+ (setq clean (replace-regexp-in-string "[^a-z0-9_-]" "-" clean))
+ (setq clean (replace-regexp-in-string "^-+\\|[-]+$" "" clean))
+ (setq clean (replace-regexp-in-string "-[-]+" "-" clean))
+ (string-trim clean)))
+
+ (defun my-gptel-save-session ()
+ "Save current gptel session to ~/gptel/sessions/ with AI-generated
+filename.
+The filename is prefixed with a YYYYMMDD-HHmmss timestamp and generated
+from the last 1500 characters of the buffer."
+ (interactive)
+ (unless gptel-mode
+ (user-error "Not a gptel session buffer"))
+ (let* ((buf (current-buffer))
+ (content (with-current-buffer buf
+ (buffer-substring-no-properties (point-min) (point-max))))
+ (tail (substring content (max 0 (- (length content) 1500))))
+ (prompt-text (format "Based on the following conversation, generate a short kebab-case
+filename (3 to 5 lowercase English words, hyphen-separated, no file
+extension). Output ONLY the filename, nothing else.\n\n%s"
+ tail)))
+ (message "Generating filename with AI...")
+ (let ((fsm (gptel-request prompt-text
+ :system "You are a filename generator. Output ONLY a short kebab-case
+filename (3-5 lowercase English words separated by hyphens). No
+explanations, no quotes, no punctuation, no file extension."
+ :stream nil
+ :callback
+ (lambda (response info)
+ (condition-case err
+ (cond
+ ((null response)
+ (message "Failed to generate filename: %s"
+ (or (plist-get info :status) "unknown error")))
+ ((not (stringp response))
+ (message "Unexpected response type: %S" response))
+ (t
+ (let* ((generated (my-gptel--sanitize-filename (string-trim response)))
+ (generated (if (string-empty-p generated)
+ "gptel-session"
+ generated))
+ (timestamp (format-time-string "%Y%m%d-%H%M%S"))
+ (dir (expand-file-name "~/gptel/sessions/"))
+ (base (concat timestamp "-" generated))
+ (file (expand-file-name (concat base ".org") dir)))
+ ;; handle name collision
+ (when (file-exists-p file)
+ (setq base (concat timestamp "-" generated "-" (format-time-string "%S")))
+ (setq file (expand-file-name (concat base ".org") dir)))
+ (unless (file-directory-p dir)
+ (make-directory dir t))
+ ;; write-file triggers gptel--save-state to preserve metadata
+ (with-current-buffer buf
+ (write-file file))
+ (if (file-exists-p file)
+ (progn
+ (pop-to-buffer (find-file-noselect file))
+ (message "Saved gptel session to %s" file))
+ (message "ERROR: File was not created: %s" file)))))
+ (error (message "gptel save-session error: %S" err)))))))
+ (unless (plist-get (gptel-fsm-info fsm) :callback)
+ (message "WARNING: gptel-request did not register callback!")))))
+
+ (with-eval-after-load 'gptel
+ (define-key gptel-mode-map (kbd "C-c C-s") #'my-gptel-save-session)))
+
+(use-package gptel-agent
+ :after gptel
+ :demand t
+ :config
+ (add-to-list 'gptel-agent-dirs "~/.emacs.d/lisp/" t)
+ (gptel-agent-update))
+
+(use-package gptel-magit
+ :straight
+ (gptel-magit :fork (:host github :repo "ArthurHeymans/gptel-magit"))
+ :hook
+ (magit-mode . gptel-magit-install)
+ :init
+ (with-eval-after-load 'gptel
+ (gptel-make-openai "gptel-Kimi-Code-magit"
+ :host "api.kimi.com"
+ :endpoint "/coding/v1/chat/completions"
+ :protocol "https"
+ :key (lambda ()
+ (auth-source-pick-first-password :host "api.kimi.com" :user "apikey"))
+ :stream t
+ :models '((kimi-for-coding))
+ :request-params '(:temperature 0.6 :thinking (:type "disabled"))
+ :header (lambda (_)
+ (when-let* ((key (gptel--get-api-key)))
+ `(("User-Agent" . "RooCode/3.30.3")
+ ("HTTP-Referer" . "https://github.com/RooVetGit/Roo-Cline")
+ ("X-Title" . "Roo Code")
+ ("Authorization" . ,(concat "Bearer " key))))))
+
+ (setq gptel-magit-model 'kimi-for-coding
+ gptel-magit-backend (gptel-get-backend "gptel-Kimi-Code-magit"))))
+
+;; opencode
+(use-package plz
+ :straight
+ (plz :type git
+ :host github
+ :repo "alphapapa/plz.el"
+ :ref "v0.9.1"))
+
+(use-package plz-media-type
+ :straight
+ (plz-media-type :type git
+ :host github
+ :repo "r0man/plz-media-type"
+ :ref "v0.2.4"))
+
+(use-package plz-event-source
+ :straight
+ (plz-event-source :type git
+ :host github
+ :repo "r0man/plz-event-source"
+ :ref "v0.1.3"))
+
+(use-package opencode
+ :straight
+ (opencode :type git
+ :host codeberg
+ :repo "sczi/opencode.el")
+ :hook
+ (opencode-session-control-mode . disable-truncate-lines))
+
+(use-package eval-elisp-mcp
+ :straight
+ (eval-elisp-mcp :type git
+ :host codeberg
+ :repo "sczi/eval-elisp-mcp"))
+
+(provide 'init-gptel)
+;;; init-gptel.el ends here
diff --git a/lisp/init-kbd-func.el b/lisp/init-kbd-func.el
@@ -0,0 +1,339 @@
+;;; init-kbd-func.el --- functions for keybindings -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(defun open-init-file()
+ "Open user's init.el file in ~/.emacs.d ."
+ (interactive)
+ (find-file "~/.emacs.d/init.el"))
+
+(when *is-windows*
+ (defun restart-emacs ()
+ "Restart emacs (for Windows)"
+ (interactive)
+ (save-some-buffers)
+ (w32-shell-execute "open" "runemacs.exe")
+ (kill-emacs)))
+
+(defun disable-truncate-lines ()
+ (toggle-truncate-lines 1))
+
+(defun my-jinx-smart-toggle ()
+ "Toggle jinx-mode smartly.
+Disable jinx-mode if it's enable and global-jinx-mode is disable ,
+otherwise toggle global-jinx-mode."
+ (interactive)
+ (unless (featurep 'jinx)
+ (require 'jinx))
+ (let ((local-on (bound-and-true-p jinx-mode))
+ (global-on (bound-and-true-p global-jinx-mode)))
+ (cond
+ ((and local-on (not global-on))
+ (message "disable jinx-mode in current buffer")
+ (jinx-mode -1))
+ (t
+ (if global-on
+ (progn
+ (message "disable global-jinx-mode")
+ (global-jinx-mode -1))
+ (progn
+ (message "enable global-jinx-mode")
+ (global-jinx-mode 1)))))))
+
+(defun popper-toggle-type-delete-other-window()
+ "Toggle type of popper window and delete other window."
+ (interactive)
+ (popper-toggle-type)
+ (delete-other-windows))
+
+(defun consult-directory-externally (file)
+ "Open FILE externally using the default application of the system."
+ (interactive "fOpen externally: ")
+ (if (and (eq system-type 'windows-nt)
+ (fboundp 'w32-shell-execute))
+ (shell-command-to-string
+ (encode-coding-string
+ (replace-regexp-in-string "/" "\\\\"
+ (format "explorer.exe %s"
+ (file-name-directory
+ (expand-file-name file))))
+ 'gbk))
+ (call-process (pcase system-type
+ ('darwin "open")
+ ('cygwin "cygstart")
+ (_ "xdg-open"))
+ nil 0 nil
+ (file-name-directory (expand-file-name file)))))
+
+(defun my-open-current-directory ()
+ "Open current directory in default file explorer."
+ (interactive)
+ (consult-directory-externally default-directory))
+
+(defun consult-fd-home ()
+ "Search for all files in home folder use fd."
+ (interactive)
+ (let ((consult-fd-args "fd -H -I -i -c never --full-path")
+ (default-directory "~/"))
+ (consult-fd)))
+
+(defun org-cycle-parent-subtree()
+ "Cycle parent org subtree."
+ (interactive)
+ (if (org-at-heading-p)
+ (progn
+ (org-up-heading 1)
+ (org-cycle))
+ (org-back-to-heading)
+ (org-cycle)))
+
+(defun my-denote-journal-path-to-existing-entry (&optional date interval)
+ "Return the path of current denote journal if it exists, otherwise return nil."
+ (require 'denote-journal)
+ (let* ((internal-date
+ (denote-journal--date-in-interval-p (or date (current-time)) interval))
+ (files (denote-journal--get-entry internal-date interval)))
+ (if files
+ (denote-journal-select-file-prompt files))))
+
+(defun my-denote-journal-open-entry ()
+ "Open current denote-journal entry."
+ (interactive)
+ (if (my-denote-journal-path-to-existing-entry)
+ (find-file (my-denote-journal-path-to-existing-entry))
+ (message "No journal for today yet")))
+
+(defun my-denote-open-metanote ()
+ "Open denote metanote in
+`~/org/my-org-note/20260508T220745==metanote--all-my-metanotes__org.org'"
+ (interactive)
+ (find-file
+ (concat org-directory "/20260508T220745==metanote--all-my-metanotes__org.org")))
+
+(defun my-denote-find-file ()
+ "Find file use denote-file-prompt."
+ (interactive)
+ (let ((denote-excluded-files-regexp "=journal\\|=archive"))
+ (find-file (denote-file-prompt))))
+
+(defun my-denote-find-backlink-with-location ()
+ "Like `denote-find-backlink-with-location' but with consult preview."
+ (interactive)
+ (when-let* ((current-file buffer-file-name)
+ (id (or (denote-retrieve-filename-identifier current-file)
+ (user-error "The current file does not have a Denote identifier")))
+ (files (denote-directory-files nil :omit-current :text-only))
+ (fetcher (lambda () (xref-matches-in-files id files))))
+ (consult-xref fetcher nil)))
+
+(defun my-denote-org-find-backlink-for-heading-with-location ()
+ "Like `denote-org-backlinks-for-heading' but with consult preview."
+ (interactive)
+ (unless (featurep 'denote-org)
+ (require 'denote-org))
+ (when-let* ((heading-id (or (denote-org--get-file-id-and-heading-id-or-context)
+ (user-error "The current file does not have a denote identifier")))
+ (files (denote-directory-files nil :omit-current :text-only))
+ (fetcher (lambda () (xref-matches-in-files heading-id files))))
+ (consult-xref fetcher nil)))
+
+(defun my-org-table-align-all ()
+ "Ajust all table in current buffer."
+ (interactive)
+ (save-excursion
+ (goto-char (point-min))
+ (org-table-map-tables 'org-table-align t)))
+
+(defun org-align-description-list ()
+ "Ajust all `::' in active region. "
+ (interactive)
+ (align-regexp (region-beginning) (region-end) "\\(\\s-*\\)::" 1 1 nil))
+
+(defun my-blog-publish (&optional directory)
+ "Publish blog , git add/commit/push , generate commit message."
+ (interactive)
+ (let* ((blog-dir (or directory
+ (if *is-windows*
+ "h:/emacs/hugo/this-is-my-blog/"
+ "~/org/hugo/this-is-my-blog/")))
+ (timestamp (format-time-string "%Y-%m-%d %H:%M:%S"))
+ (default-directory blog-dir))
+ (message "Adding files...")
+ (eshell-command "git add .")
+ (message "Committing: %s" timestamp)
+ (eshell-command (format "git commit -m \"Update: %s\"" timestamp))
+ (message "Pushing to remote...")
+ (let ((exit-code (eshell-command "git push")))
+ (if (eq exit-code t)
+ (message "Push may have failed or nothing to push, check *Messages* buffer for details")
+ (message "Push successfully %s" timestamp)))))
+
+(defun my-blog-preview ()
+ "Save and preview blog."
+ (interactive)
+ (save-buffer)
+ (let ((default-directory (if *is-windows*
+ "h:/emacs/hugo/this-is-my-blog/"
+ "~/org/hugo/this-is-my-blog/")))
+ (start-process "hugo-server" "*hugo-server*"
+ "hugo" "server" "-D" "--bind" "0.0.0.0" "--port" "1313")
+ (sleep-for 2)
+ (browse-url "http://localhost:1313")))
+
+(defun my-note-push ()
+ "Git add/commit/push notes in `~/org/my-org-note/', generate commit message."
+ (interactive)
+ (my-blog-publish "~/org/my-org-note/"))
+
+(defun my-org-tree-slide-start ()
+ "Start `org-tree-slide'."
+ (interactive)
+ (when (eq major-mode 'org-mode)
+ (setq-local header-line-format nil
+ mode-line-format nil
+ cursor-type 'hbar
+ olivetti-body-width 100)
+ (blink-cursor-mode -1)
+ (cnfonts-increase-fontsize 3)
+ (hl-line-mode 'toggle)
+ (read-only-mode 1)
+ (jinx-mode -1)
+ (org-tree-slide-mode 1)))
+
+(defun my-org-tree-slide-stop ()
+ "Stop `org-tree-slide'."
+ (interactive)
+ (when (and (eq major-mode 'org-mode) (memq 'org-tree-slide-mode local-minor-modes))
+ (org-mode-restart)
+ (blink-cursor-mode 1)
+ (cnfonts-decrease-fontsize 3)
+ (hl-line-mode 1)
+ (read-only-mode -1)
+ (jinx-mode 1)
+ (org-tree-slide-mode -1)))
+
+(defun my-dired-next-line()
+ "Move to forward line in dired buffer"
+ (interactive)
+ (forward-line 1)
+ (dired-move-to-filename))
+
+(defun my-dirvish-layout-toggle ()
+ "Toggle layout using first recipe in `dirvish-layout-recipes' instead of
+fallback."
+ (interactive)
+ (let ((dv (dirvish-curr)))
+ (unless dv (user-error "Not a dirvish buffer"))
+ (unless (dv-curr-layout dv)
+ (setf (dv-ff-layout dv) (car dirvish-layout-recipes)))
+ (dirvish-layout-toggle)))
+
+(defun my-magit-toggle-parent-section ()
+ "Toggle parent magit section."
+ (interactive)
+ (magit-section-up)
+ (magit-section-toggle (magit-section-at)))
+
+(defun my-persp-remove-marked-ibuffers ()
+ "Remove marked buffers from perspective."
+ (interactive)
+ (let ((buffers (ibuffer-get-marked-buffers)))
+ (dolist (buf buffers)
+ (persp-remove-buffer buf))))
+
+(defun my-persp-add-marked-ibuffers (persp-name)
+ "Add marked buffers to perspective."
+ (interactive
+ (list (completing-read "Perspective: "
+ (persp-names)
+ nil nil)))
+ (let ((buffers (ibuffer-get-marked-buffers)))
+ (persp-switch persp-name)
+ (dolist (buf buffers)
+ (persp-add-buffer buf))))
+
+(defun my-persp-set-marked-ibuffers (persp-name)
+ "Set marked buffers to perspective."
+ (interactive
+ (list (completing-read "Perspective: "
+ (persp-names)
+ nil nil)))
+ (let ((buffers (ibuffer-get-marked-buffers)))
+ (persp-switch persp-name)
+ (dolist (buf buffers)
+ (persp-set-buffer buf))))
+
+(defun my-gptel-agent-project ()
+ "Run `gptel-agent' in current project's root (by run it with prefix
+argument)."
+ (interactive)
+ (let ((current-prefix-arg '-))
+ (call-interactively 'gptel-agent)))
+
+(defun my-opencode ()
+ "Run `opencode' in project root."
+ (interactive)
+ (let ((default-directory (project-root (project-current t))))
+ (opencode)))
+
+(defun my-consult-grep-project ()
+ "Run `consult-grep' in current project's root."
+ (interactive)
+ (when-let* ((proj (project-current t)))
+ (consult-grep (project-root proj))))
+
+(defun consult-colors-emacs (color)
+ "Show a list of all supported colors for a particular frame.
+
+You can insert the name (default), or insert or kill the hexadecimal or RGB
+value of the selected COLOR."
+ (interactive
+ (list (consult--read (list-colors-duplicates (defined-colors))
+ :prompt "Emacs color: "
+ :require-match t
+ :category 'color
+ :history '(:input consult-colors-history))))
+ (insert color))
+
+(defun fix-theme-colors ()
+ "Fix invalid color name in theme files."
+ (interactive)
+ (load-file (expand-file-name "~/.emacs.d/lisp/fix-theme-colors.el")))
+
+(when *is-linux*
+ (defun reboot ()
+ "Execute loginctl reboot command."
+ (interactive)
+ (eshell-command "loginctl reboot"))
+
+ (defun poweroff ()
+ "Execute loginctl poweroff command"
+ (interactive)
+ (eshell-command "loginctl poweroff"))
+
+ (defun suspend ()
+ "Execute loginctl suspend command"
+ (interactive)
+ (eshell-command "loginctl suspend"))
+
+ (defun my-desktop-init ()
+ "Launch something for linux desktop."
+ (interactive)
+ (unless (zerop (shell-command "pgrep -x mihomo"))
+ (start-process-shell-command "mihomo" nil "mihomo -d ~/.config/mihomo/"))
+ (start-process-shell-command "xrandr-refresh" nil "xrandr --output DP-4 --mode 2560x1440 --rate 165.00")
+ (start-process-shell-command "xinput" nil "xinput set-prop 12 'libinput Accel Speed' -0.45"))
+
+ (defun restart-fcitx5 ()
+ "Kill and restart fcitx5, to fix random issues in exwm."
+ (interactive)
+ (if (zerop (shell-command "pgrep fcitx5"))
+ (progn
+ (eshell-command "pkill fcitx5")
+ (eshell-command "fcitx5 -d"))
+ (eshell-command "fcitx5 -d"))))
+
+(provide 'init-kbd-func)
+;;; init-kbd-func.el ends here
diff --git a/lisp/init-kbd.el b/lisp/init-kbd.el
@@ -0,0 +1,418 @@
+;;; init-kbd.el --- keybindings -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; god-mode
+(general-def god-local-mode-map
+ "i" 'god-mode-all
+ "[" 'backward-paragraph
+ "]" 'forward-paragraph
+ "." 'repeat
+ "y" 'yank
+ "C-c C-<f12>" 'scratch-buffer
+ "z" 'avy-goto-char
+ "'" 'avy-goto-word-1
+ "<f2>" 'open-init-file)
+
+;; g for gptel
+(general-def
+ :prefix "C-c g"
+ "g" 'gptel
+ "m" 'gptel-menu
+ "s" 'gptel-send
+ "a" 'gptel-agent
+ "t" 'gptel-tools
+ "o" 'opencode
+ "p" 'opencode-select-project
+ "l" 'opencode-select-session
+ "n" 'opencode-new-session)
+
+(general-def gptel-mode-map
+ "C-c C-s" 'my-gptel-save-session
+ "C-c C-k" 'gptel-abort)
+
+;; opencode
+(general-def opencode-session-mode-map
+ "C-c C-p" 'comint-previous-prompt
+ "C-c M-p" 'opencode-respond-permission
+ "C-c x" nil
+ "C-c C-k" 'opencode-abort-session
+ "C-c C-c" 'nil
+ "C-c n" 'nil
+ "C-c N" 'opencode-new-session)
+
+(general-def opencode-session-control-mode-map
+ "n" 'next-line
+ "p" 'previous-line
+ "N" 'opencode-new-session)
+
+;; u for ui
+(general-def
+ :prefix "C-c u"
+ "l" 'global-tab-line-mode
+ "d" 'disable-theme
+ "R" 'rainbow-mode
+ "b" 'indent-bars-mode
+ "t" 'consult-theme
+ "c" 'consult-colors-emacs
+ "f" 'describe-face
+ "r" 'rainbow-delimiters-mode
+ "k" 'keycast-header-line-mode
+ "w" 'global-whitespace-mode)
+
+;; f for find and consult command
+(general-def
+ :prefix "C-c f"
+ "r" 'consult-recent-file
+ "f" 'consult-find
+ "g" 'consult-grep
+ "e" 'consult-flycheck
+ "l" 'consult-locate
+ "h" 'consult-fd-home
+ "m" 'consult-man
+ "d" 'my-open-current-directory
+ "j" 'consult-jinx
+ "k" 'consult-kmacro
+ "o" 'consult-outline
+ "i" 'consult-info
+ "s" 'consult-focus-lines)
+
+;; p for project
+(general-def
+ :prefix "C-x p"
+ "b" 'consult-project-buffer
+ "E" 'eat-project
+ "r" 'my-consult-grep-project
+ "R" 'project-query-replace-regexp
+ "v" 'magit-project-status
+ "V" 'project-vc-dir
+ "a" 'my-opencode
+ "i" 'project-ibuffer)
+
+;; v for version control
+(general-def
+ :prefix "C-x v"
+ "=" 'magit-diff-buffer-file
+ "c" 'magit-clone
+ "i" 'magit-init
+ "l" 'magit-log-buffer-file
+ "h" 'magit-log-buffer-file)
+
+;; t for modes toggle
+(general-def
+ :prefix "C-c t"
+ "f" 'flycheck-mode
+ "j" 'my-jinx-smart-toggle
+ "g" 'gptel-mode
+ "h" 'global-diff-hl-mode)
+
+;; o for org-mode
+(general-def
+ :prefix "C-c o"
+ "f" 'my-denote-find-file
+ "g" 'consult-denote-grep
+ "s" 'consult-org-agenda
+ "C" 'calendar
+ "c" 'org-capture
+ "d" 'denote
+ "r" 'denote-rename-file-date
+ "R" 'denote-rename-file
+ "m" 'my-denote-open-metanote
+ "q" 'org-ql-search)
+
+;; j for journal
+(general-def
+ :prefix "C-c j"
+ "o" 'my-denote-journal-open-entry
+ "n" 'denote-journal-new-or-existing-entry)
+
+;; m for media
+(general-def
+ :prefix "C-c m"
+ "n" 'emms-next
+ "p" 'emms-previous
+ "b" 'emms-browser
+ "s" 'emms-start
+ "q" 'emms-stop
+ "P" 'emms-pause
+ "S" 'emms-toggle-single-track
+ "l" 'emms-playlist-mode-switch-buffer
+ "d" 'emms-play-directory)
+
+;; d for dired
+(general-def
+ :prefix "C-c d"
+ "a" 'dirvish-quick-access
+ "s" 'dirvish-side
+ "h" 'dirvish-history-menu
+ "f" 'dirvish-fd
+ "F" 'dirvish-fd-switches-menu
+ "t" 'trashed
+ "d" 'discomfort)
+
+;; x for some other command
+(general-def
+ :prefix "C-c x"
+ "e" 'eshell
+ "E" 'eat
+ "p" 'proced
+ "b" 'benchmark-init/show-durations-tree
+ "B" 'benchmark-init/show-durations-tabulated
+ "s" 'syncthing)
+
+;; scratch buffer
+(if *is-mac*
+ (general-def "C-c <f12>" 'scratch-buffer)
+ (general-def "C-c <delete>" 'scratch-buffer))
+
+;; dired
+(general-def (dired-mode-map dirvish-mode-map)
+ "s" 'dirvish-quicksort
+ "h" 'dirvish-history-menu
+ "M-," 'scroll-other-window-down
+ "M-." 'scroll-other-window
+ "<mouse-2>" 'emms-play-dired
+ "C-c m a" 'emms-add-dired
+ "<down>" 'my-dired-next-line
+ "C-n" 'my-dired-next-line
+ "n" 'my-dired-next-line
+ "b" 'dired-up-directory
+ "C-b" 'backward-char
+ "C-f" 'forward-char
+ "<right>" 'dired-find-file
+ "<left>" 'dired-up-directory
+ "C-/" 'dired-undo
+ "<SPC>" 'my-dirvish-layout-toggle
+ "C-c C-r" 'dired-rsync)
+
+(general-def (dired-mode-map dirvish-mode-map)
+ :prefix "C-c d"
+ "u" 'dirvish-setup-menu
+ "r" 'dirvish-renaming-menu
+ "v" 'dirvish-vc-menu
+ "m" 'dirvish-mark-menu
+ "i" 'dirvish-file-info-menu
+ "y" 'dirvish-yank-menu)
+
+;; magit
+(general-def (magit-mode-map tokei-mode-map)
+ "C-<tab>" 'my-magit-toggle-parent-section)
+
+;; sly
+(general-def (sly-mode-map sly-editing-mode-map)
+ "M-p" 'backward-paragraph
+ "M-n" 'forward-paragraph)
+
+(general-def sly-prefix-map
+ "M-p" 'sly-pprint-eval-last-expression
+ "C-p" 'sly-previous-note
+ "C-n" 'sly-next-note)
+
+;; vterm
+(general-def vterm-mode-map
+ "M-]" nil
+ "C-q" 'vterm-send-next-key)
+
+;; eat
+(general-def (eat-semi-char-mode-map
+ eat-line-mode-map
+ eat-char-mode-map
+ eat-eshell-semi-char-mode-map
+ eat-eshell-char-mode-map)
+ "M-[" nil
+ "M-]" nil)
+
+;; embark
+(general-def embark-file-map
+ "d" 'consult-directory-externally
+ "p" 'emms-play-dired)
+
+(general-def minibuffer-local-map
+ "C-c C-e" 'embark-export)
+
+;; completion
+(general-def completion-list-mode-map
+ "M-n" 'minibuffer-next-completion
+ "M-p" 'minibuffer-previous-completion)
+
+;; markdown
+(general-def markdown-mode-map
+ "M-p" nil
+ "M-n" nil)
+
+;; org-mode
+(general-def org-mode-map
+ "C-<tab>" 'org-cycle-parent-subtree
+ "M-g i" 'consult-outline
+ "M-g M-i" 'consult-outline
+ "C-c t l" 'org-toggle-link-display
+ "M-{" 'backward-paragraph
+ "M-}" 'forward-paragraph
+ "C-," 'crux-duplicate-current-line-or-region
+ "C-c o l" 'denote-link
+ "C-c o L" 'denote-org-link-to-heading
+ "C-c o b" 'my-denote-find-backlink-with-location
+ "C-c o B" 'my-denote-org-find-backlink-for-heading-with-location
+ "C-c o t" 'my-org-tree-slide-start)
+
+;; org-tree-slide-mode
+(general-def org-tree-slide-mode-map
+ "<left>" 'org-tree-slide-move-previous-tree
+ "<right>" 'org-tree-slide-move-next-tree
+ "C-c o t" 'my-org-tree-slide-stop
+ "ESC" 'my-org-tree-slide-stop
+ "q" 'my-org-tree-slide-stop)
+
+;; hs-hide-mode
+(general-def hs-minor-mode-map
+ "C-c h" 'hs-toggle-hiding
+ "C-c H" 'hs-hide-all
+ "C-c S" 'hs-show-all)
+
+;; calendar
+(general-def calendar-mode-map
+ "RET" 'denote-journal-calendar-find-file)
+
+;; ibuffer
+(general-def ibuffer-mode-map
+ "h k" 'my-persp-remove-marked-ibuffers
+ "h A" 'my-persp-set-marked-ibuffers
+ "h a" 'my-persp-add-marked-ibuffers)
+
+;; multiple-cursor
+(general-def mc/keymap
+ "<return>" 'newline)
+
+;; emms
+(general-def emms-playlist-mode-map
+ "<prior>" 'emms-previous
+ "<next>" 'emms-next
+ "C-c C-s" 'emms-history-save)
+
+;; perspective
+(general-def persp-mode-map
+ "C-c p c" nil
+ "C-c p d" 'persp-kill
+ "C-x M-b" 'persp-ibuffer)
+
+;; info
+(general-def Info-mode-map
+ "M-n" 'forward-paragraph)
+
+;; diff
+(general-def diff-mode-map
+ "M-o" 'other-window)
+
+;; discomfort
+(general-def discomfort-mode-map
+ "p" 'previous-line
+ "P" 'discomfort-poweroff)
+
+;; eww
+(general-def eww-mode-map
+ "M-n" 'forward-paragraph
+ "M-p" 'backward-paragraph)
+
+;; global map with C-c prefix
+(general-def
+ :prefix "C-c"
+ "c" 'hydra-multiple-cursors/body
+ "r" 'restart-emacs
+ "e" 'er/expand-region
+ "s" 'consult-line
+ "a" 'org-agenda
+ "l" 'org-store-link
+ "k" 'comment-line
+ "K" 'comment-kill)
+
+;; global map
+(general-def
+
+ ;; god-mode
+ "M-i" 'god-mode-all
+
+ ;; buffer, file, and window
+ "<f2>" 'open-init-file
+ "<mouse-4>" 'previous-buffer
+ "<mouse-5>" 'next-buffer
+ "M-[" 'previous-buffer
+ "M-]" 'next-buffer
+ "C-x C-b" 'ibuffer-other-window
+ "C-x K" 'crux-kill-other-buffers
+ "C-x b" 'consult-buffer
+ "C-x C-1" 'delete-other-windows
+ "C-x C-2" 'split-window-below
+ "C-x C-3" 'split-window-right
+ "C-x C-0" 'delete-window
+
+ ;; edit
+ "M-c" 'capitalize-dwim
+ "M-u" 'upcase-dwim
+ "M-l" 'downcase-dwim
+ "C-," 'crux-duplicate-current-line-or-region
+ "C-<backspace>" 'crux-kill-line-backwards
+ "M-y" 'consult-yank-from-kill-ring
+ "C-c <backspace>" 'hungry-delete-backward
+ "C-c C-<backspace>" 'hungry-delete-forward
+ "M-P" 'drag-stuff-up
+ "M-N" 'drag-stuff-down
+ "M-F" 'drag-stuff-right
+ "M-B" 'drag-stuff-left
+ "C-M-SPC" 'er/mark-symbol
+ "M-@" 'er/mark-word
+ "C-S-<mouse-1>" 'mc/add-cursor-on-click
+
+ ;; undo
+ "C-/" 'undo-fu-only-undo
+ "C-?" 'undo-fu-only-redo
+ "C-x u" 'vundo
+
+ ;; navigate
+ "M-p" 'backward-paragraph
+ "M-n" 'forward-paragraph
+ "<mouse-2>" 'xref-find-definitions-at-mouse
+ "C-M-;" 'avy-goto-char
+ "C-M-'" 'avy-goto-word-1
+ "M-g g" 'avy-goto-line
+ "M-g M-g" 'consult-goto-line
+ "M-g i" 'consult-imenu
+ "M-g I" 'consult-imenu-multi
+ "M-g M-i" 'consult-imenu
+
+ ;; window
+ "C-M-<left>" 'shrink-window-horizontally
+ "C-M-<right>" 'enlarge-window-horizontally
+ "C-M-<down>" 'shrink-window
+ "C-M-<up>" 'enlarge-window
+ "M-`" 'popper-toggle
+ "C-M-=" 'popper-toggle-type-delete-other-window
+ "M-o" 'other-window
+ "<f10>" 'esw/swap-two-windows
+
+ ;; other
+ "C-x r b" 'consult-bookmark
+ "C-;" 'embark-act)
+
+(cond
+ (*is-android*
+ (general-def
+ "C-M-w" 'popper-toggle-type-delete-other-window))
+ (*is-linux*
+ (general-def
+ "M-S-SPC" 'xdg-launcher-run-app))
+ (t nil))
+
+;; expand region
+(setq expand-region-reset-fast-key "r")
+(setq expand-region-contract-fast-key "c")
+
+;; diff changes when saving buffers
+(add-to-list 'save-some-buffers-action-alist
+ (list "d"
+ (lambda (buffer) (diff-buffer-with-file (buffer-file-name buffer)))
+ "show diff between the buffer and its file"))
+
+(provide 'init-kbd)
+;;; init-kbd.el ends here
diff --git a/lisp/init-org.el b/lisp/init-org.el
@@ -0,0 +1,284 @@
+;;; init-org.el --- org-mode config -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(use-package org
+ :hook
+ (org-mode . org-indent-mode)
+ (org-mode . visual-line-mode)
+ (org-mode . my-org-electric-pair-fix)
+ (org-mode . electric-pair-local-mode)
+
+ :init
+ (setq org-directory
+ (cond
+ (*is-windows* "h:/emacs/my-org-note")
+ (*is-mac* "~/org/my-org-note")
+ (*is-linux* "~/org/my-org-note")
+ (*is-android* "~/storage/shared/my-org-note")))
+
+ :config
+ (defvar org-hide-space-keywords
+ '(("\\cc\\( \\)[*/_=~+]\\cc.*?[*/_=~+]"
+ (0 (prog1 () (add-text-properties (match-beginning 1) (match-end 1) '(invisible t)))))
+ ("[*/_=~+].*?\\cc[*/_=~+]\\( \\)\\cc"
+ (0 (prog1 () (add-text-properties (match-beginning 1) (match-end 1) '(invisible t)))))))
+ (font-lock-add-keywords 'org-mode org-hide-space-keywords 'append)
+
+ (add-to-list 'org-src-lang-modes '("yaml" . yaml-ts))
+ (add-to-list 'org-src-lang-modes '("json" . json-ts))
+ (add-to-list 'org-src-lang-modes '("toml" . toml-ts))
+
+ (if *is-windows*
+ (add-hook 'org-mode-hook 'font-lock-update))
+
+ (unless *is-windows*
+ (add-hook 'org-mode 'jinx-mode))
+
+ (defun my-org-electric-pair-fix ()
+ (setq-local electric-pair-inhibit-predicate
+ (lambda (char)
+ (or (eq char ?<)
+ (electric-pair-default-inhibit char)))))
+
+ ;; log in drawer
+ (setq org-log-done t
+ org-log-into-drawer t)
+
+ ;; dont set bookmark
+ (setq org-bookmark-names-plist nil)
+
+ ;; todo keywords
+ (setq org-todo-keywords
+ (quote ((sequence "TODO(t)" "SOMEDAY(S)" "STARTED(s)" "WAITING(w)" "|" "DONE(d!/!)" "CANCELLED(c@/!)")
+ (sequence "IDKY(i)" "|" "KNOWN(k)" "CANCELLED(c@/!)"))))
+
+ ;; agenda
+ (setq org-agenda-files `(,(concat org-directory "/20260509T232442==agenda--all-my-todos__org.org")))
+
+ (setq org-agenda-span 'day)
+ (setq org-agenda-skip-function-global
+ '(org-agenda-skip-entry-if 'todo '("COMMENT"))))
+
+;; optimize line wrapping in tables
+(use-package phscroll
+ :hook
+ (org-mode . org-phscroll-activate)
+ :init
+ (setq org-startup-truncated nil))
+
+;; org-babel scheme
+(use-package ob-scheme
+ :demand t
+ :after org
+ :straight nil
+ :config
+ (add-to-list 'org-babel-load-languages '(scheme . t))
+ (org-babel-do-load-languages
+ 'org-babel-load-languages
+ org-babel-load-languages))
+
+;; denote
+(use-package denote
+ :hook
+ (after-init . denote-rename-buffer-mode)
+ (dired-mode . denote-dired-mode)
+ :init
+ (setq denote-directory org-directory)
+ (setq denote-org-store-link-to-heading 'context
+ denote-prompts '(title signature keywords))
+ (setq denote-title-history nil
+ denote-signature-history
+ '("note" "project" "fun" "wisdom" "article" "data" "metanote" "agenda" "journal" "archive")
+ denote-known-keywords
+ '("emacs")
+ denote-title-history nil))
+
+;; denote-org
+(use-package denote-org)
+
+;; denote-lint
+(use-package denote-lint
+ :straight
+ (denote-lint :type git
+ :host github
+ :repo "Andsy10/denote-lint"
+ :protocol ssh)
+ :config
+ (setq org-link-elisp-confirm-function nil))
+
+;; denote-journal
+(use-package denote-journal
+ :hook
+ (calendar-mode . denote-journal-calendar-mode)
+ :config
+ (setq denote-journal-directory (expand-file-name "journal" denote-directory))
+ (setq denote-journal-keyword nil)
+ (setq denote-journal-signature "journal")
+ (setq denote-journal-keyword "daily"))
+
+;; denote-explore
+(use-package denote-explore)
+
+;; consult-denote
+(use-package consult-denote
+ :hook
+ (after-init . consult-denote-mode))
+
+;; org-download
+(use-package org-download
+ :after org
+ :demand t
+ :hook
+ (org-mode . org-link-preview-region)
+ :config
+ (setq-default org-download-image-dir "./images/"
+ org-download-heading-lvl nil)
+ (setq org-download-dragndrop t
+ org-download-method 'directory
+ org-image-actual-width nil
+ org-download-image-html-width 600
+ org-return-follows-link t))
+
+;; org-ql
+(use-package org-ql)
+
+;; org-super-agenda 配置
+(use-package org-super-agenda
+ :config
+ (org-super-agenda-mode))
+
+;; agenda
+(use-package org-agenda
+ :straight nil
+ :hook
+ (org-agenda-finalize . disable-truncate-lines)
+ :config
+ (setq org-agenda-prefix-format '((agenda . " %?-12t% s")
+ (todo . " ")
+ (tags . " ")
+ (search . " ")))
+
+ (setq org-agenda-sorting-strategy
+ '((agenda time-up scheduled-up deadline-up priority-down category-keep)
+ (todo priority-down category-keep)
+ (tags priority-down category-keep)
+ (search category-keep)))
+
+ (setq org-agenda-custom-commands
+ '(("qd" "TODO entries sort by closed time"
+ ((org-ql-block '(closed)
+ ((org-ql-block-header "Closed TODOs")
+ (org-super-agenda-groups
+ '((:auto-ts t)))))))
+ ("qS" "SOMEDAYs"
+ ((org-ql-block '(todo "SOMEDAY")
+ ((org-ql-block-header "SOMEDAYs")
+ (org-super-agenda-groups
+ '((:auto-ts t)))))))
+ ("qs" "STARTEDs"
+ ((org-ql-block '(todo "STARTED")
+ ((org-ql-block-header "STARTEDs")
+ (org-super-agenda-groups
+ '((:auto-ts t)))))))
+ ("qt" "TODOs sort by start time"
+ ((org-ql-block '(todo)
+ ((org-ql-block-header "TODOs")
+ (org-super-agenda-groups
+ '((:auto-ts t)))))))
+ ("qa" "all TODO entries"
+ ((org-ql-block '(and (not (done)) (todo))
+ ((org-ql-block-header "all TODOs")
+ (org-super-agenda-groups
+ '((:name "started" :todo "STARTED")
+ (:name "waiting" :todo "WAITING")
+ (:name "priority = A" :priority "A")
+ (:name "priority = B" :priority "B")
+ (:name "priority = C" :priority "C")
+ (:name "other priority" :priority< "C")
+ (:name "someday" :todo "SOMEDAY")
+ (:name "I dont know yet" :todo "IDKY"))))))))))
+
+;; capture
+(use-package org-capture
+ :straight nil
+ :config
+ (setq my-org-capture-file (concat org-directory "/20260509T232442==agenda--all-my-todos__org.org"))
+ (setq org-capture-templates
+ `(("t" "TODO" entry
+ (file+headline ,my-org-capture-file "Something to do")
+ "* TODO %<%m-%d> %?\n%T" :empty-lines 1)
+ ("s" "STARTED" entry
+ (file+headline ,my-org-capture-file "Something to do")
+ "* STARTED %<%m-%d> %?\n%T" :empty-lines 1)
+ ("S" "SOMEDAY" entry
+ (file+headline ,my-org-capture-file "Something to do")
+ "* SOMEDAY %<%m-%d> %?\n%T" :empty-lines 1)
+ ("i" "IDKY" entry
+ (file+headline ,my-org-capture-file "Something to know")
+ "* IDKY %<%m-%d> %?\n%T" :empty-lines 1))))
+
+;; hugo
+(use-package ox-hugo
+ :init
+ (with-eval-after-load 'org-capture
+ (defun org-hugo-new-subtree-post-capture-template ()
+ "Returns `org-capture' template string for new Hugo post.
+See `org-capture-templates' for more information."
+ (let* ((title (read-from-minibuffer "Post Title: ")) ;Prompt to enter the post title
+ (fname (org-hugo-slug title)))
+ (mapconcat #'identity
+ `(
+ ,(concat "* TODO " title)
+ ":PROPERTIES:"
+ ,(concat ":EXPORT_FILE_NAME: " fname)
+ ":END:"
+ "\n\n") ;Place the cursor here finally
+ "\n")))
+ (add-to-list 'org-capture-templates
+ `("h" ;`org-capture' binding + h
+ "Hugo post"
+ entry
+ ;; It is assumed that below file is present in `org-directory'
+ ;; and that it has a "Blog Ideas" heading. It can even be a
+ ;; symlink pointing to the actual location of all-posts.org!
+ (file+headline ,(if *is-windows*
+ "h:/emacs/hugo/this-is-my-blog/all-blog.org"
+ "~/org/hugo/this-is-my-blog/all-blog.org")
+ "Blog Ideas")
+ (function org-hugo-new-subtree-post-capture-template)))))
+
+;; presentation
+(use-package org-tree-slide)
+
+;; Chinese calendar
+(use-package cal-china-x
+ :after calendar
+ :autoload cal-china-x-setup
+ :init
+ (cal-china-x-setup)
+ :config
+ (setq calendar-mark-holidays-flag t
+ cal-china-x-important-holidays cal-china-x-chinese-holidays
+ cal-china-x-general-holidays '((holiday-lunar 1 15 "元宵节")
+ (holiday-lunar 7 7 "七夕节")
+ (holiday-fixed 3 8 "妇女节")
+ (holiday-fixed 3 12 "植树节")
+ (holiday-fixed 5 4 "青年节")
+ (holiday-fixed 6 1 "儿童节")
+ (holiday-fixed 9 10 "教师节"))
+ holiday-other-holidays '((holiday-fixed 2 14 "情人节")
+ (holiday-fixed 4 1 "愚人节")
+ (holiday-fixed 12 25 "圣诞节")
+ (holiday-fixed 6 7 "高考")
+ (holiday-float 5 0 2 "母亲节")
+ (holiday-float 6 0 3 "父亲节")
+ (holiday-float 11 4 4 "感恩节"))
+ calendar-holidays (append cal-china-x-important-holidays
+ cal-china-x-general-holidays
+ holiday-other-holidays)))
+
+(provide 'init-org)
+;;; init-org.el ends here
diff --git a/lisp/init-package.el b/lisp/init-package.el
@@ -0,0 +1,228 @@
+;;; init-package.el --- some other packages -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; keycast
+(if use-package-always-defer
+ (use-package keycast))
+
+;; display match count for isearch
+(use-package anzu
+ :delight
+ :hook
+ (after-init . global-anzu-mode))
+
+;; writable grep
+(use-package wgrep)
+
+;; ripgrep
+(use-package rg)
+
+;; hydra
+(use-package hydra
+ :config
+ ;; multiple-cursors hydra
+ (defhydra hydra-multiple-cursors ()
+ "
+ ^Mark^ ^Unmark^ ^Other^
+------------------------------------------------------------------
+_p_ : prev line _P_ : previous _c_ : edit lines
+_n_ : next line _N_ : next _._ : pop
+_b_ : prev word _q_ : quit
+_f_ : next word _i_ : insert numbers
+_B_ : prev symbol
+_F_ : next symbol
+_s_ : in region
+_a_ : all dwim
+"
+ ("p" mc/mark-previous-like-this)
+ ("n" mc/mark-next-like-this)
+ ("b" mc/mark-previous-like-this-word)
+ ("f" mc/mark-next-like-this-word)
+ ("B" mc/mark-previous-like-this-symbol)
+ ("F" mc/mark-next-like-this-symbol)
+ ("P" mc/unmark-previous-like-this)
+ ("N" mc/unmark-next-like-this)
+ ("a" mc/mark-all-dwim)
+ ("s" mc/mark-all-in-region)
+ ("c" mc/edit-lines)
+ ("i" mc/insert-numbers)
+ ("." mc/mark-pop)
+ ("q" nil)))
+
+;; spell checker
+(unless *is-windows*
+ (use-package jinx
+ :delight
+ (jinx-mode " Jinx" jinx)
+ :bind
+ ([remap ispell-word] . jinx-correct)
+ :config
+ (setq jinx-languages "en_US")
+ (add-to-list 'jinx-exclude-regexps '(t "\\cc"))
+ (with-eval-after-load 'jinx
+ (dolist (range '((#x4E00 . #x9FFF)
+ (#x3400 . #x4DBF)
+ (#x3000 . #x303F)
+ (#xFF00 . #xFFEF)
+ (#x20000 . #x2A6DF)))
+ (let ((start (car range))
+ (end (cdr range)))
+ (dotimes (i (- end start))
+ (modify-syntax-entry (+ start i) "_" jinx--syntax-table))))))
+
+ (use-package consult-jinx
+ :straight
+ (consult-jinx
+ :type git
+ :host github
+ :repo "Andsy10/consult-jinx"
+ :protocol ssh)))
+
+;; terminal emulator
+(unless *is-windows*
+ (use-package eat
+ :straight
+ (eat :type git
+ :host codeberg
+ :repo "akib/emacs-eat"
+ :files ("*.el"
+ ("term" "term/*.el")
+ "*.texi"
+ "*.ti"
+ ("terminfo/e" "terminfo/e/*")
+ ("terminfo/65" "terminfo/65/*")
+ ("integration" "integration/*")
+ (:exclude ".dir-locals.el" "*-tests.el")))
+ :hook
+ (eshell-load . eat-eshell-mode)
+ (eshell-load . eat-eshell-visual-command-mode)
+ (eat-mode . toggle-truncate-lines)
+ :config
+ (setq eat-term-terminfo-directory eat--terminfo-path)))
+
+;; wordspace
+(use-package perspective
+ :bind
+ ("C-x M-b" . persp-list-buffers)
+ :custom
+ (persp-mode-prefix-key (kbd "C-c p"))
+ :hook
+ (after-init . persp-mode)
+ :config
+ (setq persp-switch-to-buffer-behavior 'switch)
+ (with-eval-after-load 'consult
+ (consult-customize consult-source-buffer :hidden t :default nil)
+ (add-to-list 'consult-buffer-sources persp-consult-source))
+ (setq switch-to-prev-buffer-skip
+ (lambda (win buff bury-or-kill)
+ (or (not (persp-is-current-buffer buff))
+ (cl-some (lambda (re) (string-match-p re (buffer-name buff)))
+ consult-buffer-filter))))
+ (setq persp-initial-frame-name "main"))
+
+;; magit
+(use-package magit
+ :config
+ (setq magit-bind-magit-project-status nil)
+ (unless *is-windows*
+ (setq magit-diff-refine-hunk 'all)))
+
+;; git-timemachine
+(use-package git-timemachine)
+
+;; ediff
+(use-package ediff
+ :config
+ (setq ediff-window-setup-function 'ediff-setup-windows-plain
+ ediff-split-window-function 'split-window-horizontally))
+
+;; diff-hl
+(use-package diff-hl
+ :hook
+ (diff-hl-mode . diff-hl-margin-mode)
+ (diff-hl-mode . global-diff-hl-show-hunk-mouse-mode)
+ (diff-hl-mode . diff-hl-flydiff-mode))
+
+;; project
+(use-package project
+ :config
+ (setq project-switch-commands (assq-delete-all 'project-vc-dir project-switch-commands))
+ (setq project-switch-commands
+ (seq-uniq (append project-switch-commands
+ '((magit-project-status "Magit" ?v)
+ (eat-project "Eat" ?E)
+ (project-query-replace-regexp "Query Replace" ?R)
+ (consult-grep "Grep" ?r)
+ (consult-project-buffer "Buffers" ?b)
+ (project-ibuffer "Ibuffer" ?i)
+ (opencode "OpenCode" ?a))))))
+
+(use-package project-ibuffer
+ :straight
+ (project-ibuffer :type git
+ :host github
+ :repo "Andsy10/project-ibuffer"
+ :protocol ssh))
+
+;; emms
+(use-package emms
+ :commands
+ (emms-playlist-mode-switch-buffer)
+ :config
+ (emms-all)
+ (setq emms-player-list '(emms-player-vlc)
+ emms-info-functions '(emms-info-native))
+ (emms-history-load))
+
+;; tokei
+(use-package tokei)
+
+;; helpful
+(use-package helpful
+ :bind
+ (([remap describe-function] . helpful-callable)
+ ([remap describe-command] . helpful-command)
+ ([remap describe-variable] . helpful-variable)
+ ([remap describe-key] . helpful-key)
+ ([remap describe-symbol] . helpful-symbol)
+ :map emacs-lisp-mode-map
+ ("C-c C-d C-d" . helpful-at-point)
+ :map lisp-interaction-mode-map
+ ("C-c C-d C-d" . helpful-at-point)
+ :map helpful-mode-map
+ ("C-x K" . helpful-kill-buffers)
+ ("r" . remove-hook-at-point)))
+
+;; typing game
+(use-package typit)
+
+;; guix
+(if *is-linux*
+ (use-package guix))
+
+;; process manager
+(use-package proced
+ :straight nil
+ :custom
+ (proced-auto-update-flag t)
+ (proced-goal-attribute nil)
+ (proced-show-remote-processes t)
+ (proced-enable-color-flag t)
+ (proced-format 'custom)
+ :config
+ (add-to-list
+ 'proced-format-alist
+ '(custom user pid ppid sess tree pcpu pmem rss start time state (args comm)))
+ (setq proced-low-memory-usage-threshold 0.025
+ proced-medium-memory-usage-threshold 0.125))
+
+;; syncthing
+(use-package syncthing
+ :hook
+ (syncthing-mode . disable-truncate-lines))
+
+(provide 'init-package)
+;;; init-package.el ends here
diff --git a/lisp/init-prog.el b/lisp/init-prog.el
@@ -0,0 +1,88 @@
+;;; init-prog.el --- programming -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; hideshow
+(use-package hideshow
+ :hook
+ (prog-mode . hs-minor-mode))
+
+;; xref
+(use-package xref
+ :autoload xref-show-definitions-completing-read
+ :init
+ (when (executable-find "rg")
+ (setq xref-search-program 'ripgrep))
+
+ (setq xref-show-definitions-function #'xref-show-definitions-completing-read
+ xref-show-xrefs-function #'xref-show-definitions-completing-read))
+
+;; syntax checking
+(use-package flycheck)
+
+(use-package flycheck-guile
+ :hook
+ (scheme-mode . (lambda ()
+ (require 'flycheck-guile))))
+
+(use-package consult-flycheck)
+
+;; tree-sitter
+(use-package treesit-auto
+ :hook
+ (after-init . global-treesit-auto-mode)
+ :config
+ (setq treesit-auto-install 'prompt)
+ (setq treesit-font-lock-level 4))
+
+;; scheme
+(use-package geiser
+ :config
+ (with-eval-after-load 'geiser
+ (setq geiser-default-implementation 'guile)))
+
+(use-package geiser-guile)
+
+;; common-lisp
+(use-package sly
+ :config
+ (setq sly-lisp-implementations nil))
+
+(use-package lisp-extra-font-lock
+ :hook
+ (lisp-mode . lisp-extra-font-lock-mode))
+
+;; markdown
+(use-package markdown-mode
+ :bind
+ (:map markdown-mode-map
+ ("C-c C-e" . markdown-do))
+ :hook
+ (markdown-mode . visual-line-mode)
+ :init
+ (setq markdown-command "multimarkdown"
+ markdown-fontify-code-blocks-natively t))
+
+(use-package edit-indirect)
+
+;; html
+(use-package shr
+ :config
+ (setq shr-inhibit-images nil
+ shr-use-fonts nil))
+
+(use-package htmlize)
+
+;; caddy
+(use-package caddyfile-mode
+ :mode
+ (("Caddyfile\\'" . caddyfile-mode)
+ ("caddy\\.conf\\'" . caddyfile-mode)))
+
+;; some modes
+(add-to-list 'auto-mode-alist '("\\.service\\'" . conf-unix-mode))
+
+(provide 'init-prog)
+;;; init-prog.el ends here
diff --git a/lisp/init-segmentation.el b/lisp/init-segmentation.el
@@ -0,0 +1,43 @@
+;;; init-segmentation.el --- Chinese word segmentation -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; emacs-chinese-word-segmentation
+(use-package cns
+ :straight nil
+ :hook
+ (after-init . require-cns)
+ (after-init . global-cns-mode)
+ :init
+ (cond
+ (*is-windows*
+ (add-to-list 'load-path "h:/emacs/emacs-chinese-word-segmentation/")
+ (setq cns-process-type 'shell)
+ (setq cns-prog "h:/emacs/emacs-chinese-word-segmentation/cnws.exe")
+ (setq cns-dict-directory "h:/emacs/emacs-chinese-word-segmentation/cppjieba/dict")
+ (setq cns-process-shell-command
+ (format "%s %s %s %s %s %s"
+ cns-prog
+ (concat (file-name-as-directory cns-dict-directory) "jieba.dict.utf8")
+ (concat (file-name-as-directory cns-dict-directory) "hmm_model.utf8")
+ (concat (file-name-as-directory cns-dict-directory) "user.dict.utf8")
+ (concat (file-name-as-directory cns-dict-directory) "idf.utf8")
+ (concat (file-name-as-directory cns-dict-directory) "stop_words.utf8"))))
+
+ (t
+ (add-to-list 'load-path "~/emacs-stuff/emacs-chinese-word-segmentation/")
+ (setq cns-process-type 'shell)
+ (setq cns-prog "~/emacs-stuff/emacs-chinese-word-segmentation/cnws")
+ (setq cns-dict-directory "~/emacs-stuff/emacs-chinese-word-segmentation/cppjieba/dict/")))
+
+ :config
+ (defun require-cns ()
+ (require 'cns nil t))
+
+ (setq cns-recent-segmentation-limit 40)
+ (define-key cns-mode-map (kbd "C-<backspace>") nil))
+
+(provide 'init-segmentation)
+;;; init-segmentation.el ends here
diff --git a/lisp/init-startup.el b/lisp/init-startup.el
@@ -0,0 +1,103 @@
+;;; init-startup.el --- startup settings -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; coding system
+(set-selection-coding-system 'utf-8)
+(when (fboundp 'set-charset-priority)
+ (set-charset-priority 'unicode))
+(set-default-coding-systems 'utf-8)
+(set-buffer-file-coding-system 'utf-8)
+(set-clipboard-coding-system 'utf-8)
+(set-file-name-coding-system 'utf-8)
+(set-keyboard-coding-system 'utf-8)
+(set-next-selection-coding-system 'utf-8)
+(set-selection-coding-system 'utf-8)
+(set-terminal-coding-system 'utf-8)
+(setq locale-coding-system 'utf-8)
+(setq system-time-locale "C")
+
+;; fullscreen
+(cond
+ (*is-mac*
+ (set-frame-parameter nil 'fullscreen 'fullscreen)
+ (toggle-frame-fullscreen)
+ (global-unset-key (kbd "<f12>"))
+ (global-set-key (kbd "<f12>") 'toggle-frame-fullscreen))
+ (*is-windows*
+ (toggle-frame-maximized))
+ (t nil))
+
+;; backup and autosave
+(setq backup-directory-alist
+ `((".*" . ,(expand-file-name "backup/" user-emacs-directory)))
+ backup-by-copying t
+ delete-old-versions t
+ kept-new-versions 6
+ kept-old-versions 2
+ version-control t)
+(setq auto-save-file-name-transforms
+ `((".*" ,(expand-file-name "auto-save-list/" user-emacs-directory) t)))
+
+;; horizontal scroll
+(put 'scroll-left 'disabled nil)
+
+;; disable lockfiles
+(setq create-lockfiles nil)
+
+;; disable ring bell
+(setq ring-bell-function 'ignore)
+
+;; package manager load path
+(cond
+ (*is-windows*
+ (add-to-list 'exec-path (expand-file-name "H/appppppppppp/scoop/apps/"))
+ (setenv "PATH" (concat (expand-file-name "H/appppppppppp/scoop/apps/") ";" (getenv "PATH"))))
+ (*is-mac*
+ (add-to-list 'exec-path (expand-file-name "/opt/homebrew/bin/"))
+ (setenv "PATH" (concat (expand-file-name "/opt/homebrew/bin/") ":" (getenv "PATH"))))
+ (*is-linux*
+ (add-to-list 'exec-path (expand-file-name "~/.guix-home/profile/bin/"))
+ (setenv "PATH" (concat (expand-file-name "~/.guix-home/profile/bin/") ":" (getenv "PATH")))))
+
+;; scratch buffer
+(setq initial-scratch-message
+ "")
+
+(defun my-scratch-set-mode (&rest _)
+ (when (eq major-mode 'fundamental-mode)
+ (funcall initial-major-mode)))
+
+(advice-add 'scratch-buffer :after #'my-scratch-set-mode)
+
+;; frame title
+(setq-default frame-title-format '("%b - Emacs"))
+
+;; native compile warning
+(setq native-comp-async-warnings-errors-kind 'silent)
+
+;; short answer
+(if (boundp 'use-short-answers)
+ (setq use-short-answers t)
+ (fset 'yes-or-no-p 'y-or-n-p))
+
+;; trash
+(setq delete-by-moving-to-trash t)
+
+;; optimize word wrapping
+(setq word-wrap-by-category t)
+
+;; don't insert tabs
+(setq-default indent-tabs-mode nil)
+
+;; modifier keys on mac
+(when *is-mac*
+ (setq mac-command-modifier 'meta)
+ (setq mac-option-modifier 'super)
+ (setq mac-pass-control-to-system nil)
+ (setq mac-pass-command-to-system nil))
+
+(provide 'init-startup)
+;;; init-startup.el ends here
diff --git a/lisp/init-terminal-kbd.el b/lisp/init-terminal-kbd.el
@@ -0,0 +1,82 @@
+;;; init-terminal-kbd.el --- keybindings -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; general
+(use-package general)
+
+(defun open-init-file()
+ "Open user's init.el file in ~/.emacs.d ."
+ (interactive)
+ (find-file "~/.emacs.d/init.el"))
+
+;; scratch buffer
+(if *is-mac*
+ (general-def "C-c <f12>" 'scratch-buffer)
+ (general-def "C-c <delete>" 'scratch-buffer)
+ (general-def "C-c <deletechar>" 'scratch-buffer))
+
+;; diff
+(general-def diff-mode-map
+ "M-o" 'other-window)
+
+;; dired
+(general-def dired-mode-map
+ "b" 'dired-up-directory)
+
+;; global map with C-c prefix
+(general-def
+ :prefix "C-c"
+ "e" 'er/expand-region
+ "k" 'comment-line
+ "f r" 'recentf
+ "i" 'imenu)
+
+;; global map
+(general-def
+
+ ;; buffer, file, and window
+ "<f2>" 'open-init-file
+ "C-x C-b" 'ibuffer-other-window
+ "C-x K" 'crux-kill-other-buffers
+
+ ;; edit
+ "M-c" 'capitalize-dwim
+ "M-u" 'upcase-dwim
+ "M-l" 'downcase-dwim
+ "C-," 'crux-duplicate-current-line-or-region
+ "C-k" 'crux-smart-kill-line
+ "C-<backspace>" 'crux-kill-line-backwards
+ "M-y" 'yank-from-kill-ring
+ "C-c DEL" 'hungry-delete-backward
+ "C-c C-DEL" 'hungry-delete-forward
+ "M-P" 'drag-stuff-up
+ "M-N" 'drag-stuff-down
+ "C-M-@" 'er/mark-symbol
+ "M-@" 'er/mark-word
+ "C-M-h" 'backward-kill-sexp
+
+ ;; undo
+ "C-/" 'undo
+ "C-M-_" 'undo-redo
+
+ ;; navigate
+ "M-p" 'backward-paragraph
+ "M-n" 'forward-paragraph
+
+ ;; window
+ "M-<left>" 'shrink-window-horizontally
+ "M-<right>" 'enlarge-window-horizontally
+ "M-<down>" 'shrink-window
+ "M-<up>" 'enlarge-window
+ "M-o" 'other-window)
+
+(add-to-list 'save-some-buffers-action-alist
+ (list "d"
+ (lambda (buffer) (diff-buffer-with-file (buffer-file-name buffer)))
+ "show diff between the buffer and its file"))
+
+(provide 'init-terminal-kbd)
+;;; init-terminal-kbd.el ends here
diff --git a/lisp/init-terminal-package.el b/lisp/init-terminal-package.el
@@ -0,0 +1,93 @@
+;;; init-terminal-package.el --- major packages -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(use-package gcmh
+ :delight
+ :hook
+ (emacs-startup . gcmh-mode)
+ :init
+ (setq gcmh-idle-delay 'auto
+ gcmh-auto-idle-delay-factor 10
+ gcmh-high-cons-threshold #x4000000))
+
+(use-package benchmark-init
+ :init
+ (benchmark-init/activate)
+ :hook
+ (after-init . benchmark-init/deactivate))
+
+(use-package recentf
+ :hook
+ (after-init . recentf-mode)
+ :init
+ (setq recentf-max-saved-items 30)
+ :config
+ (if *is-android*
+ (add-to-list 'recentf-exclude "~/storage/shared/my-org-note/journal/.*\\.org\\'")
+ (add-to-list 'recentf-exclude "~/org/my-org-note/journal/.*\\.org\\'")
+ (add-to-list 'recentf-exclude "~/org/my-org-note/20260509T232442==agenda--all-my-todos__org\\.org")))
+
+(use-package savehist
+ :hook
+ (after-init . savehist-mode)
+ :init
+ (setq enable-recursive-minibuffers t
+ history-length 50
+ savehist-additional-variables '(mark-ring
+ global-mark-ring
+ search-ring
+ regexp-search-ring
+ extended-command-history)
+ savehist-autosave-interval 300))
+
+(use-package saveplace
+ :hook
+ (after-init . save-place-mode))
+
+(use-package restart-emacs)
+
+(use-package autorevert
+ :delight
+ :hook
+ (after-init . global-auto-revert-mode))
+
+(use-package crux)
+
+(use-package hungry-delete)
+
+(use-package drag-stuff)
+
+(use-package expand-region
+ :commands
+ (er/mark-symbol er/mark-word)
+ :config
+ (setq expand-region-smart-cursor t))
+
+(use-package savehist
+ :init
+ (setq enable-recursive-minibuffers t
+ history-length 50
+ savehist-additional-variables '(mark-ring
+ global-mark-ring
+ search-ring
+ regexp-search-ring
+ extended-command-history)
+ savehist-autosave-interval 300)
+ (savehist-mode))
+
+(use-package saveplace
+ :init
+ (save-place-mode))
+
+(use-package icomplete
+ :init
+ (fido-mode)
+ :config
+ (keymap-unset minibuffer-local-completion-map "TAB")
+ (keymap-set minibuffer-local-completion-map "TAB" 'icomplete-force-complete))
+
+(provide 'init-terminal-package)
+;;; init-terminal-package.el ends here
diff --git a/lisp/init-terminal-startup.el b/lisp/init-terminal-startup.el
@@ -0,0 +1,89 @@
+;;; init-const.el --- constant and system stuff -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(global-display-line-numbers-mode 1)
+
+(defconst *is-mac* (eq system-type 'darwin))
+(defconst *is-linux* (eq system-type 'gnu/linux))
+(defconst *is-windows* (or (eq system-type 'ms-dos) (eq system-type 'windows-nt)))
+(defconst *is-android* (if (getenv "TERMUX_VERSION") t nil))
+
+(set-selection-coding-system 'utf-8)
+(when (fboundp 'set-charset-priority)
+ (set-charset-priority 'unicode))
+(set-default-coding-systems 'utf-8)
+(set-buffer-file-coding-system 'utf-8)
+(set-clipboard-coding-system 'utf-8)
+(set-file-name-coding-system 'utf-8)
+(set-keyboard-coding-system 'utf-8)
+(set-next-selection-coding-system 'utf-8)
+(set-selection-coding-system 'utf-8)
+(set-terminal-coding-system 'utf-8)
+(setq locale-coding-system 'utf-8)
+(setq system-time-locale "C")
+
+(setq backup-directory-alist
+ `((".*" . ,(expand-file-name "backup/" user-emacs-directory)))
+ backup-by-copying t
+ delete-old-versions t
+ kept-new-versions 6
+ kept-old-versions 2
+ version-control t)
+
+(setq auto-save-file-name-transforms
+ `((".*" ,(expand-file-name "auto-save-list/" user-emacs-directory) t)))
+
+(put 'scroll-left 'disabled nil)
+
+(setq create-lockfiles nil)
+
+(setq ring-bell-function 'ignore)
+
+(cond
+ (*is-windows*
+ (add-to-list 'exec-path (expand-file-name "H/appppppppppp/scoop/apps/"))
+ (setenv "PATH" (concat (expand-file-name "H/appppppppppp/scoop/apps/") ";" (getenv "PATH"))))
+ (*is-mac*
+ (add-to-list 'exec-path (expand-file-name "/opt/homebrew/bin/"))
+ (setenv "PATH" (concat (expand-file-name "/opt/homebrew/bin/") ":" (getenv "PATH"))))
+ (*is-linux*
+ (add-to-list 'exec-path (expand-file-name "~/.guix-home/profile/bin/"))
+ (setenv "PATH" (concat (expand-file-name "~/.guix-home/profile/bin/") ":" (getenv "PATH")))))
+
+(global-auto-revert-mode 1)
+
+(when (display-graphic-p)
+ (recentf-mode)
+ (setq recentf-max-saved-items 30))
+
+(delete-selection-mode)
+
+(setq initial-scratch-message
+ "")
+
+(setq native-comp-async-warnings-errors-kind 'silent)
+
+(if (boundp 'use-short-answers)
+ (setq use-short-answers t)
+ (fset 'yes-or-no-p 'y-or-n-p))
+
+(setq delete-by-moving-to-trash t)
+
+(setq xref-search-program
+ (cond
+ ((or (executable-find "ripgrep")
+ (executable-find "rg"))
+ 'ripgrep)
+ (t 'grep)))
+
+(setq word-wrap-by-category t)
+
+(setq-default indent-tabs-mode nil)
+
+(setq kill-whole-line t)
+
+(provide 'init-terminal-startup)
+;;; init-terminal-statup.el ends here
diff --git a/lisp/init-terminal-ui.el b/lisp/init-terminal-ui.el
@@ -0,0 +1,82 @@
+;;; init-terminal-ui.el --- ui and other style customization cofig -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; display file size in mode line
+(size-indication-mode t)
+
+;; display column number in mode line
+(column-number-mode t)
+
+;; highlight current line
+(global-hl-line-mode t)
+
+;; theme
+(if (>= (display-color-cells) 16777216)
+ (progn
+ (defvar base03 "#062624")
+ (defvar base02 "#0c2b29")
+ (defvar base01 "#4d6967")
+ (defvar base00 "#728e8c")
+ (defvar base1 "#7f9b99")
+ (defvar cyan "#01928d")
+ (defvar blue "#2570cd")
+ (defvar green "#3a9c36")
+ (defvar magenta "#d33682")
+ (defvar yellow "#a87c04")
+ (defvar orange "#c24713")
+ (defvar red "#ce2825")
+
+ (custom-set-faces
+ `(default ((t (:foreground ,base00 :background ,base03))))
+ `(cursor ((t (:inverse t))))
+ `(region ((t (:exdend t :foreground ,base03 :background ,base00))))
+ `(shadow ((t (:foreground ,base01))))
+ `(error ((t (:foreground ,orange))))
+ `(warning ((t (:foreground ,yellow))))
+ `(font-lock-builtin-face ((t (:foreground ,base00 :weight bold :slant normal))))
+ `(font-lock-comment-face ((t (:foreground ,base01))))
+ `(font-lock-keyword-face ((t (:foreground ,cyan :weight bold))))
+ `(font-lock-variable-name-face ((t (:foreground ,blue))))
+ `(font-lock-constant-face ((t (:foreground ,blue :weight bold))))
+ `(font-lock-string-face ((t (:foreground ,green))))
+ `(font-lock-type-face ((t (:foreground ,yellow))))
+ `(font-lock-function-name-face ((t (:foreground ,blue))))
+ `(hl-line ((t (:background ,base02 :extend t))))
+ `(show-paren-match ((t (:foreground ,magenta :weight bold))))
+ `(show-paren-mismatch ((t (:foreground ,base03 :background ,red))))
+ `(icomplete-first-match ((t (:foreground ,yellow :weight bold))))
+ `(completions-common-part ((t (:foreground ,blue))))
+ `(minibuffer-prompt ((t (:foreground ,base01 :weight bold))))
+ `(line-number ((t (:foreground ,base01 :weight extra-light))))
+ `(button ((t (:foreground ,base00 :underline t))))
+ `(mode-line ((t (:background ,base00 :foreground ,base03))))
+ `(mode-line-inactive ((t (:background ,base02 :foreground ,base00))))
+ `(dired-header ((t (:foreground ,green))))
+ `(dired-directory ((t (:foreground ,blue))))
+ `(dired-ignored ((t (:foreground ,base01))))
+ `(isearch ((t (:background ,magenta :foreground ,base03))))
+ `(lazy-highlight ((t (:background ,yellow :foreground ,base03))))
+ `(isearch-fail ((t (:foreground ,red))))
+ `(org-block ((t (:inhert default))))
+ `(org-document-title ((t (:inhert default :weight bold))))
+ `(org-document-info ((t (:inhert org-document-title))))
+ `(eshell-prompt ((t (:foreground ,yellow :weight bold))))
+ `(diff-header ((t (:foreground ,base00 :background ,base02))))
+ `(diff-file-header ((t (:inherit: diff-header :weight bold))))
+ `(diff-hunk-header ((t (:foreground "#c1a059" :background "#253224"))))
+ `(diff-added ((t (:foreground "#73b971" :background "#103628"))))
+ `(diff-refine-added ((t (:foreground "#8cc78d" :background "#1d522e"))))
+ `(diff-removed ((t (:foreground "#e17360" :background "#2d2c25"))))
+ `(diff-refine-removed ((t (:foreground "#e7917f" :background "#5c3225"))))
+ `(xref-file-header ((t (:foreground ,base01))))
+ `(xref-line-number ((t (:foreground ,green))))
+ `(match ((t (:foreground ,base1 :background ,base02 :weight bold))))))
+
+ (progn
+ (global-hl-line-mode nil)))
+
+(provide 'init-terminal-ui)
+;;; init-terminal-ui.el ends here
diff --git a/lisp/init-ui.el b/lisp/init-ui.el
@@ -0,0 +1,113 @@
+;;; init-ui.el --- ui and other style customization cofig -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; custom-theme-load-path
+(add-to-list 'custom-theme-load-path "~/.emacs.d/lisp/")
+
+;; trust all themes
+(setq custom-safe-themes t)
+
+;; solarized
+(use-package solarized-theme
+ :straight
+ (solarized-emacs
+ :fork
+ (:type git :host github :repo "Andsy10/solarized-emacs" :protocol ssh))
+ :init
+ (if (and (daemonp) (not *is-android*))
+ (add-hook 'after-make-frame-functions
+ (lambda (frame)
+ (with-selected-frame frame
+ (load-theme 'my-dark t))))
+ (if *is-android*
+ (load-theme 'my-light t)
+ (load-theme 'my-dark t))))
+
+;; line numbers
+(use-package display-line-numbers
+ :hook
+ (after-init . global-display-line-numbers-mode)
+ :config
+ (setq display-line-numbers-type '2
+ display-line-numbers-grow-only t
+ display-line-numbers-width-start 4))
+
+;; resize margins
+(use-package olivetti
+ :delight
+ :hook
+ (org-mode . olivetti-mode)
+ (olivetti-mode . (lambda () (display-line-numbers-mode -1)))
+ :init
+ (setq olivetti-body-width 85))
+
+;; rainbow mode
+(use-package rainbow-mode)
+
+;; rainbow-delimiters
+(use-package rainbow-delimiters)
+
+;; some themes
+(use-package naysayer-theme)
+(use-package ef-themes)
+
+(if *is-android*
+ (use-package simple-modeline
+ :hook
+ (after-init . simple-modeline-mode)))
+
+;; eshell-syntax-highlighting
+(use-package eshell-syntax-highlighting
+ :hook
+ (eshell-mode . eshell-syntax-highlighting-global-mode))
+
+;; indent-bars
+(use-package indent-bars
+ :custom
+ (indent-bars-color '(font-lock-comment-face :face-bg nil :blend 0.4))
+ (indent-bars-highlight-current-depth '(:face default :blend 0.4))
+ (indent-bars-pattern ".")
+ (indent-bars-width-frac 0.1)
+ (indent-bars-pad-frac 0.1)
+ (indent-bars-color-by-depth nil)
+ (indent-bars-no-descend-string t)
+ (indent-bars-prefer-character t))
+
+;; highlight current line
+(use-package hl-line
+ :hook
+ (after-init . global-hl-line-mode))
+
+;; display time in mode line
+(unless *is-android*
+ (use-package time
+ :hook
+ (persp-mode . display-time-mode)
+ :config
+ (setq display-time-default-load-average nil
+ display-time-string-forms
+ '((propertize
+ (concat
+ (propertize (format-time-string " %I:%M") 'face 'display-time-date-and-time)
+ (propertize (format-time-string "-%p") 'face 'font-lock-comment-face))
+ 'help-echo (format-time-string "%A, %B %d, %Y"))))))
+
+;; easier to setup fonts
+(use-package cnfonts
+ :hook
+ (after-init . cnfonts-mode)
+ :init
+ (setq cnfonts-personal-fontnames
+ '(("Sarasa Fixed TC") ;English
+ ("Sarasa Fixed TC") ;Chinese
+ nil ;ext-B
+ nil ;symbol
+ nil)) ;what's this
+ :config
+ (cnfonts--select-profile "profile1"))
+
+(provide 'init-ui)
+;;; init-ui.el ends here
diff --git a/lisp/init-window.el b/lisp/init-window.el
@@ -0,0 +1,135 @@
+;;; init-window.el --- windows manage packages -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+(use-package window
+ :straight nil
+ :config
+ (setq switch-to-buffer-obey-display-actions t))
+
+(use-package popper
+ :defines
+ popper-echo-dispatch-actions
+ :commands
+ popper-group-by-directory
+ :hook
+ (after-init . popper-mode)
+
+ :init
+ (setq popper-reference-buffers
+ '("\\*Messages\\*"
+ "Output\\*$" "\\*Pp Eval Output\\*$"
+ "\\*Compile-Log\\*"
+ "\\*Completions\\*"
+ "\\*Warnings\\*"
+ "\\*Flymake diagnostics.*\\*"
+ "\\*Async Shell Command\\*"
+ "\\*Apropos\\*"
+ "\\*Backtrace\\*"
+ "\\*prodigy\\*"
+ "\\*Calendar\\*"
+ "\\*Holidays\\*"
+ "\\*Embark Actions\\*"
+ "\\*Finder\\*"
+ "\\*Kill Ring\\*"
+ "\\*Embark Export:.*\\*"
+ "\\*Edit Annotation.*\\*"
+ "\\*Flutter\\*"
+ "\\*Ibuffer\\*"
+ "^\\*Finder-"
+ "Buffers\\*$"
+ "^\\*Geiser"
+ "\\*gptel-Kimi-Code\\*"
+ "\\*gptel-agent:.*\\*"
+ "^\\*OpenCode Sessions"
+ "^\\*sly"
+ "^magit"
+ "\\*discomfort\\*"
+ "\\*eww bookmarks\\*"
+ "\\*eww history\\*"
+ "\\*Proced\\*"
+ bookmark-bmenu-mode
+ lsp-bridge-ref-mode
+ comint-mode
+ compilation-mode
+ help-mode helpful-mode
+ tabulated-list-mode
+ Buffer-menu-mode
+ occur-mode
+ gnus-article-mode devdocs-mode
+ grep-mode occur-mode rg-mode deadgrep-mode ag-mode pt-mode
+ ivy-occur-mode ivy-occur-grep-mode
+ process-menu-mode list-environment-mode cargo-process-mode
+ youdao-dictionary-mode osx-dictionary-mode fanyi-mode
+ gptel-mode
+ ibuffer-mode
+
+ "^\\*eshell.*\\*.*$" eshell-mode
+ ".*eshell\\*$"
+ "^\\*shell.*\\*.*$" shell-mode
+ "^\\*terminal.*\\*.*$" term-mode
+ "^\\*vterm.*\\*.*$" vterm-mode
+ "^\\*eat.*\\*.*$" eat-mode
+
+ "\\*DAP Templates\\*$" dap-server-log-mode
+ "\\*ELP Profiling Restuls\\*" profiler-report-mode
+ "\\*Flycheck errors\\*$" " \\*Flycheck checker\\*$"
+ "\\*Paradox Report\\*$" "\\*package update results\\*$" "\\*Package-Lint\\*$"
+ "\\*[Wo]*Man.*\\*$"
+ "\\*ert\\*$" overseer-buffer-mode
+ "\\*gud-debug\\*$"
+ "\\*lsp-help\\*$" "\\*lsp session\\*$"
+ "\\*quickrun\\*$"
+ "\\*tldr\\*$"
+ "\\*vc-.*\\*$"
+ "\\*eldoc\\*"
+ "^\\*elfeed-entry\\*$"
+ "^\\*macro expansion\\**"
+
+ "\\*Agenda Commands\\*" "\\*Org Select\\*" "\\*Capture\\*" "^CAPTURE-.*\\.org*" "^CAPTURE-" "\\*Org Note\\*"
+ "\\*Gofmt Errors\\*$" "\\*Go Test\\*$" godoc-mode
+ "\\*docker-containers\\*" "\\*docker-images\\*" "\\*docker-networks\\*" "\\*docker-volumes\\*"
+ "\\*prolog\\*" inferior-python-mode inf-ruby-mode swift-repl-mode
+ "\\*rustfmt\\*$" rustic-compilation-mode rustic-cargo-clippy-mode
+ rustic-cargo-outdated-mode rustic-cargo-test-mode
+
+ "^\\*\\[D\\] FILE backlinks for" "^\\*Denote HEADING backlinks for"))
+
+ (when (display-grayscale-p)
+ (setq popper-mode-line
+ '("[POP]")))
+ (setq popper-echo-dispatch-actions t)
+ (setq popper-group-function nil)
+
+ :config
+ (popper-echo-mode 1)
+
+ (with-no-warnings
+ (defun my-popper-fit-window-height (win)
+ "Determine the height of popup window WIN by fitting it to the buffer's content."
+ (fit-window-to-buffer
+ win
+ (floor (frame-height) 3)
+ (floor (frame-height) 3)))
+ (setq popper-window-height #'my-popper-fit-window-height)
+
+ (defun popper-close-window-hack (&rest _)
+ "Close popper window via `C-g'."
+ ;; `C-g' can deactivate region
+ (when (and (called-interactively-p 'interactive)
+ (not (region-active-p))
+ popper-open-popup-alist)
+ (let ((window (caar popper-open-popup-alist)))
+ (when (window-live-p window)
+ (delete-window window)))))
+ (advice-add #'keyboard-quit :before #'popper-close-window-hack)))
+
+;; windmove
+(use-package windmove
+ :hook
+ (after-init . windmove-swap-states-default-keybindings))
+
+(provide 'init-window)
+;;; init-window.el ends here
diff --git a/lisp/my-dark-theme.el b/lisp/my-dark-theme.el
@@ -0,0 +1,148 @@
+;;; my-dark-theme.el --- Dark Theme -*- lexical-binding: t -*-
+
+;;; Commentary:
+;; A green dark theme base on solarized-theme
+
+;;; Code:
+
+(require 'solarized)
+(require 'my-palette)
+(eval-when-compile
+ (require 'solarized-palettes))
+
+(deftheme my-dark "A dark theme using Solarized framework.")
+
+(solarized-with-color-variables-with-palette
+ 'dark
+ 'my-dark
+ my-dark-core-palette
+ '((custom-theme-set-faces
+ theme-name
+
+ `(font-lock-keyword-face ((,class (:foreground ,cyan :weight bold))))
+ `(font-lock-doc-face ((,class (:foreground ,green :slant normal))))
+ `(font-lock-string-face ((,class (:foreground ,green))))
+
+ `(italic ((,class (:slant italic))))
+ `(line-number ((,class (:foreground ,base01 :weight light))))
+ `(button ((,class (:foreground ,yellow :underline t))))
+
+ `(mode-line ((,class (:foreground ,base0 :background ,base02))))
+ `(mode-line-inactive ((,class (:foreground ,base01 :background ,base03))))
+ `(display-time-date-and-time ((,class (:foreground ,base1 :bold t))))
+
+ `(org-level-1 ((,class (:foreground ,orange :height 1.0 :weight normal))))
+ `(org-level-2 ((,class (:foreground ,blue :height 1.0 :weight normal))))
+ `(org-level-3 ((,class (:foreground ,green :height 1.0 :weight normal))))
+ `(org-level-4 ((,class (:foreground ,yellow :height 1.0 :weight normal))))
+ `(org-level-5 ((,class (:foreground ,cyan :height 1.0 :weight normal))))
+ `(org-level-6 ((,class (:foreground ,green :height 1.0 :weight normal))))
+ `(org-level-7 ((,class (:foreground ,orange :height 1.0 :weight normal))))
+ `(org-level-8 ((,class (:foreground ,blue :height 1.0 :weight normal))))
+ `(org-document-title ((,class (:foreground ,base0 :height 1.0 :weight bold))))
+ `(org-done ((,class (:foreground ,green :weight bold))))
+ `(org-headline-done ((,class (:foreground ,green))))
+ `(org-block-begin-line ((,class (:foreground ,base01 :slant italic))))
+ `(org-block-end-line ((,class (:foreground ,base01 :slant italic))))
+ `(org-priority ((,class (:foreground ,green :weight bold))))
+ `(org-checkbox ((,class (:foreground ,base0 :weight bold))))
+ `(org-dispatcher-highlight ((,class (:inherit diff-hunk-header :weight bold))))
+
+ `(calendar-month-header ((,class (:foreground ,base0 :weight bold))))
+ `(holiday ((,class (:underline (:style line :color ,yellow)))))
+ `(cal-china-x-important-holiday-face ((,class (:underline (:style line :color ,red)))))
+ `(cal-china-x-general-holiday-face ((,class (:underline (:style line :color ,yellow)))))
+
+ `(denote-journal-calendar ((,class (:foreground ,cyan :slant italic))))
+ `(denote-faces-keywords ((,class (:foreground ,cyan))))
+
+ `(markdown-header-face-1 ((,class (:foreground ,orange :height 1.0 :weight normal))))
+ `(markdown-header-face-2 ((,class (:foreground ,blue :height 1.0 :weight normal))))
+ `(markdown-header-face-3 ((,class (:foreground ,green :height 1.0 :weight normal))))
+ `(markdown-header-face-4 ((,class (:foreground ,yellow :height 1.0 :weight normal))))
+ `(markdown-header-face-5 ((,class (:foreground ,cyan :height 1.0 :weight normal))))
+ `(markdown-header-face-6 ((,class (:foreground ,green :height 1.0 :weight normal))))
+ `(markdown-code-face ((,class (:foreground ,base0))))
+ `(markdown-table-face ((,class (:foreground ,green))))
+
+ `(dashboard-footer-face ((,class (:foreground ,blue))))
+ `(dashboard-text-banner ((,class (:foreground ,green))))
+ `(dashboard-heading ((,class (:foreground ,green :weight bold))))
+
+ `(dired-broken-symlink ((,class (:inherit dired-symlink :foreground ,orange))))
+ `(dired-header ((,class (:foreground ,green))))
+ `(dirvish-file-time ((,class (:foreground ,base01))))
+ `(dirvish-free-space ((,class (:foreground ,green))))
+ `(dired-async-mode-message ((,class (:foreground ,red))))
+ `(dired-async-message ((,class (:foreground ,yellow))))
+
+ `(diff-hunk-header ((,class (:foreground ,yellow-1fg :background ,yellow-1bg))))
+
+ `(consult-file ((,class (:foreground ,green))))
+ `(consult-notes-name ((,class (:foreground ,base01))))
+ `(consult-notes-time ((,class (:foreground ,base01))))
+ `(consult-notes-size ((,class (:foreground ,base01))))
+
+ `(vertico-current ((,class (:background ,base02 :extend t :underline nil))))
+
+ `(transient-key-stay ((,class (:foreground ,cyan :inherit transient-key))))
+ `(transient-key-return ((,class (:foreground ,violet :inherit transient-key))))
+ `(transient-key-exit ((,class (:foreground ,blue :inherit transient-key))))
+ `(transient-key-stack ((,class (:foreground ,magenta :inherit transient-key))))
+ `(transient-key-recurse ((,class (:foreground ,blue :inherit transient-key))))
+ `(transient-key-noop ((,class (:foreground ,base01 :inherit transient-key))))
+
+ `(geiser-font-lock-repl-output ((,class (:foreground ,green))))
+ `(geiser-font-lock-doc-link ((,class (:foreground ,blue :underline t))))
+ `(geiser-font-lock-error-link ((,class (:foreground ,orange :underline t))))
+
+ `(lisp-extra-font-lock-backquote ((,class (:inherit font-lock-type-face))))
+
+ `(vundo-saved ((,class (:foreground ,green))))
+ `(vundo-last-saved ((,class (:foreground ,green :weight bold))))
+ `(vundo-highlight ((,class (:foreground ,cyan :weight bold))))
+ `(vundo-node ((,class (:foreground ,base01))))
+ `(vundo-stem ((,class (:foreground ,base01))))
+
+ `(jinx-misspelled ((,class (:underline (:style line :color ,yellow)))))
+
+ `(keycast-key ((,class (:foreground ,green :weight bold))))
+
+ `(emms-playlist-track-face ((,class (:foreground ,cyan))))
+ `(emms-playlist-selected-face ((,class (:foreground ,blue :weight bold))))
+
+ `(proced-pid ((,class (:foreground ,violet))))
+ `(proced-session-leader-pid ((,class (:inherit proced-pid :underline t))))
+ `(proced-ppid ((,class (:foreground ,blue))))
+ `(proced-sess ((,class (:inherit proced-ppid))))
+ `(proced-emacs-pid ((,class (:foreground ,magenta))))
+ `(proced-memory-low-usage ((,class (:foreground ,green))))
+ `(proced-memory-medium-usage ((,class (:foreground ,yellow))))
+ `(proced-memory-high-usage ((,class (:foreground ,red))))
+ `(proced-executable ((,class (:foreground ,cyan))))
+ `(proced-run-status-code ((,class (:foreground ,green))))
+ `(proced-interruptible-sleep-status-code ((,class (:foreground ,base01))))
+ `(proced-uninterruptible-sleep-status-code ((,class (:foreground ,red))))
+ `(proced-time-colon ((,class (:foreground ,base01))))
+ `(proced-cpu ((,class (:foreground ,base0))))
+ `(proced-mem ((,class (:foreground ,base0))))
+
+ `(syncthing-bold ((,class (:inherit bold))))
+ `(syncthing-italic ((,class (:inherit italic))))
+ `(syncthing-my-id ((,class (:foreground ,blue :weight bold))))
+ `(syncthing-rate-upload ((,class (:foreground ,green))))
+ `(syncthing-rate-download ((,class (:foreground ,blue :weight bold))))
+ `(syncthing-uptime ((,class (:foreground ,magenta :wegiht bold))))
+ `(syncthing-count-discovery ((,class (:foreground ,blue :weight bold))))
+ `(syncthing-count-listeners ((,class (:foreground ,green :weight bold))))
+ `(syncthing-count-local-bytes ((,class (:foreground ,cyan :weight bold))))
+ `(syncthing-count-local-files ((,class (:inherit default :weight bold))))
+ `(syncthing-count-local-folders ((,class (:foreground ,yellow :weight bold))))
+ `(syncthing-progress-100 ((,class (:foreground ,green))))
+ `(syncthing-progress-75 ((,class (:foreground ,cyan))))
+ `(syncthing-progress-50 ((,class (:foreground ,yellow))))
+ `(syncthing-progress-25 ((,class (:foreground ,orange))))
+ `(syncthing-progress-0 ((,class (:foreground ,red)))))))
+
+(provide-theme 'my-dark)
+;;; my-dark-theme.el ends here
diff --git a/lisp/my-light-theme.el b/lisp/my-light-theme.el
@@ -0,0 +1,148 @@
+;;; my-light-theme.el --- Light Theme -*- lexical-binding: t -*-
+
+;;; Commentary:
+;; A green light theme base on solarized-theme
+
+;;; Code:
+
+(require 'solarized)
+(require 'my-palette)
+(eval-when-compile
+ (require 'solarized-palettes))
+
+(deftheme my-light "A light theme using Solarized framework.")
+
+(solarized-with-color-variables-with-palette
+ 'light
+ 'my-light
+ my-light-core-palette
+ '((custom-theme-set-faces
+ theme-name
+
+ `(font-lock-keyword-face ((,class (:foreground ,cyan :weight bold))))
+ `(font-lock-doc-face ((,class (:foreground ,green :slant normal))))
+ `(font-lock-string-face ((,class (:foreground ,green))))
+
+ `(italic ((,class (:slant italic))))
+ `(line-number ((,class (:foreground ,base01 :weight light))))
+ `(button ((,class (:foreground ,yellow :underline t))))
+
+ `(mode-line ((,class (:foreground ,base0 :background ,base02))))
+ `(mode-line-inactive ((,class (:foreground ,base01 :background ,base03))))
+ `(display-time-date-and-time ((,class (:foreground ,base1 :bold t))))
+
+ `(org-level-1 ((,class (:foreground ,orange :height 1.0 :weight normal))))
+ `(org-level-2 ((,class (:foreground ,blue :height 1.0 :weight normal))))
+ `(org-level-3 ((,class (:foreground ,green :height 1.0 :weight normal))))
+ `(org-level-4 ((,class (:foreground ,yellow :height 1.0 :weight normal))))
+ `(org-level-5 ((,class (:foreground ,cyan :height 1.0 :weight normal))))
+ `(org-level-6 ((,class (:foreground ,green :height 1.0 :weight normal))))
+ `(org-level-7 ((,class (:foreground ,orange :height 1.0 :weight normal))))
+ `(org-level-8 ((,class (:foreground ,blue :height 1.0 :weight normal))))
+ `(org-document-title ((,class (:foreground ,base0 :height 1.0 :weight bold))))
+ `(org-done ((,class (:foreground ,green :weight bold))))
+ `(org-headline-done ((,class (:foreground ,green))))
+ `(org-block-begin-line ((,class (:foreground ,base01 :slant italic))))
+ `(org-block-end-line ((,class (:foreground ,base01 :slant italic))))
+ `(org-priority ((,class (:foreground ,green :weight bold))))
+ `(org-checkbox ((,class (:foreground ,base0 :weight bold))))
+ `(org-dispatcher-highlight ((,class (:inherit diff-hunk-header :weight bold))))
+
+ `(calendar-month-header ((,class (:foreground ,base0 :weight bold))))
+ `(holiday ((,class (:underline (:style line :color ,yellow)))))
+ `(cal-china-x-important-holiday-face ((,class (:underline (:style line :color ,red)))))
+ `(cal-china-x-general-holiday-face ((,class (:underline (:style line :color ,yellow)))))
+
+ `(denote-journal-calendar ((,class (:foreground ,cyan :slant italic))))
+ `(denote-faces-keywords ((,class (:foreground ,cyan))))
+
+ `(markdown-header-face-1 ((,class (:foreground ,orange :height 1.0 :weight normal))))
+ `(markdown-header-face-2 ((,class (:foreground ,blue :height 1.0 :weight normal))))
+ `(markdown-header-face-3 ((,class (:foreground ,green :height 1.0 :weight normal))))
+ `(markdown-header-face-4 ((,class (:foreground ,yellow :height 1.0 :weight normal))))
+ `(markdown-header-face-5 ((,class (:foreground ,cyan :height 1.0 :weight normal))))
+ `(markdown-header-face-6 ((,class (:foreground ,green :height 1.0 :weight normal))))
+ `(markdown-code-face ((,class (:foreground ,base0))))
+ `(markdown-table-face ((,class (:foreground ,green))))
+
+ `(dashboard-footer-face ((,class (:foreground ,blue))))
+ `(dashboard-text-banner ((,class (:foreground ,green))))
+ `(dashboard-heading ((,class (:foreground ,green :weight bold))))
+
+ `(dired-broken-symlink ((,class (:inherit dired-symlink :foreground ,orange))))
+ `(dired-header ((,class (:foreground ,green))))
+ `(dirvish-file-time ((,class (:foreground ,base01))))
+ `(dirvish-free-space ((,class (:foreground ,green))))
+ `(dired-async-mode-message ((,class (:foreground ,red))))
+ `(dired-async-message ((,class (:foreground ,yellow))))
+
+ `(diff-hunk-header ((,class (:foreground ,yellow-1fg :background ,yellow-1bg))))
+
+ `(consult-file ((,class (:foreground ,green))))
+ `(consult-notes-name ((,class (:foreground ,base01))))
+ `(consult-notes-time ((,class (:foreground ,base01))))
+ `(consult-notes-size ((,class (:foreground ,base01))))
+
+ `(vertico-current ((,class (:background ,base02 :extend t :underline nil))))
+
+ `(transient-key-stay ((,class (:foreground ,cyan :inherit transient-key))))
+ `(transient-key-return ((,class (:foreground ,violet :inherit transient-key))))
+ `(transient-key-exit ((,class (:foreground ,blue :inherit transient-key))))
+ `(transient-key-stack ((,class (:foreground ,magenta :inherit transient-key))))
+ `(transient-key-recurse ((,class (:foreground ,blue :inherit transient-key))))
+ `(transient-key-noop ((,class (:foreground ,base01 :inherit transient-key))))
+
+ `(geiser-font-lock-repl-output ((,class (:foreground ,green))))
+ `(geiser-font-lock-doc-link ((,class (:foreground ,blue :underline t))))
+ `(geiser-font-lock-error-link ((,class (:foreground ,orange :underline t))))
+
+ `(lisp-extra-font-lock-backquote ((,class (:inherit font-lock-type-face))))
+
+ `(vundo-saved ((,class (:foreground ,green))))
+ `(vundo-last-saved ((,class (:foreground ,green :weight bold))))
+ `(vundo-highlight ((,class (:foreground ,cyan :weight bold))))
+ `(vundo-node ((,class (:foreground ,base01))))
+ `(vundo-stem ((,class (:foreground ,base01))))
+
+ `(jinx-misspelled ((,class (:underline (:style line :color ,yellow)))))
+
+ `(keycast-key ((,class (:foreground ,green :weight bold))))
+
+ `(emms-playlist-track-face ((,class (:foreground ,cyan))))
+ `(emms-playlist-selected-face ((,class (:foreground ,blue :weight bold))))
+
+ `(proced-pid ((,class (:foreground ,violet))))
+ `(proced-session-leader-pid ((,class (:inherit proced-pid :underline t))))
+ `(proced-ppid ((,class (:foreground ,blue))))
+ `(proced-sess ((,class (:inherit proced-ppid))))
+ `(proced-emacs-pid ((,class (:foreground ,magenta))))
+ `(proced-memory-low-usage ((,class (:foreground ,green))))
+ `(proced-memory-medium-usage ((,class (:foreground ,yellow))))
+ `(proced-memory-high-usage ((,class (:foreground ,red))))
+ `(proced-executable ((,class (:foreground ,cyan))))
+ `(proced-run-status-code ((,class (:foreground ,green))))
+ `(proced-interruptible-sleep-status-code ((,class (:foreground ,base01))))
+ `(proced-uninterruptible-sleep-status-code ((,class (:foreground ,red))))
+ `(proced-time-colon ((,class (:foreground ,base01))))
+ `(proced-cpu ((,class (:foreground ,base0))))
+ `(proced-mem ((,class (:foreground ,base0))))
+
+ `(syncthing-bold ((,class (:inherit bold))))
+ `(syncthing-italic ((,class (:inherit italic))))
+ `(syncthing-my-id ((,class (:foreground ,blue :weight bold))))
+ `(syncthing-rate-upload ((,class (:foreground ,green))))
+ `(syncthing-rate-download ((,class (:foreground ,blue :weight bold))))
+ `(syncthing-uptime ((,class (:foreground ,magenta :wegiht bold))))
+ `(syncthing-count-discovery ((,class (:foreground ,blue :weight bold))))
+ `(syncthing-count-listeners ((,class (:foreground ,green :weight bold))))
+ `(syncthing-count-local-bytes ((,class (:foreground ,cyan :weight bold))))
+ `(syncthing-count-local-files ((,class (:inherit default :weight bold))))
+ `(syncthing-count-local-folders ((,class (:foreground ,yellow :weight bold))))
+ `(syncthing-progress-100 ((,class (:foreground ,green))))
+ `(syncthing-progress-75 ((,class (:foreground ,cyan))))
+ `(syncthing-progress-50 ((,class (:foreground ,yellow))))
+ `(syncthing-progress-25 ((,class (:foreground ,orange))))
+ `(syncthing-progress-0 ((,class (:foreground ,red)))))))
+
+(provide-theme 'my-light)
+;;; my-light-theme.el ends here
diff --git a/lisp/my-palette.el b/lisp/my-palette.el
@@ -0,0 +1,33 @@
+;;; my-palette.el --- Color palette for solarized -*- lexical-binding: t -*-
+
+;;; Commentary:
+;; Palette of my-theme .
+
+;;; Code:
+
+(defvar my-dark-core-palette
+ '("#062624" ; darkest-base
+ "#E3FCFB" ; brightest-base
+ "#A87C04" ; yellow
+ "#C24713" ; orange
+ "#CE2825" ; red
+ "#d33682" ; magenta
+ "#6c71c4" ; violet
+ "#2570CD" ; blue
+ "#01928D" ; cyan
+ "#3A9C36")) ; green
+
+(defvar my-light-core-palette
+ '("#051E23" ; darkest-base
+ "#FCFFDE" ; brightest-base
+ "#A87C04" ; yellow
+ "#C24713" ; orange
+ "#CE2825" ; red
+ "#d33682" ; magenta
+ "#6c71c4" ; violet
+ "#2570CD" ; blue
+ "#01928D" ; cyan
+ "#3A9C36")) ; green
+
+(provide 'my-palette)
+;;; my-palette.el ends here