;;; init.el --- Isaac's Emacs configuration ;; Copyright (c) 2016-2022 Isaac Gu ;; Author: Isaac Gu ;; URL: https://github.com/gujiaxi/.emacs.d ;; Package-Requires: ((emacs "29.1")) ;;; Commentary: ;; This is a personal Emacs configuration. ;;; License: ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Code: ;; ------------------------------------------------------------------- ;; Basic settings ;; ------------------------------------------------------------------- ;; Personal Infomation (setq user-full-name "Isaac Gu") (setq user-mail-address "imjiaxi@gmail.com") ;; set unicode encoding (prefer-coding-system 'utf-8) ;; no lockfile (setq create-lockfiles nil) ;; backup and autosave (setq backup-directory-alist `((".*" . ,(expand-file-name "backup" user-emacs-directory)))) (setq version-control t) (setq delete-old-versions t) ;; move to trash (setq delete-by-moving-to-trash t) (setq trash-directory "~/.Trash/") ;; clean startup (setq inhibit-startup-message t) ;; initial buffer (setq initial-major-mode 'text-mode) (setq initial-scratch-message nil) ;; no ring-bell (setq ring-bell-function 'ignore) ;; nice frame (scroll-bar-mode 0) (tool-bar-mode 0) (menu-bar-mode 0) ;; nice scrolling (pixel-scroll-mode) (setq scroll-margin 5) ;; use y/n instead of yes/no (setq use-short-answers t) ;; word wrap for CJK (setq word-wrap-by-category t) ;; enable syntax highlight (global-font-lock-mode t) ;; indentation (setq-default indent-tabs-mode nil) (setq-default default-tab-width 4) (setq-default c-basic-offset 4) ;; delete selection (delete-selection-mode t) ;; auto revert external changes (global-auto-revert-mode t) ;; always load newest byte code (setq load-prefer-newer t) ;; highlight current line (global-hl-line-mode t) ;; display time in mode line (display-time-mode t) (setq display-time-default-load-average nil) (setq display-time-24hr-format t) (setq system-time-locale "C") ;; display battery status (display-battery-mode t) ;; set frame title (setq frame-title-format "%b") ;; set a larger kill ring (setq kill-ring-max 200) ;; use system clipboard (setq save-interprogram-paste-before-kill t) ;; confirm before quit (setq confirm-kill-emacs 'yes-or-no-p) ;; suppress warnings (setq find-file-suppress-same-file-warnings t) ;; custom directory (setq org-directory "~/Library/CloudStorage/Dropbox/Documents/OrgDir/") (setq custom-file (expand-file-name "custom.el" user-emacs-directory)) (when (file-exists-p custom-file) (load custom-file)) ;; ------------------------------------------------------------------- ;; Built-in packages ;; ------------------------------------------------------------------- ;; ----- customizations ----- ;; abbrev [built-in] (setq save-abbrevs nil) ;; calendar [built-in] (setq calendar-location-name "Beijing, China") (setq calendar-chinese-all-holidays-flag t) (setq mark-diary-entries-in-calendar t) (setq mark-holidays-in-calendar t) (setq diary-file (expand-file-name "diary.org" org-directory)) (global-set-key (kbd "C-c k") 'calendar) ;; dired [built-in] (put 'dired-find-alternate-file 'disabled nil) (setq dired-recursive-deletes 'always) (setq dired-recursive-copies 'always) (setq dired-listing-switches "-alh") ;; display-line-numbers [built-in] (setq display-line-numbers-type 'relative) (mapc (lambda (hook) (add-hook hook 'display-line-numbers-mode)) (list 'prog-mode-hook 'bibtex-mode-hook)) ;; electric [built-in] (electric-pair-mode t) (electric-indent-mode t) (electric-layout-mode t) ;; epa [built-in] (setq epa-file-cache-passphrase-for-symmetric-encryption t) (setq epa-pinentry-mode 'loopback) ;; epg [built-in] (setq epg-gpg-minimum-version "100") ;; flyspell [built-in] (add-hook 'org-mode-hook 'flyspell-mode) (add-hook 'text-mode-hook 'flyspell-mode) (add-hook 'LaTeX-mode-hook 'flyspell-mode) (add-hook 'markdown-mode-hook 'flyspell-mode) ;; grep [built-in] (global-set-key (kbd "C-c g") 'zrgrep) ;; help-at-pt [bilt-in] (custom-set-variables '(help-at-pt-timer-delay 0.5) '(help-at-pt-display-when-idle t)) ;; hideshow [built-in] (add-hook 'prog-mode-hook 'hs-minor-mode) ;; org-mode [built-in] (global-set-key (kbd "C-c a") 'org-agenda) (global-set-key (kbd "C-c c") 'org-capture) (defun org-publish-site () "A function for publishing a site. The site configuration is defined in index.org." (interactive) (let ((index-file (expand-file-name "index.org" org-directory))) (find-file index-file) (org-babel-load-file index-file) (kill-this-buffer))) (global-set-key (kbd "C-c p") 'org-publish-site) ;; savehist [built-in] (savehist-mode t) ;; recentf [built-in] (setq recentf-max-saved-items 500) (recentf-mode t) ;; reftex [built-in] (setq reftex-plug-into-AUCTeX t) (setq reftex-toc-split-windows-horizontally t) ;; saveplace [built-in] (save-place-mode t) ;; tab-bar [built-in] (setq tab-bar-show 1) ;; tramp [built-in] (setq tramp-backup-directory-alist backup-directory-alist) ;; use-package [built-in] (setq use-package-always-ensure t) ;; winner [built-in] (winner-mode t) ;; zone [built-in] (autoload 'zone-when-idle "zone" nil t) (zone-when-idle 18000) ;; ----- key binding ----- (when (display-graphic-p) (define-key key-translation-map (kbd "ESC") (kbd "C-g"))) (global-set-key (kbd "C-x k") 'kill-this-buffer) (global-set-key (kbd "C-c m") 'compile) (global-set-key (kbd "C-c t") 'toggle-truncate-lines) ;; ------------------------------------------------------------------- ;; Package Bootstrap ;; ------------------------------------------------------------------- ;; package repository (setq package-archives '(("gnu" . "https://mirrors.163.com/elpa/gnu/") ("melpa" . "https://mirrors.163.com/elpa/melpa/"))) (package-initialize) ;; ------------------------------------------------------------------- ;; Flymake ;; ------------------------------------------------------------------- ;; flymake [built] (use-package flymake :hook (prog-mode . flymake-mode)) ;; ------------------------------------------------------------------- ;; Org Mode ;; ------------------------------------------------------------------- ;; org [built-in] (use-package org :defer t :custom ;; general (org-hide-leading-stars t) (org-startup-indented t) (org-startup-folded nil) (org-src-preserve-indentation t) (org-image-actual-width nil) (org-catch-invisible-edits 'show-and-error) (org-confirm-babel-evaluate nil) (org-export-with-archived-trees nil) (org-export-html-style-include-scripts nil) (org-export-html-style-include-default nil) (org-html-postamble t) (org-html-postamble-format '(("en" "Edited by %a on %C"))) (org-archive-location (expand-file-name "archive.org::" org-directory)) (org-refile-targets '((org-agenda-files :level . 1) (nil :level . 1))) (org-priority-faces '((?A . (:foreground "red" :weight bold)) (?B . (:foreground "orange" :weight bold)) (?C . (:foreground "yellow" :wegith bold)))) ;; org-agenda (org-agenda-files (list (expand-file-name "agenda.org" org-directory))) (org-agenda-include-diary nil) (org-agenda-custom-commands '(("n" "Agenda and all TODOs" ((tags "PRIORITY={A}" ((org-agenda-skip-function '(org-agenda-skip-subtree-if 'todo 'done)) (org-agenda-overriding-header "High-priority:"))) (agenda "" ((org-agenda-span (quote day)))) (alltodo "" ((org-agenda-skip-function '(or (org-agenda-skip-subtree-if 'scheduled) (org-agenda-skip-subtree-if 'todo '("WAIT")) (org-agenda-skip-subtree-if 'regexp "\\[#A\\]"))) (org-agenda-overriding-header "Others tasks:"))) (todo "WAIT" ((org-agenda-skip-function '(org-agenda-skip-subtree-if 'regexp "\\[#A\\]")) (org-agenda-overriding-header "Postponed tasks:"))))))) ;; org-capture (org-default-notes-file (expand-file-name "agenda.org" org-directory)) (org-capture-templates '(("a" "Appt" entry (file+headline "agenda.org" "Appointments") "* %?\n%t") ("t" "Task" entry (file+headline "agenda.org" "Tasks") "* TODO %?\n%U\n%a") ("n" "Note" entry (file+headline "notes.org" "Inbox") "* %?\n%U\n%a") ("j" "Journal" plain (file+olp+datetree "journal.org") "%U %?\n") ("p" "Publish" plain (file "p-scratch.org") "%?\n\n%U\n-----"))) :config ;; ox-html (use-package htmlize) (setq org-html-htmlize-output-type 'css) ;; ox-latex (with-eval-after-load 'ox-latex (add-to-list 'org-latex-logfiles-extensions "tex") (add-to-list 'org-latex-packages-alist '("" "listings" nil)) (add-to-list 'org-latex-packages-alist '("margin=1in" "geometry" nil)) (add-to-list 'org-latex-packages-alist '("scheme=plain" "ctex" nil)) (setq org-latex-hyperref-template "\\hypersetup{pdfauthor={%a},pdftitle={%t},hidelinks}")) (setq org-latex-pdf-process '("latexmk -xelatex -quiet -shell-escape -f %f")) (setq org-latex-listings t) (setq org-latex-listings-options '(("breaklines" "true") ("basicstyle" "\\ttfamily") ("frame" "single"))) ;; org-babel (org-babel-do-load-languages 'org-babel-load-languages '((awk . t) (C . t) (calc . t) (emacs-lisp . t) (latex . t) (python . t) (ruby . t) (R . t) (scheme . t) (shell . t))) ;; key bindings in org-mode (unbind-key "C-'" org-mode-map)) ;; ------------------------------------------------------------------- ;; TeX ;; ------------------------------------------------------------------- ;; auctex (use-package tex :ensure auctex :after latex :config (add-to-list 'TeX-command-list '("Latexmk" "latexmk -xelatex -quiet %s" TeX-run-command nil t :help "Run latexmk")) (add-to-list 'LaTeX-clean-intermediate-suffixes "\\.fdb_latexmk") (with-eval-after-load 'evil (evil-set-initial-state 'TeX-output-mode 'emacs)) :hook ((LaTeX-mode . turn-on-reftex) (LaTeX-mode . LaTeX-math-mode) (LaTeX-mode . TeX-fold-mode)) :custom (TeX-auto-save t) (TeX-parse-self t) (TeX-clean-confirm nil)) ;; ------------------------------------------------------------------- ;; Theme ;; ------------------------------------------------------------------- ;; ----- color theme ----- ;; modus-themes: operandi for day and vivendi for night (load-theme 'modus-operandi) (setq modus-themes-no-mixed-fonts t) (run-at-time "09:00" (* 60 60 24) #'load-theme 'modus-operandi) (run-at-time "17:30" (* 60 60 24) #'load-theme 'modus-vivendi) ;; ----- mode-line ----- ;; nyan-mode (use-package nyan-mode) ;; Crafted for battery-mode, vc-mode and evil-mode (setq-default mode-line-format (list '(:eval (when (boundp 'evil-mode) (propertize (evil-generate-mode-line-tag evil-state) 'face '(:inherit font-lock-function-name-face)))) 'mode-line-mule-info 'mode-line-modified 'mode-line-remote " " '(:eval (propertize " %b " 'face (if (buffer-modified-p) '(:background "#d33682" :foreground "#fdf6e3" :weight bold) '(:background "#268bd2" :foreground "#fdf6e3" :weight light)) 'help-echo (buffer-file-name))) '(:eval (when (boundp 'nyan-mode) (nyan-create))) '(:propertize " %p L%l " face (:background "gray30" :foreground "#fdf6e3")) '(:propertize " (%m)" face (:inherit font-lock-function-name-face :weight bold)) '(:eval (when (> (window-width) 64) (concat (when vc-mode (propertize vc-mode 'face '(:inherit font-lock-keyword-face :weight bold))) (propertize (format-time-string " %p·%R ") 'help-echo (format-time-string "%F %A")) (replace-regexp-in-string "%" "%%" battery-mode-line-string)))) "-%-")) ;; ------------------------------------------------------------------- ;; Evil ;; ------------------------------------------------------------------- ;; evil (use-package evil :config (evil-mode) (mapc (lambda (my-mode) (evil-set-initial-state my-mode 'emacs)) (list 'calendar-mode 'comint-mode 'completion-mode 'dired-mode 'diff-mode 'epa-info-mode 'epa-key-list-mode 'eshell-mode 'eww-mode 'eww-bookmark-mode 'help-mode 'inferior-emacs-lisp-mode 'inferior-python-mode 'Info-mode 'message-mode 'newsticker-treeview-mode 'process-menu-mode 'profiler-report-mode 'shell-mode 'speedbar-mode 'special-mode 'term-mode)) (unbind-key "SPC" evil-normal-state-map) ;; reserve for leader key (unbind-key "TAB" evil-motion-state-map) ;; reserve for org-mode (unbind-key "C-n" evil-insert-state-map) ;; reserve for auto complete (unbind-key "C-p" evil-insert-state-map) ;; reserve for auto complete :custom (evil-undo-system 'undo-redo) (evil-want-abbrev-expand-on-insert-exit nil) :bind (("" . evil-make) :map evil-normal-state-map ("j" . evil-next-visual-line) ("k" . evil-previous-visual-line) ("SPC w" . save-buffer) ;; tab-bar-mode ("g o" . tab-bar-new-tab) ("g c" . tab-bar-close-tab) ("g t" . tab-bar-switch-to-next-tab) ("g T" . tab-bar-switch-to-prev-tab) :map evil-visual-state-map ("j" . evil-next-visual-line) ("k" . evil-previous-visual-line) :map evil-emacs-state-map ("C-w" . evil-window-map))) ;; evil-nerd-commenter (use-package evil-nerd-commenter :after evil :bind (("M-;" . evilnc-comment-or-uncomment-lines) :map evil-normal-state-map ("SPC c SPC" . evilnc-comment-or-uncomment-lines))) ;; evil-surround (use-package evil-surround :config (global-evil-surround-mode)) ;; evil-matchit (use-package evil-matchit :config (global-evil-matchit-mode)) ;; ------------------------------------------------------------------- ;; Completion System ;; ------------------------------------------------------------------- ;; Vertico (use-package vertico :init (vertico-mode) :custom (vertico-resize t) (vertico-cycle t) :config (use-package orderless :custom (completion-styles '(substring orderless))) (use-package marginalia :init (marginalia-mode) :custom (marginalia-annotator-registry '((command marginalia-annotate-binding builtin none)))) (use-package consult :custom (consult-preview-key "M-.") :bind (("C-x b" . consult-buffer) ("C-s" . consult-line) ("M-y" . consult-yank-pop) ("C-c i" . consult-imenu)))) ;; ------------------------------------------------------------------- ;; Auto Complete ;; ------------------------------------------------------------------- (use-package corfu :custom (corfu-cycle t) (corfu-auto t) (corfu-auto-delay 0.1) (corfu-auto-prefix 2) (corfu-on-exact-match nil) (corfu-preview-current nil) :config (global-corfu-mode) (use-package cape :config (add-to-list 'completion-at-point-functions #'cape-abbrev) (add-to-list 'completion-at-point-functions #'cape-file) (add-to-list 'completion-at-point-functions #'cape-keyword))) ;; ------------------------------------------------------------------- ;; LSP (Language Server Protocol) ;; ------------------------------------------------------------------- ;; eglot (use-package eglot :custom (eglot-autoreconnect nil) (eglot-autoshutdown t) :hook (python-mode . eglot-ensure) :bind (:map eglot-mode-map ("C-c C-e f" . eglot-format) ("C-c C-e i" . eglot-code-action-organize-imports))) ;; ------------------------------------------------------------------- ;; Deft ;; ------------------------------------------------------------------- (use-package deft :custom (deft-directory org-directory) (deft-extensions '("org" "md" "tex")) (deft-default-extension "org") (deft-ignore-file-regexp "\\(?:index\\|readme\\|sitemap\\|archive\\)") (deft-recursive t) (deft-auto-save-interval 0) (deft-use-filename-as-title t) (deft-use-filter-string-for-filename t) :config (with-eval-after-load 'evil (evil-set-initial-state 'deft-mode 'emacs)) :hook (deft-open-file . deft-filter-clear) :bind ("C-c d" . deft)) ;; ------------------------------------------------------------------- ;; Markdown ;; ------------------------------------------------------------------- ;; markdown-mode (use-package markdown-mode :mode ("\\.md\\'" "\\.markdown\\'") :custom (markdown-command "pandoc --quiet --mathjax --no-highlight -f markdown") (markdown-css-paths '("https://isaac.ttm.sh/org/css/md.css")) (markdown-xhtml-header-content "\n\n")) ;; ------------------------------------------------------------------- ;; Web ;; ------------------------------------------------------------------- ;; web-mode (use-package web-mode :mode (("\\.html?$" . web-mode) ("\\.jsx?$" . web-mode) ("\\.php$" . web-mode) ("\\.s?css$" . web-mode))) ;; ------------------------------------------------------------------- ;; Other packages ;; ------------------------------------------------------------------- ;; aggressive-indent (use-package aggressive-indent :config (global-aggressive-indent-mode t)) ;; avy (use-package avy :custom (avy-background t) :bind (("C-'" . avy-goto-char-2) :map evil-normal-state-map ("SPC s" . avy-goto-char-2))) ;; bind-dict (use-package bing-dict :bind ("C-c l" . bing-dict-brief)) ;; magit (use-package magit :bind ("C-x g" . magit-status)) ;; quickrun (use-package quickrun :config (with-eval-after-load 'evil (evil-set-initial-state 'quickrun--mode 'emacs)) (quickrun-add-command "c++/clang++" '((:exec . ("%c -std=c++14 -x c++ %o -o %e %s" "%e %a"))) :override t) :bind ("C-c r" . quickrun)) ;; rainbow-delimiters (use-package rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode)) ;; sr-speedbar (use-package sr-speedbar :custom (speedbar-show-unknown-files t) (speedbar-enable-update t) (sr-speedbar-skip-other-window-p t) (sr-speedbar-auto-refresh t) :bind (("C-c s" . sr-speedbar-toggle) :map speedbar-mode-map ("a" . speedbar-toggle-show-all-files) ("l" . sr-speedbar-refresh-toggle))) ;; symon (use-package symon :custom (symon-delay 33) :config (symon-mode)) ;; tempel (use-package tempel ;; User-defined templates are put in `~/.emacs.d/templates'. :init (global-tempel-abbrev-mode) :config (use-package tempel-collection) :bind (:map tempel-map ("" . tempel-next) ("