Here is my personal configuration file for Emacs. The whole README file is a symlink to solarion-emacs.org
, and with org babel
, this file could be tangled into separate emacs-lisp files under $HOME/.emacs.d/lisp/
.
- Solarion Emacs
- Installation
- early-init.el
- init.el
- init-straight.el
- init-func.el
- init-basic.el
- init-general.el
- init-ui.el
- init-themes.el
- init-scroll.el
- init-fonts.el
- init-edit.el
- init-hydra.el
- init-map.el
- init-vertico.el
- init-corfu.el
- init-tempel.el
- init-magit.el
- init-ibuffer.el
- init-midnight.el
- init-tramp.el
- init-org.el
- init-latex.el
- init-dired.el
- init-projectile.el
- init-dashboard.el
- init-vterm.el
- init-persp.el
- init-dict.el
- init-im.el
- init-wsl.el
Clone the repository
git clone [email protected]:wang1zhen/solarion-emacs ~/.emacs.d
Tangle the org file
emacs --batch --eval "(progn (require 'org) (let ((org-confirm-babel-evaluate nil)) (org-babel-tangle-file \"~/.emacs.d/solarion-emacs.org\")))"
Launch Emacs and have fun!
;;; early-init.el --- early-init.el is run before package and UI initialization happens -*- lexical-binding: t -*-
;;; Code:
;; Defer garbage collection further back in the startup process
(setq gc-cons-threshold most-positive-fixnum
gc-cons-percentage 0.5)
;; Package initialize occurs automatically, before `user-init-file' is
;; loaded, but after `early-init-file'. We handle package
;; initialization, so we must prevent Emacs from doing it early!
(setq package-enable-at-startup nil)
;; Inhibit resizing frame
(setq frame-inhibit-implied-resize t)
;; Faster to disable these here (before they've been initialized)
(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)
;; Suppress the 'Package cl is deprecated' warning
(setq byte-compile-warnings '(not obsolete))
;;; init.el --- Load the full configuration -*- lexical-binding: t -*-
;;; Code:
(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))
;; Custom file
(setq custom-file (make-temp-file "emacs-custom-"))
;; Adjust garbage collection thresholds during startup, and thereafter
(let ((normal-gc-cons-threshold (* 20 1024 1024))
(init-gc-cons-threshold (* 128 1024 1024)))
(setq gc-cons-threshold init-gc-cons-threshold)
(add-hook 'emacs-startup-hook
(lambda () (setq gc-cons-threshold normal-gc-cons-threshold))))
;; Always load newest byte code
(setq load-prefer-newer t)
;; Packages
(require 'init-straight)
;; Useful functions defined
(require 'init-func)
;; Preferences
(require 'init-basic)
(require 'init-general)
(require 'init-ui)
(require 'init-themes)
(require 'init-scroll)
(require 'init-fonts)
(require 'init-edit)
;; Keybindings
(require 'init-hydra)
(require 'init-map)
(require 'init-vertico)
(require 'init-corfu)
(require 'init-tempel)
(require 'init-magit)
(require 'init-ibuffer)
(require 'init-midnight)
(require 'init-tramp)
(require 'init-org)
(require 'init-latex)
(require 'init-dired)
(require 'init-projectile)
(require 'init-dashboard)
(require 'init-vterm)
(require 'init-persp)
(require 'init-dict)
(require 'init-im)
;; WSL specific setting
(when (and (eq system-type 'gnu/linux) (getenv "WSLENV"))
(require 'init-wsl))
;;; init-straight.el --- Initialize package configurations -*- lexical-binding: t -*-
;;; Code:
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(setq straight-use-package-by-default t)
(setq straight-vc-git-default-protocol 'https)
(setq straight-vc-git-default-clone-depth 3)
(load bootstrap-file nil 'nomessage))
;; Install use-package with straight
(straight-use-package 'use-package)
;; Should set before loading `use-package'
(setq use-package-expand-minimally t)
(setq use-package-enable-imenu-support t)
(require 'use-package)
;; Native compile
;; Log warnings but not pop up the *Warnings* buffer
(setq native-comp-async-report-warnings-errors 'silent)
;; Required by `use-package'
(use-package diminish)
(use-package bind-key)
(provide 'init-straight)
;;; init-func.el --- Useful functions are defined here -*- lexical-binding: t -*-
;;; Code:
(defun indent-buffer ()
(interactive)
(save-excursion
(indent-region (point-min) (point-max) nil)))
;; Font
(defun font-installed-p (font-name)
"Check if font with FONT-NAME is available."
(find-font (font-spec :name font-name)))
;; Auto tangle babel file
(defun org-babel-auto-tangle ()
(when (and (eq major-mode 'org-mode)
(string-equal (buffer-name) "solarion-emacs.org"))
(org-babel-tangle)))
;; Define split-window-below-and-focus and split-window-right-and-focus
(defun split-window-below-and-focus ()
"Split the window vertically and focus the new window."
(interactive)
(split-window-below)
(windmove-down))
(defun split-window-right-and-focus ()
"Split the window horizontally and focus the new window."
(interactive)
(split-window-right)
(windmove-right))
(defun solarion/org-mode-setup ()
(auto-fill-mode 0)
(visual-line-mode 1)
(adaptive-wrap-prefix-mode 1)
;; (electric-pair-local-mode -1)
)
;; Ask for the filename before pasting an image
;; filename should end with ".png/.jpg/.svg"
(defun solarion/org-download-paste-clipboard-wsl ()
"to simplify the logic, use c:/Users/Public as temporary directory, and move it into current directory"
(interactive)
(let* ((powershell (executable-find "powershell.exe"))
(file-base-name (format-time-string "image-%Y%m%d_%H%M%S.png"))
(file-name (read-string (format "Filename [%s]: " file-base-name) nil nil file-base-name))
(file-path-wsl (concat "./image/" file-name)))
(shell-command (concat powershell " -command \"(Get-Clipboard -Format Image).Save(\\\"C:/Users/Public/" file-name "\\\")\""))
(make-directory "./image" t)
(rename-file (concat "/mnt/c/Users/Public/" file-name) file-path-wsl)
(insert (concat "#+ATTR_LATEX: :width \\linewidth\n"))
(org-indent-line)
(insert (concat "[[file:" file-path-wsl "]]"))
(org-display-inline-images)))
;; dashboard
(defun solarion-homepage (&rest _)
(interactive)
(browse-url "https://github.com/wang1zhen/solarion-emacs"))
(defun solarion-edit-config (&rest _)
(interactive)
(find-file (concat user-emacs-directory "solarion-emacs.org")))
;; buffer
(defun solarion-new-buffer nil
(interactive)
(let ((buffer (generate-new-buffer "*new*")))
(set-window-buffer nil buffer)
(with-current-buffer buffer
(funcall (default-value 'major-mode)))))
;; Delete file and buffer
(defun delete-file-and-buffer ()
"Kill the current buffer and deletes the file it is visiting."
(interactive)
(let ((filename (buffer-file-name)))
(if filename
(if (y-or-n-p (concat "Do you really want to delete file " filename " ?"))
(progn
(delete-file filename)
(message "Deleted file %s." filename)
(kill-buffer)))
(message "Not a file visiting buffer!"))))
(defun flash-mode-line ()
(invert-face 'mode-line)
(run-with-timer 0.1 nil #'invert-face 'mode-line))
(defun copy-line (arg)
"Copy lines (as many as prefix argument) in the kill ring.
Ease of use features:
- Move to start of next line.
- Appends the copy on sequential calls.
- Use newline as last char even on the last line of the buffer.
- If region is active, copy its lines."
(interactive "p")
(let ((beg (line-beginning-position))
(end (line-end-position arg)))
(when mark-active
(if (> (point) (mark))
(setq beg (save-excursion (goto-char (mark)) (line-beginning-position)))
(setq end (save-excursion (goto-char (mark)) (line-end-position)))))
(if (eq last-command 'copy-line)
(kill-append (buffer-substring beg end) (< end beg))
(kill-ring-save beg end)))
(kill-append "\n" nil)
(beginning-of-line (or (and arg (1+ arg)) 2))
(if (and arg (not (= 1 arg))) (message "%d lines copied" arg)))
(defun solarion/git-add-commit-push ()
"Simple commit current git project and push to its upstream."
(interactive)
(when (and buffer-file-name
(buffer-modified-p))
(save-buffer)) ;; save it first if modified.
(magit-diff-unstaged)
(when (yes-or-no-p "Do you really want to commit everything?")
(magit-stage-modified t) ;; stage modified and untracked
(magit-diff-staged)
(let ((msg (read-string "Commit Message: ")))
(when (= 0 (length msg))
(setq msg (format-time-string "commit by magit in emacs@%Y-%m-%d %H:%M:%S"
(current-time))))
(magit-call-git "commit" "-m" msg)
(magit-push-current-to-upstream nil)
(message "now do async push to %s" (magit-get "remote" "origin" "url"))))
(magit-mode-bury-buffer))
(defun solarion/indent-buffer-and-format ()
"Indent buffer and format code"
(interactive)
(indent-buffer)
(when (format-all--language-id-buffer)
(format-all-buffer t)))
(provide 'init-func)
;;; init-basic.el --- Default configurations -*- lexical-binding: t -*-
;;; Code:
(setq user-full-name "wang1zhen"
user-mail-address "[email protected]")
;; Increase how much is read from processes in a single chunk (default is 4kb)
(setq read-process-output-max #x10000) ; 64kb
;; Garbage Collector Magic Hack
(use-package gcmh
:diminish
:init
(setq gcmh-idle-delay 5
gcmh-high-cons-threshold #x1000000) ; 16MB
:hook (after-init . gcmh-mode))
;; Encoding
;; UTF-8 as the default coding system
(when (fboundp 'set-charset-priority)
(set-charset-priority 'unicode))
;; Explicitly set the prefered coding systems to avoid annoying prompt
;; from emacs (especially on Microsoft Windows)
(prefer-coding-system 'utf-8)
(setq locale-coding-system 'utf-8)
(set-language-environment 'utf-8)
(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-terminal-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(modify-coding-system-alist 'process "*" 'utf-8)
;; Ensure environment variables inside Emacs look the same as in the user's shell
(use-package exec-path-from-shell
:init
(setq exec-path-from-shell-variables '("PATH" "MANPATH")
exec-path-from-shell-arguments '("-l"))
:config
(exec-path-from-shell-initialize))
;; Start server
(use-package server
:straight nil
:hook (after-init . server-mode))
;; Go to the last place when previously visited the file
(use-package saveplace
:straight nil
:hook (after-init . save-place-mode))
(use-package recentf
:straight nil
:hook (after-init . recentf-mode)
:init
(setq recentf-max-saved-items 500
recentf-max-menu-items 15
recentf-exclude
'("\\.?cache" ".cask" "url" "COMMIT_EDITMSG\\'" "bookmarks"
"\\.\\(?:gz\\|gif\\|svg\\|png\\|jpe?g\\|bmp\\|xpm\\)$"
"\\.?ido\\.last$" "\\.revive$" "/G?TAGS$" "/.elfeed/"
"^/tmp/" "^/var/folders/.+$" "^/ssh:" "/persp-confs/"
(lambda (file) (file-in-directory-p file package-user-dir))))
:config
(push (expand-file-name recentf-save-file) recentf-exclude)
(add-to-list 'recentf-filename-handlers #'abbreviate-file-name))
(use-package savehist
:straight nil
:hook (after-init . savehist-mode)
:init
(setq enable-recursive-minibuffers t ; Allow commands in minibuffers
history-length 1000
savehist-additional-variables '(mark-ring
global-mark-ring
search-ring
regexp-search-ring
extended-command-history)
savehist-autosave-interval 300))
(use-package simple
:straight nil
:hook ((after-init . size-indication-mode)
(text-mode . visual-line-mode)
(helpful-mode . visual-line-mode)
((prog-mode org-mode markdown-mode conf-mode latex-mode) . (lambda () (setq show-trailing-whitespace t))))
:init
(setq column-number-mode t
line-number-mode t
;; kill-whole-line t ; Kill line including '\n'
line-move-visual t
;; track-eol t ; Keep cursor at end of lines. Require line-move-visual is nil.
set-mark-command-repeat-pop t) ; Repeating C-SPC after popping mark pops it again
)
(use-package time
:straight nil
:init (setq display-time-24hr-format t
display-time-day-and-date t))
(use-package so-long
:straight nil
:hook (after-init . global-so-long-mode)
:config (setq so-long-threshold 400))
(use-package adaptive-wrap
:commands adaptive-wrap-prefix-mode)
(use-package keyfreq
:init
(setq keyfreq-file "~/.emacs.d/.keyfreq")
(setq keyfreq-file-lock "~/.emacs.d/.keyfreq.lock")
(keyfreq-mode 1)
(keyfreq-autosave-mode 1)
:config
(setq keyfreq-excluded-commands
'(self-insert-command
org-self-insert-command
forward-char
backward-char
previous-line
next-line))
(setq keyfreq-excluded-regexp
'("\\`vertico-.*\\'"
"\\`iscroll-.*\\'"
"\\`vterm-.*\\'")))
;; Misc
(fset 'yes-or-no-p 'y-or-n-p)
(setq-default major-mode 'emacs-lisp-mode
tab-width 8
indent-tabs-mode nil) ; Permanently indent with spaces, never with TABs
;; flash the modeline for visual bell
(setq visible-bell nil
ring-bell-function 'flash-mode-line)
(setq inhibit-compacting-font-caches t ; Don’t compact font caches during GC.
delete-by-moving-to-trash t ; Deleting files go to OS's trash folder
make-backup-files nil ; Forbide to make backup files
create-lockfiles nil ; Forbide to make lockfiles
auto-save-default nil ; Disable auto save
uniquify-buffer-name-style 'post-forward-angle-brackets ; Show path if names are same
adaptive-fill-regexp "[ t]+|[ t]*([0-9]+.|*+)[ t]*"
adaptive-fill-first-line-regexp "^* *$"
sentence-end-double-space nil)
;; Use the system clipboard
(setq select-enable-clipboard t)
;; Always focus the help window
(setq help-window-select t)
;; Enable mouse in terminal mode
(xterm-mouse-mode)
;; Auto tangle this file after save (without prompt)
(add-hook 'after-save-hook #'org-babel-auto-tangle)
;; Disable scratch buffer text
(setq initial-scratch-message nil)
(provide 'init-basic)
Only prepare the packages here, specific keybindings goes to init-map.el
.
;;; init-general.el --- Initialize general -*- lexical-binding: t -*-
;;; Code:
(use-package key-chord
:diminish
:init
(key-chord-mode))
(use-package general)
(provide 'init-general)
;;; init-ui.el --- Better lookings and appearances. -*- lexical-binding: t -*-
;;; Code:
(defconst solarion-font-size
260
"Font size for default font and modeline")
;; Title
(setq frame-title-format '((:eval (if (buffer-file-name)
(abbreviate-file-name (buffer-file-name))
"%b"))
" "
user-login-name
"@"
system-name)
icon-title-format frame-title-format)
;; Optimization
(setq idle-update-delay 1.0)
(setq-default cursor-in-non-selected-windows nil)
(setq highlight-nonselected-windows nil)
(tooltip-mode -1) ;; Disable tooltips
(set-fringe-mode 10) ;; 左右边框 仅对GUI生效
(global-hl-line-mode t)
;; always split vertically
(setq split-height-threshold nil
split-width-threshold 80)
;; Mode-line
(use-package doom-modeline
:diminish doom-modeline-mode
:init
(setq doom-modeline-modal-icon nil)
;; Must use mono font here
(set-face-attribute 'mode-line nil :font "CaskaydiaCove Nerd Font Mono" :height solarion-font-size)
(set-face-attribute 'mode-line-inactive nil :font "CaskaydiaCove Nerd Font Mono" :height solarion-font-size)
(unless (version< emacs-version "29")
(set-face-attribute 'mode-line-active nil :font "CaskaydiaCove Nerd Font Mono" :height solarion-font-size)) ;; For Emacs 29+
(doom-modeline-mode t))
;; Icons
;; NOTE: Must run `M-x all-the-icons-install-fonts', and install fonts manually on Windows
(use-package all-the-icons)
(use-package display-line-numbers
:straight nil
:init
(setq display-line-numbers-width-start t)
(setq display-line-numbers-current-absolute t)
:config
(dolist (mode '(c-mode-common-hook
c-mode-hook
emacs-lisp-mode-hook
lisp-interaction-mode-hook
lisp-mode-hook
sh-mode-hook
python-mode-hook
html-mode-hook
rust-mode-hook
conf-mode-hook))
(add-hook mode (lambda () (setq display-line-numbers t)))))
;; Suppress GUI features
(setq use-file-dialog nil
use-dialog-box nil
inhibit-startup-screen t
inhibit-startup-echo-area-message t)
;; Display dividers between windows
(setq window-divider-default-places t
window-divider-default-bottom-width 1
window-divider-default-right-width 1)
(add-hook 'window-setup-hook #'window-divider-mode)
(add-to-list 'default-frame-alist '(fullscreen . maximized))
(use-package rainbow-delimiters
:hook
(prog-mode . rainbow-delimiters-mode)
(LaTeX-mode . rainbow-delimiters-mode))
(use-package which-key
:diminish which-key-mode
:hook (after-init . which-key-mode)
:init
(setq which-key-idle-delay 0.2)
(setq which-key-sort-order 'which-key-key-order-alpha)
(setq which-key-prefix-prefix "")
:config
(set-face-attribute 'which-key-group-description-face nil :weight 'bold))
;; (use-package which-key-posframe
;; :init
;; (which-key-posframe-mode)
;; :config
;; (setq which-key-posframe-parameters
;; '((left-fringe . 8)
;; (right-fringe . 8))))
(use-package command-log-mode
:commands command-log-mode)
;; (use-package keycast
;; :after doom-modeline
;; :config
;; (setq keycast-mode-line-insert-after '(:eval (doom-modeline-format--main)))
;; (add-to-list 'global-mode-string '("" keycast-mode-line))
;; (keycast-mode-line-mode))
(use-package helpful
:bind
([remap describe-function] . helpful-callable)
([remap describe-variable] . helpful-variable)
([remap describe-key] . helpful-key))
(use-package winum
:hook (after-init . winum-mode))
(use-package posframe)
(use-package shackle
:hook (after-init . shackle-mode)
:init
(setq shackle-select-reused-windows nil) ; default nil
(setq shackle-default-alignment 'right) ; default below
(setq shackle-select-reused-windows t)
(setq shackle-rules
'(("*vterm*" :size 0.3 :align below :popup t)
;; (compilation-mode :ignore t)
;; ("\\*Async Shell.*\\*" :regexp t :ignore t)
;; ("\\*corfu.*\\*" :regexp t :ignore t)
;; ("*eshell*" :select t :size 0.4 :align t :popup t)
(helpful-mode :size 0.4 :align t :popup t)
(help-mode :size 0.4 :align t :popup t)
;; ("*Messages*" :select t :size 0.4 :align t :popup t)
(magit-status-mode :inhibit-window-quit t :other t)
(magit-log-mode :inhibit-window-quit t :other t)
("\\*Org Src.*\\*" :regexp t :inhibit-window-quit t :other t))))
(provide 'init-ui)
;;; init-themes.el --- Theme related configs goes here. -*- lexical-binding: t -*-
;;; Code:
;; (use-package modus-themes
;; :init
;; (setq modus-themes-italic-constructs t)
;; (setq modus-themes-bold-constructs t)
;; (setq modus-themes-syntax '(alt-syntax green-strings yellow-comments))
;; (setq modus-themes-links '(neutral-underline background))
;; (setq modus-themes-hl-line '(intense))
;; (setq modus-themes-markup '(italic bold intense background))
;; (setq modus-themes-paren-match '(intense))
;; (setq modus-themes-org-blocks nil)
;; (setq modus-themes-completions '((selection . (intense))))
;; :config
;; (modus-themes-load-operandi))
(use-package ef-themes
:straight '(ef-themes :type git :host github :repo "protesilaos/ef-themes")
:init
(setq ef-themes-headings nil)
(setq ef-themes-mixed-fonts nil)
(setq ef-themes-variable-pitch-ui nil)
(ef-themes-select 'ef-cyprus))
(provide 'init-themes)
Use iscroll for image scrolling and pixel-scroll-precision-mode for smooth scrolling (available since emacs 29)
;;; init-scroll.el --- Better scrolling effects. -*- lexical-binding: t -*-
;;; Code:
(setq scroll-preserve-screen-position 'always)
(setq next-screen-context-lines 5)
(use-package iscroll
:init
;; (setq iscroll-preserve-screen-position t)
:hook (org-mode . iscroll-mode))
(when (fboundp 'pixel-scroll-precision-mode)
(pixel-scroll-precision-mode))
(provide 'init-scroll)
The font settings are mainly for GUI Emacs, this would not affect TUI Emacs. font check Chinese: 言 Symbols: ♪ Kana: 夜に駆ける
;;; init-fonts.el --- Fonts configurations (for GUI) -*- lexical-bindings: t -*-
;;; Code:
(defun solarion-config-fonts ()
(when (display-graphic-p)
;; Set default font
(set-face-attribute 'default
nil
:font "CaskaydiaCove Nerd Font Mono"
:height solarion-font-size)
;; Fixed-pitch (monospaced) fonts 等宽字体
(set-face-attribute 'fixed-pitch
nil
:font "CaskaydiaCove Nerd Font Mono"
:height solarion-font-size)
;; CJK fonts
(set-fontset-font t 'han (font-spec :family "Noto Serif CJK SC" :weight 'semi-bold :slant 'normal))
(set-fontset-font t 'cjk-misc (font-spec :family "Noto Serif CJK SC" :weight 'semi-bold :slant 'normal))
(set-fontset-font t 'kana (font-spec :family "Noto Serif CJK JP" :weight 'semi-bold :slant 'normal))
;; Emoji
(set-fontset-font t 'symbol (font-spec :family "Noto Color Emoji") nil 'prepend)))
(solarion-config-fonts)
(add-hook 'window-setup-hook #'solarion-config-fonts)
(add-hook 'server-after-make-frame-hook #'solarion-config-fonts)
;; https://github.com/mickeynp/ligature.el
(use-package ligature
:straight '(ligature :type git :host github :repo "mickeynp/ligature.el")
:config
;; Enable the "www" ligature in every possible major mode
(ligature-set-ligatures 't '("www"))
;; Enable traditional ligature support in eww-mode, if the
;; `variable-pitch' face supports it
(ligature-set-ligatures 'eww-mode '("ff" "fi" "ffi"))
;; Enable all Cascadia Code ligatures in programming modes
(ligature-set-ligatures 'prog-mode '("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>"
":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!=="
"!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<"
"<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
"<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<"
"..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
"~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
"[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
"<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!"
"##" "#(" "#?" "#_" "%%" ".=" ".-" ".." ".?" "+>" "++" "?:"
"?=" "?." "??" ";;" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)"
"\\\\" "://"))
;; Enables ligature checks globally in all buffers. You can also do it
;; per mode with `ligature-mode'.
(global-ligature-mode t))
(provide 'init-fonts)
;;; init-edit.el --- Initialize editing configurations -*- lexical-binding: t -*-
;;; Code:
;; Automatically reload files was modified by external program
(use-package autorevert
:straight nil
:diminish
:init
(setq global-auto-revert-non-file-buffers t
auto-revert-interval 1)
(global-auto-revert-mode))
(use-package auto-save
:straight '(auto-save :type git :host github :repo "manateelazycat/auto-save")
:config
(auto-save-enable)
(setq auto-save-silent t) ; quietly save
(setq auto-save-delete-trailing-whitespace t) ; automatically delete spaces at the end of the line when saving
)
(use-package format-all
:commands (format-all-buffer format-all--language-id-buffer))
;; Jump to things in Emacs tree-style
(use-package avy
:hook (after-init . avy-setup-default)
:config (setq avy-all-windows t
avy-background t
avy-style 'at-full
avy-timeout-seconds 0.5))
(use-package beginend
:diminish beginend-global-mode
:hook (after-init . beginend-global-mode))
;; A comprehensive visual interface to diff & patch
(use-package ediff
:straight nil
:hook (;; show org ediffs unfolded
(ediff-prepare-buffer . outline-show-all)
;; restore window layout when done
;; (ediff-quit . winner-undo)
)
:config
(setq ediff-window-setup-function 'ediff-setup-windows-plain
ediff-split-window-function 'split-window-vertically
ediff-merge-split-window-function 'split-window-vertically))
;; Increase selected region by semantic units
(use-package expand-region
:commands er/expand-region)
;; Hungry deletion
(use-package hungry-delete
:diminish
:hook (after-init . global-hungry-delete-mode)
:init (setq hungry-delete-except-modes '(help-mode minibuffer-mode minibuffer-inactive-mode calc-mode)
hungry-delete-chars-to-skip "
\f�"))
;; Move to the beginning/end of line or code
(use-package mwim
:config
(general-def "C-a" #'mwim-beginning-of-code-or-line)
(general-def "C-e" #'mwim-end-of-code-or-line))
(general-def "C-/" #'undo-only)
(general-def "C-r" #'undo-redo)
;; vundo
(use-package vundo
:config
(general-def "C-x u" #'vundo)
(general-def "C-x r" #'vundo)
(general-def vundo-mode-map "C-n" #'vundo-next)
(general-def vundo-mode-map "C-p" #'vundo-previous)
(general-def vundo-mode-map "C-f" #'vundo-forward)
(general-def vundo-mode-map "C-b" #'vundo-backward)
(setq vundo-glyph-alist vundo-unicode-symbols))
;; Handling capitalized subwords in a nomenclature
(use-package subword
:straight nil
:diminish
:hook ((prog-mode . subword-mode)
(minibuffer-setup . subword-mode)))
(use-package sudo-edit
:commands (sudo-edit-find-file sudo-edit-current-file))
;; On-the-fly spell checker
(use-package flyspell
:straight nil
:diminish
:if (executable-find "aspell")
:hook
(((text-mode outline-mode) . flyspell-mode)
(prog-mode . flyspell-prog-mode)
(LaTeX-mode . flyspell-mode)
(flyspell-mode . (lambda ()
(dolist (key '("C-;" "C-," "C-."))
(unbind-key key flyspell-mode-map)))))
:init
(setq flyspell-issue-message-flag nil
ispell-program-name "aspell"
ispell-extra-args '("--sug-mode=ultra" "--lang=en_US" "--run-together")))
;; Framework for mode-specific buffer indexes
(use-package imenu
:straight nil
:init
(setq imenu-auto-rescan t))
;; 中英文间自动加入空格
(use-package pangu-spacing
:diminish global-pangu-spacing-mode
:init
(global-pangu-spacing-mode 1)
(setq pangu-spacing-real-insert-separtor t))
;; occur
(add-hook 'occur-hook (lambda () (switch-to-buffer-other-window "*Occur*")))
;; smartparens
(use-package smartparens
:diminish
:config
(require 'smartparens-config)
(add-hook 'org-mode-hook #'smartparens-mode)
(add-hook 'LaTeX-mode-hook #'smartparens-mode)
(add-hook 'emacs-lisp-mode-hook #'smartparens-mode)
;; custom pairs
(with-eval-after-load 'org
(sp-local-pair 'org-mode "\\[" "\\]")
(sp-local-pair 'org-mode "=" nil :actions :rem)
(sp-local-pair 'org-mode "/" nil :actions :rem)))
(use-package lorem-ipsum)
;; (treesit-auto-install-all)
(use-package treesit-auto
:config
(global-treesit-auto-mode)
(setq treesit-font-lock-level 4))
(provide 'init-edit)
;;; init-hydra.el --- Hydra configurations -*- lexical-binding: t -*-
;;; Code:
(use-package hydra
:config
(defhydra hydra-window-resize (:timeout 4)
"Resize window"
("j" enlarge-window "Increase height")
("k" shrink-window "Decrease height")
("h" shrink-window-horizontally "Decrease width")
("l" enlarge-window-horizontally "Increase width")
("SPC" balance-windows "Balance windows")
("q" nil "quit" :exit t)))
(provide 'init-hydra)
Define the majority of keybindings here.
;;; init-map.el --- Keybindings -*- lexical-binding: t -*-
;;; Code:
;; misc
(general-def [f10] #'solarion/indent-buffer-and-format) ;; f12 reserved for yakuake
(general-def [f5] #'revert-buffer)
(general-def ";" (general-key-dispatch 'self-insert-command
:timeout 0.25
"'" #'comment-line))
(general-def "j" (general-key-dispatch 'self-insert-command
:timeout 0.25
"k" (general-key "C-g")))
(general-def "k" (general-key-dispatch 'self-insert-command
:timeout 0.25
"j" #'avy-goto-char-timer))
(general-def :keymaps 'override "C-c k" #'copy-line)
(general-unbind "M-`") ;; reserved for tmux
(general-create-definer global-leader-def
:keymaps 'override
:prefix "C-c")
(general-create-definer local-leader-def
:keymaps 'override
:prefix "C-c m")
;; Global leader
(global-leader-def
;; maps
"h" #'(help-command :which-key "Help")
"p" #'(projectile-command-map :which-key "Projectile")
;; keys
"C-." #'consult-imenu ;; "C-c ." for org-time-stamp
"=" #'er/expand-region
"C-s" #'consult-ripgrep
"C-SPC" #'consult-mark
;; window
"w" '(:ignore t :which-key "Window")
"ws" #'split-window-below-and-focus
"wv" #'split-window-right-and-focus
"wd" #'(delete-window :which-key "Delete window")
"wq" #'(kill-buffer-and-window :which-key "Kill buffer and window")
"wr" #'(hydra-window-resize/body :which-key "Window Resize")
"w=" #'(balance-windows :which-key "Balance Windows")
"1" #'(winum-select-window-1 :which-key "Switch to window 1")
"2" #'(winum-select-window-2 :which-key "Switch to window 2")
"3" #'(winum-select-window-3 :which-key "Switch to window 3")
"4" #'(winum-select-window-4 :which-key "Switch to window 4")
"5" #'(winum-select-window-5 :which-key "Switch to window 5")
;; buffer & bookmark
"b" '(:ignore t :which-key "Buffer/Bookmark")
"bp" #'(previous-buffer :which-key "Previous Buffer")
"bn" #'(next-buffer :which-key "Next Buffer")
"bb" #'(consult-buffer :which-key "Switch Buffer")
"bc" #'(clone-indirect-buffer :which-key "Clone Buffer")
"bd" #'(kill-current-buffer :which-key "Kill Buffer")
"bi" #'ibuffer
"bm" #'(bookmark-set :which-key "Set Bookmark")
"bM" #'(bookmark-delete :which-key "Delete Bookmark")
"bj" #'(consult-bookmark :which-key "Jump to Bookmark")
"bl" #'(list-bookmarks :which-key "Bookmarks List")
"bN" #'(solarion-new-buffer :which-key "New Empty Buffer")
"br" #'(revert-buffer :which-key "Revert Buffer")
;; file
"f" '(:ignore t :which-key "File")
"fd" #'(dired-jump :which-key "Dired Jump")
"fD" #'(delete-file-and-buffer :which-key "Delete File")
"ff" #'(find-file :which-key "Find File")
"fs" #'(save-buffer :which-key "Save File")
"fS" #'(write-file :which-key "Save File As")
"fr" #'(consult-recent-file :which-key "Recent Files")
"fp" #'(solarion-edit-config :which-key "Edit Config")
;; quit
"q" '(:ignore t :which-key "Quit")
"qf" #'(delete-frame :which-key "Delete Frame")
"qq" #'(save-buffers-kill-terminal :which-key "Quit Emacs")
;; roam
"r" '(:ignore t :which-key "Roam")
"ra" #'org-roam-node-random
"rr" #'org-roam-buffer-toggle
"rf" #'org-roam-node-find
"rg" #'org-roam-graph
"ri" #'org-roam-node-insert
"rc" #'org-roam-capture
"rs" #'solarion/org-roam-rg-search
"rS" #'org-roam-db-sync
"ro" '(:ignore t :which-key "Node Properties")
"roa" #'org-roam-alias-add
"roA" #'org-roam-alias-remove
"ror" #'org-roam-ref-add
"roR" #'org-roam-ref-remove
"rot" #'org-roam-tag-add
"roT" #'org-roam-tag-remove
;; git
"g" '(:ignore t :which-key "Git")
"gR" #'vc-revert
"g/" #'magit-dispatch
"g." #'magit-file-dispatch
;; "g'" #'forge-dispatch
"gb" #'magit-branch-checkout
"gg" #'magit-status
"gG" #'solarion/git-add-commit-push
"gD" #'magit-file-delete
"gB" #'magit-blame
"gC" #'magit-clone
"gF" #'magit-fetch
"gL" #'magit-log-buffer-file
"gS" #'magit-stage-file
"gU" #'magit-unstage-file
"gf" '(:ignore t :which-key "find")
"gff" #'magit-find-file
"gfg" #'magit-find-git-config-file
"gfc" #'magit-show-commit
;; "gfi" #'forge-visit-issue
;; "gfp" #'forge-visit-pullreq
"gl" '(:ignore t :which-key "list")
"glr" #'magit-list-repositories
"gls" #'magit-list-submodules
;; "gli" #'forge-list-issues
;; "glp" #'forge-list-pullreqs
;; "gln" #'forge-list-notifications
"gc" '(:ignore t :which-key "create")
"gcr" #'magit-init
"gcR" #'magit-clone
"gcc" #'magit-commit-create
"gcf" #'magit-commit-fixup
"gcb" #'magit-branch-and-checkout
;; "gci" #'forge-create-issue
;; "gcp" #'forge-create-pullreq
;; custom
"o" '(:ignore t :which-key "Custom Entry")
"oT" #'(consult-theme :which-key "Choose Theme")
"ot" #'(ef-themes-load-random :which-key "Random Theme")
"oo" #'occur
"of" #'(fanyi-dwim :which-key "Dict")
"oy" #'yadm
;; "ok" #'(keycast-mode-line-mode :which-key "Keycast")
)
;; Local leader
;; org-mode
(local-leader-def org-mode-map
"," #'org-switchb
"." #'consult-org-heading
"b" #'org-mark-ring-goto
"a" '(:ignore t :which-key "Attach")
"aa" #'org-attach
"ap" #'solarion/org-download-paste-clipboard-wsl
"e" #'(org-export-dispatch :which-key "Export")
"d" '(:ignore t :which-key "Date")
"dd" #'org-deadline
"ds" #'org-schedule
"dt" #'org-time-stamp
"dT" #'org-time-stamp-inactive
"f" #'org-footnote-action
"h" #'org-toggle-heading
"i" #'org-toggle-item
"r" '(:ignore t :which-key "Roam")
"ra" #'org-roam-node-random
"rr" #'org-roam-buffer-toggle
"rf" #'org-roam-node-find
"rg" #'org-roam-graph
"ri" #'org-roam-node-insert
"rc" #'org-roam-capture
"rs" #'solarion/org-roam-rg-search
"rS" #'org-roam-db-sync
"ro" '(:ignore t :which-key "Node Properties")
"roa" #'org-roam-alias-add
"roA" #'org-roam-alias-remove
"ror" #'org-roam-ref-add
"roR" #'org-roam-ref-remove
"rot" #'org-roam-tag-add
"roT" #'org-roam-tag-remove
"p" '(:ignore t :which-key "Priority")
"pd" #'org-priority-down
"pp" #'org-priority
"pu" #'org-priority-up
"R" #'org-refile
"t" #'org-todo
"x" #'org-toggle-checkbox)
(general-def help-map
;; new keybinds
"'" #'describe-char
;; Unbind `help-for-help'. Conflicts with which-key's help command for the
;; <leader> h prefix. It's already on ? and F1 anyway.
"C-h" nil
;; replacement keybinds
;; replaces `info-emacs-manual' b/c it's on C-m now
"r" nil
"b" #'describe-bindings
"B" #'general-describe-keybindings
;; replaces `apropos-command'
"a" #'apropos
"A" #'apropos-documentation
;; replaces `describe-copying' b/c not useful
"C-c" #'describe-coding-system
;; replaces `Info-got-emacs-command-node' b/c redundant w/ `Info-goto-node'
"F" #'describe-face
;; replaces `view-hello-file' b/c annoying
"h" nil
;; replaces `help-with-tutorial', b/c it's less useful than `load-theme'
"t" #'consult-theme
;; replaces `finder-by-keyword' b/c not useful
"p" nil)
(provide 'init-map)
The bundle of vertico, consult, orderless, marginalia and embark
;;; init-vertico.el --- Initialize the vertico bundle -*- lexical-binding: t -*-
;;; Code:
(use-package vertico
:straight (vertico :files (:defaults "extensions/*"))
:init
(vertico-mode)
(setq vertico-scroll-margin 2)
;; Show 10 candidates
(setq vertico-count 10)
;; Optionally enable cycling for `vertico-next' and `vertico-previous'.
(setq vertico-cycle t))
;; (use-package vertico-posframe
;; :after vertico
;; :init
;; (vertico-posframe-mode 1)
;; (setq vertico-posframe-parameters
;; '((left-fringe . 8)
;; (right-fringe . 8))))
(use-package vertico-directory
:after vertico
:straight nil
;; More convenient directory navigation commands
:bind (:map vertico-map
("RET" . vertico-directory-enter)
("DEL" . vertico-directory-delete-char)
("C-DEL" . vertico-directory-delete-word))
;; Tidy shadowed file names
:hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
(use-package all-the-icons-completion
:after (marginalia all-the-icons)
:hook (marginalia-mode . all-the-icons-completion-marginalia-setup)
:init
(all-the-icons-completion-mode))
(use-package pinyinlib
:after orderless
:config
(defun completion--regex-pinyin (str)
(orderless-regexp (pinyinlib-build-regexp-string str)))
(add-to-list 'orderless-matching-styles 'completion--regex-pinyin))
(use-package orderless
:init
;; Configure a custom style dispatcher (see the Consult wiki)
;; (setq orderless-style-dispatchers '(+orderless-dispatch)
;; orderless-component-separator #'orderless-escapable-split-on-space)
(setq completion-styles '(basic orderless)
completion-category-defaults nil
completion-category-overrides '((file (styles basic partial-completion)))))
;; Enable richer annotations using the Marginalia package
(use-package marginalia
;; Either bind `marginalia-cycle` globally or only in the minibuffer
;; The :init configuration is always executed (Not lazy!)
:init
;; Must be in the :init section of use-package such that the mode gets
;; enabled right away. Note that this forces loading the package.
(marginalia-mode))
(use-package consult
:bind
("C-s" . consult-line)
([remap switch-to-buffer] . consult-buffer)
([remap yank-pop] . consult-yank-pop)
:config
(setq consult-fontify-preserve nil))
(use-package embark
:bind
("C-." . embark-act)
("M-." . embark-dwim)
;; Optionally replace the key help with a completing-read interface
:init
(setq prefix-help-command #'embark-prefix-help-command))
(use-package embark-consult
:after (embark consult)
:demand t
;; only necessary if you have the hook below
;; if you want to have consult previews as you move around an
;; auto-updating embark collect buffer
:hook
(embark-collect-mode . consult-preview-at-point-mode))
(use-package wgrep)
(provide 'init-vertico)
Corfu enhances completion at point with a small completion popup. The current candidates are shown in a popup below or above the point. Corfu is the minimalistic completion-in-region counterpart of the Vertico minibuffer UI.
;;; init-corfu.el --- Completion Overlay Region FUnction -*- lexical-binding: t -*-
;;; Code:
(use-package corfu
:straight (corfu :files (:defaults "extensions/*"))
:init
;; built-in configurations
(setq completion-cycle-threshold 5)
;; Enable indentation+completion using the TAB key.
(setq tab-always-indent 'complete)
;; Emacs 28: Hide commands in M-x which do not apply to the current mode.
;; Corfu commands are hidden, since they are not supposed to be used via M-x.
(setq read-extended-command-predicate #'command-completion-default-include-p)
;; corfu settings
(setq corfu-cycle t)
(setq corfu-auto t)
(setq corfu-auto-prefix 2)
(setq corfu-auto-delay 0)
(setq corfu-count 7)
(setq corfu-preselect-first nil) ;; tab for complete common
(global-corfu-mode)
;; corfu quick
(setq corfu-quick1 "asdf")
(setq corfu-quick2 "jkl")
(general-def corfu-map "`" #'corfu-quick-complete)
)
(use-package cape
:init
;; Add `completion-at-point-functions', used by `completion-at-point'.
(setq cape-dabbrev-check-other-buffers nil) ;; only check current buffer for completion
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
(add-to-list 'completion-at-point-functions #'cape-file))
(provide 'init-corfu)
Tempel is a tiny template package for Emacs, which uses the syntax of the Emacs Tempo library. A substitute for yasnippet.
;;; init-tempel.el --- Simple templates for Emacs -*- lexical-binding: t -*-
;;; Code:
;; Configure Tempel
(use-package tempel
:bind
(:map tempel-map
("TAB" . tempel-next))
:init
(setq tempel-path (concat user-emacs-directory "tempel-templates/*.eld"))
(setq tempel-trigger-prefix "<")
;; Setup completion at point
(defun tempel-setup-capf ()
;; Add the Tempel Capf to `completion-at-point-functions'.
;; `tempel-expand' only triggers on exact matches. Alternatively use
;; `tempel-complete' if you want to see all matches, but then you
;; should also configure `tempel-trigger-prefix', such that Tempel
;; does not trigger too often when you don't expect it. NOTE: We add
;; `tempel-expand' *before* the main programming mode Capf, such
;; that it will be tried first.
(setq-local completion-at-point-functions
(cons #'tempel-complete
completion-at-point-functions)))
(add-hook 'prog-mode-hook 'tempel-setup-capf)
(add-hook 'text-mode-hook 'tempel-setup-capf))
(provide 'init-tempel)
;;; init-magit.el --- Configuration related to git -*- lexical-binding: t -*-
;;; Code:
(use-package magit
:bind
(:map magit-mode-map
("p" . magit-push))
:init
(setq magit-display-buffer-function #'magit-display-buffer-traditional
git-commit-major-mode 'org-mode))
(use-package diff-hl
:diminish
:init
(global-diff-hl-mode)
(add-hook 'magit-pre-refresh-hook 'diff-hl-magit-pre-refresh)
(add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh))
(provide 'init-magit)
;;; init-ibuffer.el --- Initialize ibuffer configurations -*- lexical-binding: t -*-
;;; Code:
(use-package ibuffer
:straight nil
:hook (ibuffer-mode . (lambda () (ibuffer-auto-mode 1) (ibuffer-switch-to-saved-filter-groups "custom")))
:custom
(ibuffer-show-empty-filter-groups nil)
(ibuffer-saved-filter-groups
'(("custom"
("Dired" (mode . dired-mode))
("Org" (mode . org-mode))
("Emacs" (or
(name . "^\\*scratch\\*$")
(name . "^\\*Backtrace\\*$")
(name . "^\\*Messages\\*$")))
("Help" (or
(name . "Help")
(name . "^helpful")))
("Magit" (name . "^magit"))
))))
(provide 'init-ibuffer)
Clean inactive buffers.
;;; init-midnight.el --- Configurations for midnight -*- lexical-binding: t -*-
;;; Code:
;; use `clean-buffer-list' from `midngiht.el'
(use-package midnight
:after (dashboard vterm minimap)
:config
;;kill buffers if they were last disabled more than this seconds ago
(setq clean-buffer-list-delay-special (* 3 60 60))
(defvar clean-buffer-list-timer nil
"Stores clean-buffer-list timer if there is one. You can disable clean-buffer-list by (cancel-timer clean-buffer-list-timer).")
;; run clean-buffer-list every 30 minites
(setq clean-buffer-list-timer (run-at-time t 1800 'clean-buffer-list))
;; kill everything, clean-buffer-list is very intelligent at not killing
;; unsaved buffer.
;; 满足条件且超过`clean-buffer-list-delay-special'的buffer才会被清除
(setq clean-buffer-list-kill-regexps '("^.*$"))
(defvar solarion-clean-buffer-list-kill-never-buffer-names
`("*httpd*" "*Messages" "*Backtrace*" "*scratch*" "*Ibuffer*" ,dashboard-buffer-name ,vterm-buffer-name ,minimap-buffer-name)
"buffer names not to kill")
(dolist (buf solarion-clean-buffer-list-kill-never-buffer-names)
(add-to-list 'clean-buffer-list-kill-never-buffer-names buf))
(defvar solarion-clean-buffer-list-kill-never-regexps
nil
"regexps not to kill")
(dolist (buf solarion-clean-buffer-list-kill-never-regexps)
(add-to-list 'clean-buffer-list-kill-never-regexps buf)))
(provide 'init-midnight)
;;; init-tramp.el --- Tramp settings -*- lexical-binding: t -*-
;;; Code:
(use-package tramp
:straight (:type built-in)
:config
(add-to-list 'tramp-methods
'("yadm"
(tramp-login-program "yadm")
(tramp-login-args (("enter")))
(tramp-login-env (("SHELL") ("/bin/sh")))
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-args ("-c"))))
(defun yadm ()
(interactive)
(magit-status "/yadm::")))
(provide 'init-tramp)
;;; init-org.el --- Org-mode -*- lexical-binding: t -*-
;;; Code:
(use-package org
:straight (:type built-in)
:hook
(org-mode . solarion/org-mode-setup)
:config
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(shell . t)
(latex . t)
(python . t)
(matlab . t)
(gnuplot . t)))
(setq org-startup-with-inline-images nil)
(setq org-startup-with-latex-preview nil)
(setq org-startup-numerated t);; Start org-mode numbered
(setq org-adapt-indentation t);; add indentation for newlines
(setq org-highlight-latex-and-related '(native script entities))
(setq org-directory "~/org")
(setq org-ellipsis "\t[+]")
(setq org-tags-column -80)
(setq org-log-done 'time)
(setq org-hide-emphasis-markers nil) ;; Show bold and italic verbosely
(setq org-link-descriptive t) ;; Show links verbosely
(setq org-hide-leading-stars t)
;; export settings
(setq org-export-with-tags nil)
(setq org-export-with-sub-superscripts '{})
;; latex settings
(setq org-latex-compiler "xelatex")
(setq org-latex-hyperref-template "\\hypersetup{\n pdfauthor={%a},\n pdftitle={%t},\n pdfkeywords={%k},\n pdfsubject={%d},\n colorlinks=true,\n linkcolor=black\n}\n")
;; set table of contents level
(setq org-export-with-toc 3)
(setq org-latex-toc-command "\\pagestyle{empty}\n\\tableofcontents\n\\clearpage\n\n\\setcounter{page}{1}\n\\pagestyle{plain}\n\n")
;; maketitle command
(setq org-latex-title-command "\\maketitle\n\\thispagestyle{empty}")
;; size of the preview latex fragments
(plist-put org-format-latex-options :scale 2)
(general-def org-src-mode-map "C-c C-c" #'org-edit-src-exit)
(general-def org-mode-map "C-RET" #'org-meta-return)
(general-def org-mode-map "C-<return>" #'org-meta-return)
;; org latex packages
(setq org-latex-packages-alist
'(("" "siunitx")
("" "mathrsfs")
("scheme=plain" "ctex")
;; mlmodern is thicker
;; ("" "mlmodern")
("" "lmodern")
("T1" "fontenc")))
(setq org-image-actual-width t)
(setq org-preview-latex-image-directory (concat user-emacs-directory ".local/ltximg/"))
(general-def [remap org-return] #'(lambda () (interactive) (org-return electric-indent-mode)))
)
(use-package ox-gfm
:config (add-to-list 'org-export-backends 'md))
(use-package org-superstar
:diminish org-superstar-mode
:hook (org-mode . (lambda () (org-superstar-mode)))
:init
(setq
org-superstar-headline-bullets-list '("■" "◆" "▲" "▶")
org-superstar-cycle-headline-bullets nil
org-superstar-prettify-item-bullets nil))
(use-package org-download
:defer t
:config
(org-download-enable)
(setq
org-download-method 'directory
org-download-image-dir "images"
org-download-heading-lvl nil
org-download-timestamp "%Y%m%d-%H%M%S_")
;; to change image width seperately (also hide the annotate #+DOWNLOADED)
(setq org-download-annotate-function (lambda (_link) "#+ATTR_LATEX: :width \\linewidth\n")))
(use-package org-roam
:diminish
:init
(setq
org-roam-v2-ack t
org-roam-directory (file-truename "~/org-roam/")
org-id-locations-file (file-truename "~/org-roam/.orgids"))
(add-to-list 'display-buffer-alist
'("\\*org-roam\\*"
(display-buffer-in-direction)
(direction . right)
(window-width . 0.33)
(window-height . fit-window-to-buffer)))
:config
(unless (file-exists-p org-roam-directory)
(make-directory org-roam-directory))
(setq org-roam-capture-templates
'(("d" "Default" plain
"%?"
:target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+date: %u\n")
:unnarrowed t)
("r" "Research Note" plain
(file "~/org-roam/Templates/ResearchNoteTemplate.org")
:target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+date: %u\n")
:unnarrowed t)))
(defun solarion/org-roam-rg-search ()
"Search org-roam directory using consult-ripgrep. With live-preview."
(interactive)
(let ((consult-ripgrep-command "rg --null --ignore-case --type org --line-buffered --color=always --max-columns=500 --no-heading --line-number . -e ARG OPTS"))
(consult-ripgrep org-roam-directory)))
(setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
(org-roam-db-autosync-mode))
;; Automatically insert table of contents after the heading with :TOC: tag
(use-package toc-org
:hook (org-mode . toc-org-mode))
;; Auto-toggle Org LaTeX fragments
(use-package org-fragtog)
;; matlab mode, currently only for org mode, could be separated
;; the package name is matlab, yet it provides `matlab'
(use-package matlab
:straight matlab-mode
:diminish
:config
(add-to-list 'auto-mode-alist '("\\.m\\'" . matlab-mode))
(setq matlab-indent-function t)
(setq matlab-shell-command "matlab"))
;; gnuplot mode, currently only for org mode, could be separated
(use-package gnuplot
:diminish
:config
(add-to-list 'auto-mode-alist '("\\.gp$" . gnuplot-mode)))
(use-package org-roam-ui
:config
(setq org-roam-ui-sync-theme t
org-roam-ui-follow t
org-roam-ui-update-on-save t
org-roam-ui-open-on-start nil))
(use-package ox-hugo
:after ox)
(provide 'init-org)
;;; init-latex.el --- Initialize LaTeX settings -*- lexical-binding: t -*-
;; GhostScript is needed for previewing latex fragments
;;; Code:
;; Note that it *must* be 'use-package latex', if 'auctex' is used instead,
;; 'auctex.el' is never called later, and the :config section is not set.
;; Many (most?) people use 'use-package tex', which is fine and probably
;; more "correct", but then care would have to be taken with variables which
;; are not defined in 'tex.el' (starting with "TeX-"), but in 'latex.el'
;; (starting with "LaTeX-"). As 'latex.el' requires 'tex.el', simply setting
;; 'use-package latex' catches all in one go.
(use-package latex
:straight auctex
:config
(setq
LaTeX-electric-left-right-brace t
TeX-parse-self t ;; parse onload
TeX-auto-save t ;; parse on save
;; use hidden dirs for auctex files
TeX-auto-local ".auctex-auto"
TeX-style-local ".auctex-style"
TeX-source-correlate-method 'synctex
;; don't start the emacs server when correlating sources
TeX-source-correlate-start-server nil
;; just save, dont ask me before each compilation
TeX-save-query nil)
(setq-default TeX-engine 'xetex)
(setq preview-default-option-list '("displaymath" "floats" "graphics" "textmath" "footnotes"))
;; (setq preview-scale-function 1.5)
(add-to-list 'auto-mode-alist '("\\.tex\\'" . LaTeX-mode))
(TeX-source-correlate-mode))
(use-package auctex-latexmk
:straight '(auctex-latexmk :type git :host github :fork "wang1zhen/auctex-latexmk")
:hook (LaTeX-mode . (lambda ()
(setq TeX-command-default "LatexMk")))
:config
(setq auctex-latexmk-inherit-TeX-PDF-mode t)
(auctex-latexmk-setup))
(provide 'init-latex)
;;; init-dired.el --- Emacs built in file manager -*- lexical-binding: t -*-
;;; Code:
(use-package dired
:straight nil
:commands (dired dired-jump)
:config
(general-def dired-mode-map "C-c C-p" #'wdired-change-to-wdired-mode)
(setq dired-listing-switches "-alh --group-directories-first"
dired-dwim-target t
dired-recursive-deletes 'always
dired-recursive-copies 'always))
(use-package dired-rsync
:after dired
:config
(general-def dired-mode-map "C-c C-r" #'dired-rsync))
;; Colourful dired
(use-package diredfl
:after dired
:config (diredfl-global-mode 1))
(use-package dired-single
:after dired
:bind
(:map dired-mode-map
([remap dired-find-file] . dired-single-buffer)
([remap dired-mouse-find-file-other-window] . dired-single-buffer-mouse)
([remap dired-up-directory] . dired-single-up-directory)))
(use-package dired-hide-dotfiles
:after dired
:hook (dired-mode . dired-hide-dotfiles-mode)
:config
(general-def dired-mode-map "H" 'dired-hide-dotfiles-mode))
(provide 'init-dired)
;;; init-projectile.el --- Projectile configurations -*- lexical-binding: t -*-
;;; Code:
(use-package projectile
:diminish
:hook (after-init . projectile-mode)
:init
(setq solarion-projectile-dir "~/solarion-emacs")
(when (file-directory-p solarion-projectile-dir)
(setq projectile-project-search-path `(,(file-truename solarion-projectile-dir))))
(setq projectile-switch-project-action #'projectile-dired)
:config
(setq projectile-mode-line-prefix nil
projectile-sort-order 'recentf
projectile-use-git-grep t))
(provide 'init-projectile)
;;; init-dashboard.el --- Setup for the splash screen (dashboard) -*- lexical-binding: t -*-
;;; Code:
(use-package dashboard
:diminish
:init
(defun solarion-init-time ()
"Showing Emacs initializing time, packages loaded and GC"
(format "Loaded %d packages in %.2f ms."
(- (length load-path) (length (get 'load-path 'initial-value)))
(* 1e3 (float-time (time-subtract after-init-time before-init-time)))))
(setq dashboard-init-info (solarion-init-time))
(setq dashboard-banner-logo-title (concat "Emacs " emacs-version)
dashboard-startup-banner "~/.emacs.d/logo.png"
dashboard-image-banner-max-height 400
dashboard-page-separator "\n\n"
dashboard-center-content t
dashboard-show-shortcuts t
dashboard-items '((recents . 5)
(bookmarks . 5)
(projects . 3))
dashboard-startupify-list '(dashboard-insert-banner
dashboard-insert-newline
dashboard-insert-banner-title
dashboard-insert-newline
dashboard-insert-navigator
dashboard-insert-newline
dashboard-insert-init-info
dashboard-insert-items)
dashboard-navigator-buttons `(((nil "Homepage (H)" "Browse homepage" solarion-homepage)
(nil "Restore (R)" "Restore previous session" (lambda (&rest _) (restore-previous-session)))
(nil "Config (C)" "Open custom file" solarion-edit-config)
(nil "Update (U)" "Update Packages" (lambda (&rest _) (straight-pull-all))))))
(when (< (length command-line-args) 2)
(setq initial-buffer-choice 'dashboard-open))
:config
(dashboard-setup-startup-hook)
(general-def dashboard-mode-map
"H" #'solarion-homepage
"R" #'restore-previous-session
"C" #'solarion-edit-config
"U" #'straight-pull-all))
(provide 'init-dashboard)
;;; init-vterm.el --- Emacs libvterm integration -*- lexical-binding: t -*-
;;; Code:
(when (and module-file-suffix ;; dynamic module
(executable-find "cmake")
(executable-find "libtool") ;; install libtool-bin
(executable-find "make"))
(use-package vterm
:init
(setq vterm-always-compile-module t)
:bind (:map vterm-mode-map
("C-\\" . toggle-input-method)
("C-q" . vterm-send-next-key)))
(use-package vterm-toggle
:bind
([f2] . vterm-toggle)
([C-f2] . vterm-toggle-cd)
(:map vterm-mode-map
("C-<return>" . vterm-toggle-insert-cd)
([f2] . vterm-toggle))))
(provide 'init-vterm)
Restore previous session.
;;; init-persp.el --- Configurations for persp-mode -*- lexical-binding: t -*-
;;; Code:
(use-package persp-mode
:diminish
:hook
((after-init . persp-mode)
(persp-mode . persp-load-frame)
(kill-emacs . persp-save-frame))
:init
(setq persp-keymap-prefix nil
persp-nil-name "default"
persp-set-last-persp-for-new-frames nil
persp-kill-foreign-buffer-behaviour 'kill
persp-auto-resume-time 0)
:config
;; Save and load frame parameters (size & position)
(defvar persp-frame-file (expand-file-name "persp-frame" persp-save-dir)
"File of saving frame parameters.")
(defun persp-save-frame ()
"Save the current frame parameters to file."
(interactive)
(when (and (display-graphic-p) persp-mode)
(condition-case error
(with-temp-buffer
(erase-buffer)
(insert
";;; -*- mode: emacs-lisp; coding: utf-8-unix -*-\n"
";;; This is the previous frame parameters.\n"
";;; Last generated " (current-time-string) ".\n"
"(setq initial-frame-alist\n"
(format " '((top . %d)\n" (eval (frame-parameter nil 'top)))
(format " (left . %d)\n" (eval (frame-parameter nil 'left)))
(format " (width . %d)\n" (eval (frame-parameter nil 'width)))
(format " (height . %d)\n" (eval (frame-parameter nil 'height)))
(format " (fullscreen . %s)))\n" (frame-parameter nil 'fullscreen)))
(write-file persp-frame-file))
(error
(warn "persp frame: %s" (error-message-string error))))))
(defun persp-load-frame ()
"Load frame with the previous frame's geometry."
(interactive)
(when (and (display-graphic-p) persp-mode)
(condition-case error
(progn
(load persp-frame-file)
;; Handle multiple monitors gracefully
(when (or (>= (eval (frame-parameter nil 'left)) (display-pixel-width))
(>= (eval (frame-parameter nil 'top)) (display-pixel-height)))
(set-frame-parameter nil 'left 0)
(set-frame-parameter nil 'top 0)))
(error
(warn "persp frame: %s" (error-message-string error))))))
(defun restore-previous-session ()
"Restore the previous session."
(interactive)
(when (bound-and-true-p persp-mode)
(restore-session persp-auto-save-fname)))
(defun restore-session (fname)
"Restore the specified session."
(interactive (list (read-file-name "Load perspectives from a file: "
persp-save-dir)))
(when (bound-and-true-p persp-mode)
(message "Restoring session...")
(quit-window t)
(condition-case-unless-debug err
(persp-load-state-from-file fname)
(error "Error: Unable to restore session -- %s" err))
(message "Restoring session...done")))
;; Don't save dead or temporary buffers
(add-hook 'persp-filter-save-buffers-functions
(lambda (b)
"Ignore dead and unneeded buffers."
(or (not (buffer-live-p b))
(string-prefix-p " *" (buffer-name b)))))
(add-hook 'persp-filter-save-buffers-functions
(lambda (b)
"Ignore temporary buffers."
(let ((bname (file-name-nondirectory (buffer-name b))))
(or (string-prefix-p ".newsrc" bname)
(string-prefix-p "magit" bname)
(string-prefix-p "COMMIT_EDITMSG" bname)
(string-prefix-p "Pfuture-Callback" bname)
(string-prefix-p "treemacs-persist" bname)
(string-match-p "\\.elc\\|\\.tar\\|\\.gz\\|\\.zip\\'" bname)
(string-match-p "\\.bin\\|\\.so\\|\\.dll\\|\\.exe\\'" bname)))))
;; Don't save persp configs in `recentf'
(with-eval-after-load 'recentf
(push persp-save-dir recentf-exclude)))
(provide 'init-persp)
;;; init-dict.el --- Youdao dictionary -*- lexical-binding: t -*-
;;; Code:
(use-package fanyi
:commands fanyi-dwim
:custom
(fanyi-providers '(;; Longman
fanyi-longman-provider
;; 海词
fanyi-haici-provider
;; 有道同义词词典
;; fanyi-youdao-thesaurus-provider
;; Etymonline
;; fanyi-etymon-provider
)))
(provide 'init-dict)
;;; init-im.el --- 输入法相关 -*- lexical-binding: t -*-
;;; Code:
;; requires librime-dev on Debian
(use-package rime
:init
(setq default-input-method "rime"
rime-show-candidate 'posframe
rime-popup-style 'vertical
rime-posframe-style 'vertical
rime-user-data-dir (concat user-emacs-directory "rime/")
rime-posframe-properties '(:internal-border-width 2))
:config
(general-def rime-mode-map "C-`" #'rime-send-keybinding)
(general-def rime-active-mode-map "S-<delete>" #'rime-send-keybinding))
;; requires emacs-mozc on Debian
(use-package mozc
:init
(setq mozc-candidate-style 'echo-area))
(defun solarion/toggle-input-method ()
"Toggle between nil, rime and japanese-mozc input methods."
(interactive)
(cond
((equal current-input-method nil)
(set-input-method 'rime))
((equal current-input-method "rime")
(set-input-method 'japanese-mozc))
((equal current-input-method "japanese-mozc")
(set-input-method 'rime))))
(general-def :keymaps 'override "C-c SPC" #'solarion/toggle-input-method)
(provide 'init-im)
;;; init-wsl.el --- wsl-specific setup -*- lexical-binding: t -*-
;;; Code:
;; teach Emacs how to open links with your default browser
(let ((cmd-exe "/mnt/c/Windows/System32/cmd.exe")
(cmd-args '("/c" "start")))
(when (file-exists-p cmd-exe)
(setq browse-url-generic-program cmd-exe
browse-url-generic-args cmd-args
browse-url-browser-function 'browse-url-generic
search-web-default-browser 'browse-url-generic)))
;; Fix wayland Copy from wsl to Windows
(setq select-active-regions nil)
(defun wl-copy (text)
(let ((process-connection-type nil))
(let ((proc (start-process "wl-copy" "*Messages*" "wl-copy" "-f" "-n")))
(process-send-string proc text)
(process-send-eof proc))))
(defun wl-paste ()
(shell-command-to-string "wl-paste -n"))
;; (setq interprogram-cut-function 'wl-copy)
;; (setq interprogram-paste-function 'wl-paste)
(provide 'init-wsl)