Emacs saves you time when you work, and takes it back when you play with it.
Use M-x org-babel-tangle
or C-c C-v t
to manually extract lisp code.
Load an optional pre init file.
(load (locate-user-emacs-file "local.pre.init.el") 'noerror)
Name and mail addresses
(setq user-full-name "Peng Mei Yu"
user-mail-address "pmy@xqzp.net")
Identities
(setq my-irc-nick "pmy")
;; Set garbage collection threshold to a big value.
(setq gc-cons-threshold-original gc-cons-threshold)
(setq gc-cons-threshold (* 100 gc-cons-threshold-original))
;; Set garbage collection threshold to a smaller value after initialization.
(add-hook 'after-init-hook
(lambda ()
(setq gc-cons-threshold (* 10 gc-cons-threshold-original))
(makunbound 'gc-cons-threshold-original)
(message "Init done")))
(let ((min-version "27.1"))
(when (version< emacs-version min-version)
(error "Gnu Emacs %s or newer is required" min-version)))
(setq load-prefer-newer t)
Detect existing emacs server and switch to it if possible
(require 'server)
(defun my-server-shunt ()
"Shunts to emacsclient"
(let ((args (append '("emacsclient" "-c" "-n")
(cdr command-line-args))))
(shell-command (substring (format "%S" args) 1 -1))
(kill-emacs)))
;; Keep only one Emacs server instance
(if (server-running-p)
(if (daemonp)
(error "Another running Emacs server detected, abort")
(my-server-shunt))
(server-start))
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/"))
Load packages managed by Guix.
(unless (require 'guix-emacs nil t)
(let ((default-directory "~/.guix-profile/share/emacs/site-lisp/"))
(when (file-accessible-directory-p default-directory)
(normal-top-level-add-to-load-path '("."))
(normal-top-level-add-subdirs-to-load-path))))
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(eval-when-compile
(require 'use-package))
(require 'bind-key)
(setq use-package-verbose t)
;; Disable lazy loading in daemon mode
(if (daemonp)
(setq use-package-always-demand t))
Variables configured via the interactive ‘customize’ interface
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(load custom-file 'noerror)
Emacs built-in features
(require 'cl-lib)
Define XDG directories
(require 'xdg)
(defvar user-emacs-config-dir
(expand-file-name "emacs" (xdg-config-home)))
(defvar user-emacs-data-dir
(expand-file-name "emacs" (xdg-data-home)))
(defvar user-emacs-cache-dir
(expand-file-name "emacs" (xdg-cache-home)))
(defconst *os-is-gnu* (eq system-type 'gnu/linux))
(defconst *os-is-mac* (eq system-type 'darwin))
(defconst *os-is-windows* (eq system-type 'windows-nt))
(set-language-environment "UTF-8")
`set-locale-environment` changes the default coding system, therefore call it before setting coding system.
(if *os-is-gnu*
(set-locale-environment "en_US.UTF-8"))
(if *os-is-mac*
(set-locale-environment "en_US.UTF-8"))
(if *os-is-windows*
(set-locale-environment "ENU"))
(set-default-coding-systems 'utf-8-unix)
Use hexadecimal instead of octal for quoted-insert (C-q).
(setq read-quoted-char-radix 16)
Inhibits the startup screen
(setq inhibit-startup-screen t)
*scratch*
buffer’s default content
(setq initial-scratch-message nil)
Hide all kinds of bars
(menu-bar-mode -1)
(if (fboundp 'tool-bar-mode)
(tool-bar-mode -1))
(if (fboundp 'scroll-bar-mode)
(scroll-bar-mode -1))
mode line
(line-number-mode t)
(column-number-mode t)
(size-indication-mode t)
ring
(setq ring-bell-function 'ignore)
buffer name
(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)
(setq uniquify-separator "/")
(setq uniquify-after-kill-buffer-p t)
(setq uniquify-ignore-buffers-re "^\\*")
frame name
;; show either a file or a buffer name
(setq frame-title-format
'("" invocation-name " - "
(:eval (if (buffer-file-name)
(abbreviate-file-name (buffer-file-name))
"%b"))))
Let ‘yes-or-no-p’ use shorter answers “y” or “n”.
(setq use-short-answers t)
Disable dialog boxes.
(setq use-dialog-box nil)
Bind C-x k
to kill-this-buffer
(global-set-key (kbd "C-x k") 'kill-this-buffer)
Expand text
(global-set-key (kbd "M-/") 'hippie-expand)
Upcase or downcase text
(global-set-key (kbd "M-u") 'upcase-dwim)
(global-set-key (kbd "M-l") 'downcase-dwim)
shell
(global-set-key (kbd "C-c s") 'eshell)
(add-to-list 'completion-styles 'flex 'append)
Fill column
(setq-default fill-column 80)
Final new line
(setq require-final-newline t)
Delete the selection with a key press
(delete-selection-mode t)
Smart tab key behavior, indent or complete
(setq tab-always-indent 'complete)
Indentation
;; don't use tabs to indent
(setq-default indent-tabs-mode nil)
(setq-default tab-width 8)
Revert buffers automatically when underlying files are changed externally
(global-auto-revert-mode t)
Automatically save buffers to file when losing focus
(defun my-save-buffers ()
"Save all file-visiting buffers."
(save-some-buffers t nil))
(add-hook 'focus-out-hook 'my-save-buffers)
Automatically make a shell script executable on save
(add-hook 'after-save-hook
'executable-make-buffer-file-executable-if-script-p)
(blink-cursor-mode -1)
;; highlight the current line
(global-hl-line-mode 1)
;; highlight matching parentheses when the point is on them
(show-paren-mode t)
(setq blink-matching-paren nil)
whitespace-mode
(require 'whitespace)
(setq whitespace-style '(face empty trailing lines-tail indentation
missing-newline-at-eof))
(setq whitespace-line-column 80)
(defun my-whitespace-mode-setup ()
(whitespace-mode 1)
(add-hook 'before-save-hook 'whitespace-cleanup nil t))
(add-hook 'text-mode-hook 'auto-fill-mode)
(add-hook 'text-mode-hook 'my-whitespace-mode-setup)
(add-hook 'prog-mode-hook 'abbrev-mode)
(add-hook 'prog-mode-hook 'my-whitespace-mode-setup)
(defun my-prog-mode-setup ()
(which-function-mode 1)
(setq-local comment-auto-fill-only-comments t)
(auto-fill-mode 1)
;; highlight a bunch of well known comment annotations
(font-lock-add-keywords
nil
'(("\\<\\(\\(FIX\\(ME\\)?\\|TODO\\|OPTIMIZE\\|HACK\\|REFACTOR\\):\\)"
1 font-lock-warning-face t))))
(add-hook 'prog-mode-hook 'my-prog-mode-setup)
(add-to-list 'completion-ignored-extensions ".jar")
flyspell
(let ((enable-flyspell nil))
(cond
((executable-find "aspell")
(setq ispell-program-name "aspell")
(setq enable-flyspell t))
((executable-find "hunspell")
(setq ispell-program-name "hunspell")
(setq ispell-dictionary "en_US")
(setq enable-flyspell t))
(t
(message "Neither aspell nor hunspell found")))
(when enable-flyspell
(require 'flyspell)
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)))
(require 'tramp)
(setq tramp-default-method "ssh")
(setq dired-recursive-copies 'always)
(setq dired-recursive-deletes 'top)
(require 'dired-x)
(setq dired-clean-confirm-killing-deleted-buffers nil)
(require 'bookmark)
(setq bookmark-save-flag 1)
(require 'calendar)
(require 'holidays)
(require 'cal-china)
(calendar-set-date-style 'iso)
(setq calendar-mark-holidays-flag t)
(setq calendar-chinese-all-holidays-flag t)
(setq calendar-holidays
(append holiday-general-holidays
holiday-local-holidays
holiday-other-holidays
holiday-oriental-holidays))
(setq calendar-chinese-celestial-stem
["甲" "乙" "丙" "丁" "戊" "己" "庚" "辛" "壬" "癸"])
(setq calendar-chinese-terrestrial-branch
["子" "丑" "寅" "卯" "辰" "巳" "午" "未" "申" "酉" "戌" "亥"])
Don’t send anything in HTTP header field
(setq url-privacy-level 'paranoid)
SOCKS 5 proxy
(setq url-gateway-method 'socks)
(setq socks-server '("Default server" "localhost" 1080 5))
HTTP proxy
(setq url-proxy-services
'(("no_proxy" . "^\\(localhost\\|10\\..*\\|192\\.168\\..*\\)")
("http" . "localhost:1081")
("https" . "localhost:1081")))
eww
(global-set-key (kbd "C-c w") 'eww)
(global-set-key (kbd "C-c b") 'eww-list-bookmarks)
message mode
;; Turn on PGP
(add-hook 'message-mode-hook 'epa-mail-mode)
(setq mml-secure-openpgp-encrypt-to-self t)
;; Message signature
(setq message-signature-directory
(expand-file-name "signature" (xdg-config-home)))
(setq message-signature-file "personal")
;; Don't keep message buffer after sending a message.
(setq message-kill-buffer-on-exit t)
SMTP
(setq message-send-mail-function 'message-smtpmail-send-it)
(setq smtpmail-smtp-server "smtp.gmail.com"
smtpmail-stream-type 'ssl ;; StartTLS is evil.
smtpmail-smtp-service 465)
sendmail
(setq message-send-mail-function 'message-send-mail-with-sendmail)
;; Use the "From:" address in mail header as envelope-from address.
(setq mail-specify-envelope-from t
mail-envelope-from 'header)
(setq message-sendmail-envelope-from 'header)
msmtp
(setq sendmail-program "msmtp")
Query passphrase through the minibuffer, instead of the pinentry program.
(unless (display-graphic-p)
(setq epg-pinentry-mode 'loopback))
(setq auth-sources
(list (expand-file-name "auth/netrc.gpg" (xdg-data-home))))
Get secret from auth-source
(cl-defun my-get-secret (&rest spec &key domain port user &allow-other-keys)
(let ((record (nth 0 (auth-source-search :max 1
:host domain
:port port
:user user
:require '(:secret)))))
(if record
(let ((secret (plist-get record :secret)))
(if (functionp secret)
(funcall secret)
secret))
nil)))
Disable prompt for vc-follow-symlinks during initialization.
;; When desktop-save-mode restores buffers, the VC prompt is useless and
;; annoying.
(setq vc-follow-symlinks nil)
;; Restore default values after initialization.
(add-hook 'after-init-hook
(lambda ()
(setq vc-follow-symlinks 'ask)))
(setq desktop-auto-save-timeout 600)
(setq desktop-save t)
(setq desktop-dirname user-emacs-directory)
(desktop-save-mode t)
(require 'recentf)
(setq recentf-auto-cleanup 'never)
(setq recentf-exclude
(mapcar 'expand-file-name
(list "/gnu" "/nix" "/run" "/tmp" "/ssh:" "~/.cache"
package-user-dir)))
(recentf-mode 1)
(savehist-mode 1)
(setq auto-save-list-file-prefix
(expand-file-name "auto-save-list/" user-emacs-cache-dir))
(let ((backup-dir (expand-file-name "backup" user-emacs-cache-dir)))
(setq-default backup-directory-alist `((".*" . ,backup-dir))))
(use-package cnfonts
:ensure t
:config
(cnfonts-enable))
(use-package color-theme-sanityinc-tomorrow
:ensure t
:config
(load-theme 'sanityinc-tomorrow-night 'no-confirm))
alpha ‘(<active> . <inactive>)
(set-frame-parameter (selected-frame) 'alpha '(95 . 90))
(add-to-list 'default-frame-alist '(alpha . (98 . 90)))
(use-package diminish
:ensure t
:config
(diminish 'abbrev-mode)
(diminish 'auto-fill-function)
(diminish 'auto-revert-mode)
(diminish 'eldoc-mode)
(diminish 'whitespace-mode))
Highlight the cursor whenever the window scrolls
(use-package beacon
:ensure t
:diminish beacon-mode
:config
(beacon-mode t))
(use-package helm
:ensure t
:defer 3
:diminish helm-mode
:bind-keymap ("C-c h" . helm-command-map)
:bind (("C-c f" . helm-recentf)
("C-h a" . helm-apropos)
("C-x b" . helm-mini)
("C-x C-b" . helm-buffers-list)
("C-x C-d" . helm-browse-project)
("C-x C-f" . helm-find-files)
("M-x" . helm-M-x)
("M-y" . helm-show-kill-ring)
("M-s o" . helm-occur)
:map helm-command-map
("M-g g" . helm-do-grep-rg))
:init
(defalias 'helm-do-grep-rg 'helm-do-grep-ag)
:config
(helm-mode 1)
(setq helm-move-to-line-cycle-in-source t)
;; fuzzy matching
(setq helm-mode-fuzzy-match t)
(setq helm-completion-in-region-fuzzy-match t)
(setq helm-M-x-fuzzy-match t
helm-buffers-fuzzy-matching t
helm-recentf-fuzzy-match t)
(add-to-list 'helm-mini-default-sources 'helm-source-bookmarks 'append)
(setq helm-ff-file-name-history-use-recentf t)
(setq helm-ff-skip-boring-files t)
;; ripgrep
(setq helm-grep-ag-command
(concat "rg --color=always --colors 'match:fg:black'"
" --colors 'match:bg:yellow' --smart-case"
" --no-heading --line-number %s %s %s"))
(setq helm-grep-ag-pipe-cmd-switches
'("--colors 'match:fg:black'" "--colors 'match:bg:yellow'")))
helm-rg
(use-package helm-rg
:ensure t
:after helm
:bind (:map helm-command-map
("g" . helm-rg)))
(use-package dired-sidebar
:ensure t
:commands (dired-sidebar-toggle-sidebar))
(use-package crux
:ensure t
:bind (("C-a" . crux-move-beginning-of-line)
("C-c d" . crux-duplicate-current-line-or-region)
("C-c D" . crux-delete-file-and-buffer)
("C-c e" . crux-eval-and-replace)
("C-c I" . crux-find-user-init-file)
("C-c o o" . crux-open-with)
("C-c o r" . crux-sudo-edit)
("C-c r n" . crux-rename-file-and-buffer)
("C-c TAB" . crux-indent-defun)
("C-x K" . crux-kill-other-buffers)
("C-^" . crux-top-join-line)
("C-<BACKSPACE>" . crux-kill-line-backwards)
("C-S-<BACKSPACE>" . crux-kill-whole-line)))
(use-package which-key
:ensure t
:defer 10
:diminish which-key-mode
:config
(which-key-mode 1))
(use-package discover-my-major
:ensure t
:commands (discover-my-major discover-my-mode)
:bind ("C-h m" . discover-my-major))
keyfreq
(use-package keyfreq
:ensure t
:defer 10
:config
(setq keyfreq-file (locate-user-emacs-file "keyfreq"))
(setq keyfreq-file.lock (concat keyfreq-file ".lock"))
(keyfreq-mode 1)
(keyfreq-autosave-mode 1))
(use-package undo-tree
:ensure t
:diminish undo-tree-mode
:bind ("C-x u" . undo-tree-visualize)
:config
(setq undo-tree-history-directory-alist
`(("." . ,(expand-file-name "undo-tree/" user-emacs-cache-dir))))
(global-undo-tree-mode t))
Jump to visible text using a char-based decision tree
(use-package avy
:ensure t
:bind (("C-c j" . avy-goto-char-timer)
("M-g g" . avy-goto-line))
:config
(setq avy-background t))
select a window
(use-package ace-window
:ensure t
:bind ("C-x o" . ace-window)
:config
(setq aw-scope 'frame))
(use-package multiple-cursors
:ensure t
:bind (("C-|" . mc/edit-lines)
("C->" . mc/mark-next-like-this)
("C-<" . mc/mark-previous-like-this)
("C-S-<mouse-1>" . mc/add-cursor-on-click)))
anzu-mode enhances isearch & query-replace by showing total matches and current match position in the mode-line
(use-package anzu
:ensure t
:diminish anzu-mode
:bind (("M-%" . anzu-query-replace)
("C-M-%" . anzu-query-replace-regexp))
:config
(global-anzu-mode t))
(use-package alert
:ensure t
:config
(setq alert-default-style 'libnotify))
Magit
(use-package magit
:ensure t
:mode ("/\\(\
\\(\\(COMMIT\\|NOTES\\|PULLREQ\\|TAG\\)_EDIT\\|MERGE_\\|\\)MSG\
\\|\\(BRANCH\\|EDIT\\)_DESCRIPTION\\)\\'" . git-commit-mode)
:bind (("C-x g" . magit-status)
("C-x M-g" . magit-dispatch)
("C-c M-g" . magit-file-dispatch)))
Git modes
(use-package git-modes
:ensure t
:defer 10)
(use-package diff-hl
:ensure t
:defer 10
:config
(global-diff-hl-mode t)
(add-hook 'dired-mode-hook 'diff-hl-dired-mode)
(add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh))
(use-package company
:ensure t
:defer 10
:diminish company-mode
:config
(setq company-minimum-prefix-length 2)
(global-company-mode 1))
Rime input method. This package should be installed by a system package manager.
(use-package rime
:ensure nil
:pin manual
:requires rime
:config
(setq default-input-method "rime")
(setq rime-show-candidate 'posframe)
(setq rime-posframe-style 'vertical)
(setq rime-disable-predicates
'(active-minibuffer-window
rime-predicate-ace-window-p
rime-predicate-prog-in-code-p))
(add-to-list 'rime-translate-keybindings "C-`")
(defun my-telega-msg-p ()
"Check if the current point is on a telega message."
(string= "telega-msg-button"
(symbol-name (get-text-property (point) 'category))))
(add-to-list 'rime-disable-predicates 'my-telega-msg-p))
(use-package flycheck
:ensure t
:diminish flycheck-mode
:hook (prog-mode . flycheck-mode)
:config
(setq flycheck-display-errors-function
'flycheck-display-error-messages-unless-error-list))
Eglot
(use-package eglot
:ensure t
:commands (eglot eglot-ensure)
:bind (:map eglot-mode-map
("C-c l a" . eglot-code-actions)
("C-c l f" . eglot-format)
("C-c l r" . eglot-rename)
("C-c l t" . eglot-find-typeDefinition)
("C-c l i" . eglot-find-implementation)))
smart parens
(use-package smartparens
:ensure t
:defer 10
:diminish smartparens-mode
:hook (prog-mode . smartparens-strict-mode)
:config
(require 'smartparens-config)
(show-smartparens-global-mode 1))
colorful parens
(use-package rainbow-delimiters
:ensure t
:hook (prog-mode . rainbow-delimiters-mode))
(use-package yasnippet
:ensure t
:defer 20
:diminish yas-minor-mode
:config
(let ((dir "~/Projects/guix/etc/snippets"))
(when (file-directory-p dir)
(add-to-list 'yas-snippet-dirs dir)))
(yas-global-mode 1))
(use-package yasnippet-snippets
:ensure t
:after yasnippet)
Indentation
(use-package aggressive-indent
:ensure t
:diminish aggressive-indent-mode
:hook ((emacs-lisp-mode scheme-mode) . aggressive-indent-mode))
geiser
(use-package geiser
:ensure t
:hook (scheme-mode . geiser-mode--maybe-activate)
:config
(setq geiser-active-implementations '(guile))
(setq geiser-mode-start-repl-p t)
(setq geiser-repl-history-filename
(expand-file-name "geiser_history" user-emacs-directory))
(use-package geiser-guile
:ensure t))
Guix
(use-package guix
:ensure t
:defer 20
:hook (scheme-mode . guix-devel-mode))
(setq c-default-style "linux")
(setq-default c-basic-offset 4)
clang-format
(use-package clang-format
:ensure t
:commands (clang-format-buffer))
(defun clang-format-buffer-smart ()
"Reformat buffer if .clang-format exists in the project root."
(when (f-exists? (expand-file-name ".clang-format" (project-root (project-current))))
(clang-format-buffer)))
(defun my-c-mode-setup ()
(add-hook 'before-save-hook 'clang-format-buffer-smart nil t))
(add-hook 'c-mode-hook 'my-c-mode-setup)
(add-hook 'c++-mode-hook 'my-c-mode-setup)
csharp-mode
(use-package csharp-mode
:ensure nil
:mode ("\\.cs\\'" . csharp-mode)
:config
(defun my-csharp-mode-setup ()
(c-set-style "c#"))
(add-hook 'csharp-mode-hook 'my-csharp-mode-setup))
(use-package fish-mode
:ensure t
:mode ("\\.fish\\'" . fish-mode)
:interpreter ("fish"))
(use-package go-mode
:ensure t
:mode ("\\.go\\'" . go-mode))
(use-package go-eldoc
:ensure t
:after (go-mode)
:hook (go-mode . go-eldoc-setup))
(defun my-go-mode-setup ()
(add-hook 'before-save-hook 'gofmt-before-save nil t))
(add-hook 'go-mode-hook 'my-go-mode-setup)
java-mode
(defun my-java-mode-setup ()
(setq fill-column 120))
(add-hook 'java-mode-hook 'my-java-mode-setup)
(add-hook 'java-mode-hook 'subword-mode)
kotlin-mode
(use-package kotlin-mode
:ensure nil
:mode ("\\.kts?\\'" . kotlin-mode))
nix-mode
(use-package nix-mode
:ensure t
:mode ("\\.nix\\'" . nix-mode)
:config
(setq nix-nixfmt-bin "nixpkgs-fmt"))
powershell-mode
(use-package powershell
:ensure nil
:mode ("\\.ps[dm]?1\\'" . powershell-mode))
Prefer Python 3
(setq python-shell-interpreter "python3")
python-mode
(defun my-python-mode-setup ()
(add-hook 'post-self-insert-hook
'electric-layout-post-self-insert-function
nil t))
(add-hook 'python-mode-hook 'my-python-mode-setup)
rust-mode
(use-package rust-mode
:ensure nil
:mode ("\\.rs\\'" . rust-mode)
:config
(setq rust-format-on-save t))
Syntax-based indentation for sql-mode.
(use-package sql-indent
:ensure t
:hook (sql-mode . sqlind-minor-mode))
htmlize – Converting buffer text and decorations to HTML.
(use-package htmlize
:ensure t
:defer 20)
rainbow mode
(use-package rainbow-mode
:ensure t
:hook ((html-mode css-mode) . rainbow-mode))
vue-mode
(use-package vue-mode
:ensure nil
:mode ("\\.vue\\'" . vue-mode))
(use-package org
:ensure org-contrib
:defer 10
:mode ("\\.org\\'" . org-mode)
:bind (("C-c a" . org-agenda)
("C-c c" . org-capture)
("C-c o l" . org-store-link)
("C-c C-," . org-insert-structure-template))
:config
(setq org-directory "~/Sync/Org")
(setq org-agenda-files (list org-directory))
(setq org-default-notes-file
(expand-file-name "Organizer.org" org-directory))
(setq my-org-inbox-file (expand-file-name "Inbox.org" org-directory))
(setq org-catch-invisible-edits 'show)
(setq org-id-track-globally nil) ; Do not store org IDs on disk.
(setq org-use-sub-superscripts '{})
;;; org-agenda
(setq org-agenda-default-appointment-duration 60)
(setq org-agenda-compact-blocks t)
(setq org-agenda-span 'month)
(setq org-agenda-start-on-weekday nil)
;;; org-todo
(setq org-log-done 'time)
(setq org-log-into-drawer t)
(setq org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!/!)" "CANCELLED(c@/!)")))
(setq org-todo-repeat-to-state "NEXT")
(setq org-todo-keyword-faces '(("NEXT" :inherit warning)))
;;; org-tag
(setq org-fast-tag-selection-single-key 'expert)
(setq org-tags-column -80) ; Align right edge to 80th column.
;;; org-capture
(setq org-capture-templates
`(("i" "inbox"
entry (file my-org-inbox-file)
"* %?\n")
("j" "journal"
entry (file+olp org-default-notes-file "Journal")
"* %u\n%?\n")
("t" "todo"
entry (file+olp org-default-notes-file "Agenda")
"* TODO %?\n :PROPERTIES:\n :Captured_at: %U\n :END:\n")))
(add-to-list 'org-structure-template-alist
'("semacs" . "src emacs-lisp") t)
(add-to-list 'org-structure-template-alist
'("sscheme" . "src scheme") t)
(add-to-list 'org-structure-template-alist
'("sshell" . "src sh") t)
(add-to-list 'org-structure-template-alist
'("ssql" . "src sql") t)
(add-to-list 'org-structure-template-alist
'("shttp" . "src http") t)
;;; org-clock
;; Persist the running clock and all clock history
(org-clock-persistence-insinuate)
(setq org-clock-persist t)
(setq org-clock-in-resume t)
;; Save clock data and notes in drawer
(setq org-clock-into-drawer t)
;; Remove the clock line when result time is zero
(setq org-clock-out-remove-zero-time-clocks t)
;;; org-babel
(org-babel-do-load-languages
'org-babel-load-languages
'((dot . t)
(latex . t)
(ledger . t)
(python . t)
(scheme . t)
(shell . t)
(sql . t)))
;; Prefer Python 3
(setq org-babel-python-command "python3")
;; Disable emacs-lisp-checker for org-src-mode
(add-hook 'org-src-mode-hook
(lambda ()
(setq-local flycheck-disabled-checkers
'(emacs-lisp-checkdoc))))
;;; org-export
(setq org-export-exclude-tags '("noexport" "private"))
(setq org-export-with-section-numbers nil)
(setq org-export-with-sub-superscripts '{})
(setq org-export-with-toc nil)
;;; org-html
(setq org-html-doctype "html5")
(setq org-html-html5-fancy-p t)
(setq org-html-validation-link nil)
;;; org-latex
(add-to-list 'org-latex-packages-alist '("" "color"))
(add-to-list 'org-latex-packages-alist '("" "listings"))
(setq org-latex-listings t
org-latex-listings-options '(("basicstyle" "\\small")
("frame" "single")))
;;; org-icalendar
(setq org-icalendar-alarm-time 60) ; 60 minutes before the event.
(setq org-icalendar-combined-agenda-file
(expand-file-name "agenda.ics" org-directory))
(setq org-icalendar-exclude-tags
(append org-export-exclude-tags '("archive" "journal")))
;; Include tasks that are not in DONE state.
(setq org-icalendar-include-todo t)
;; Include scheduled and deadline events.
(setq org-icalendar-use-scheduled
'(event-if-todo event-if-not-todo todo-start))
(setq org-icalendar-use-deadline
'(event-if-todo event-if-not-todo todo-due))
;; Whether to make events from plain time stamps.
(setq org-icalendar-with-timestamps 'active))
Notifications for org agenda items
(use-package org-alert
:ensure t
:defer 20
:config
(setq org-alert-interval 600)
(org-alert-enable))
(use-package org-roam
:ensure nil
:after org
:defer 10
:bind (("C-c r l" . org-roam-buffer-toggle)
("C-c r f" . org-roam-node-file)
("C-c r g" . org-roam-graph)
("C-c r c" . org-roam-capture)
("C-c r i" . org-roam-node-insert))
:init
(setq org-roam-v2-ack t)
:config
(setq org-roam-directory org-directory)
(setq org-roam-capture-templates
`(("i" "inbox" entry nil
:if-new (file+olp ,my-org-inbox-file ())
:unnarrowed t)
("j" "journal" entry nil
:if-new (file+olp ,org-default-notes-file ("Journal"))
:unnarrowed t)
("t" "todo" entry nil
:if-new (file+olp ,org-default-notes-file ("Agenda"))
:unnarrowed t)))
(org-roam-setup))
(use-package ob-http
:ensure t
:after (ob)
:mode ("\\.http\\'" . org-mode)
:config
(org-babel-do-load-languages
'org-babel-load-languages
'((http . t))))
(use-package ox-hugo
:ensure t
:after ox)
(defun my-org-add-uuid-to-headlines-in-buffer ()
"Add ID property to all headlines in the current buffer."
(interactive)
(org-map-entries 'org-id-get-create))
(use-package csv-mode
:ensure t
:mode ("\\.csv\\'" . csv-mode))
(use-package ledger-mode
:ensure nil
:mode ("\\.ledger\\'" . ledger-mode)
:config
(use-package flycheck-ledger
:ensure t))
(use-package markdown-mode
:ensure t
:mode ("\\.md\\'" . markdown-mode))
po-mode is provided by “gettext”
(use-package po-mode
:ensure nil
:mode ("\\.pot?\\'" . po-mode)
:config
;; Do not wrap lines when editing msgstr.
(add-hook 'po-subedit-mode-hook
(lambda ()
(setq fill-column 1000)))
;; Enable input method.
(add-hook 'po-subedit-mode-hook
(lambda ()
(toggle-input-method))))
Wrap po file
;; https://www.emacswiki.org/emacs/PoMode
(defun po-wrap ()
"Filter current po-mode buffer through `msgcat' tool to wrap all lines."
(interactive)
(if (eq major-mode 'po-mode)
(let ((tmp-file (make-temp-file "po-wrap."))
(tmp-buf (generate-new-buffer "*temp*")))
(unwind-protect
(progn
(write-region (point-min) (point-max) tmp-file nil 1)
(if (zerop
(call-process
"msgcat" nil tmp-buf t (shell-quote-argument tmp-file)))
(let ((saved (point))
(inhibit-read-only t))
(delete-region (point-min) (point-max))
(insert-buffer tmp-buf)
(goto-char (min saved (point-max))))
(with-current-buffer tmp-buf
(error (buffer-string)))))
(kill-buffer tmp-buf)
(delete-file tmp-file)))))
AUCTeX
(use-package auctex
:ensure t
:mode ("\\.tex\\'" . LaTeX-mode)
:config
(setq TeX-auto-save t
TeX-parse-self t
TeX-PDF-mode t)
(setq-default TeX-master nil)
(use-package company-auctex
:ensure t
:after (company auctex)
:config (company-auctex-init)))
RefTeX
(setq reftex-plug-into-AUCTeX t)
(add-hook 'LaTeX-mode-hook 'turn-on-reftex)
(use-package yaml-mode
:ensure t
:mode ("\\.yaml\\'" "\\.yml\\'"))
(use-package bbdb
:ensure t
:config
(bbdb-initialize 'gnus 'message 'mu4e))
(use-package gnus
:commands (gnus)
:config
;; Email servers
(setq my--gnus-local '(nnmaildir "local"
(directory "~/Mail")
(get-new-mail nil)))
;; Usenet servers
(setq my--gnus-gmane
'(nntp "gmane"
(nntp-address "news.gmane.org")
(nntp-port-number 563)
(nntp-open-connection-function nntp-open-tls-stream))
my--gnus-aioe
'(nntp "aioe"
(nntp-address "nntp.aioe.org")
(nntp-port-number 563)
(nntp-open-connection-function nntp-open-tls-stream)))
(setq gnus-select-method my--gnus-local)
(setq gnus-secondary-select-methods
(list my--gnus-gmane my--gnus-aioe)))
(setq mail-user-agent 'mu4e-user-agent)
(use-package mu4e
:ensure nil
:bind (("C-c m" . mu4e))
:config
(setq mu4e-confirm-quit nil)
;; Don't save message to the "sent" folder if IMAP takes care of this.
;; (setq mu4e-sent-messages-behavior 'delete)
;; Fetch email.
(setq mu4e-get-mail-command "fdm fetch -v")
;; Default context.
(setq mu4e-drafts-folder "/drafts")
(setq mu4e-refile-folder "/archive/inbox")
(setq mu4e-sent-folder "/sent")
(setq mu4e-trash-folder "/trash")
(setq mu4e-maildir-shortcuts
'((:maildir "/archive/inbox" :key ?a)
(:maildir "/drafts" :key ?d)
(:maildir "/inbox" :key ?i)
(:maildir "/sent" :key ?s)
(:maildir "/spam" :key ?j)
(:maildir "/trash" :key ?t)))
(add-to-list 'mu4e-headers-actions
'("git apply mbox" . mu4e-action-git-apply-mbox) t)
(add-to-list 'mu4e-view-actions
'("git apply mbox" . mu4e-action-git-apply-mbox) t))
ERC
(use-package erc
:commands (erc my-erc-start-or-switch)
:config
(setq erc-nick my-irc-nick)
(setq erc-autojoin-channels-alist
'((".*\\.freenode.net" "#emacs")))
(erc-autojoin-mode t)
;; spell checking
(erc-spelling-mode 1)
;; logging
(setq erc-log-channels-directory
(expand-file-name "erc" (xdg-data-home)))
(setq erc-save-buffer-on-part t)
;; fallback to auth-source
(setq erc-prompt-for-password nil)
;; Kill buffers for channels after /part
(setq erc-kill-buffer-on-part t)
;; Kill buffers for private queries after quitting the server
(setq erc-kill-queries-on-quit t)
;; Kill buffers for server messages after quitting the server
(setq erc-kill-server-buffer-on-quit t)
;; open query buffers in the current window
(setq erc-query-display 'buffer)
(setq erc-auto-reconnect nil)
(erc-track-mode t)
(setq erc-track-exclude-types '("JOIN" "NICK" "PART" "QUIT" "MODE"
"324" "329" "332" "333" "353" "477"))
(defun my-erc-start-or-switch ()
"Connect to ERC, or switch to last active buffer."
(interactive)
(if (get-buffer "irc.libera.chat:6697")
(erc-track-switch-buffer 1)
(when (y-or-n-p "Start ERC? ")
(erc-tls :server "irc.libera.chat" :port 6697
:nick my-irc-nick)))))
(use-package telega
:ensure nil
:commands (telega))
elfeed
(use-package elfeed
:ensure t
:bind (("C-c n" . my-elfeed-open)
:map elfeed-search-mode-map
("q" . my-elfeed-quit))
:config
(setq elfeed-db-directory
(expand-file-name "elfeed" (xdg-data-home)))
(setq elfeed-search-title-max-width 120)
(use-package elfeed-org
:ensure t
:after elfeed
:config
(elfeed-org))
(defun my-elfeed-open ()
(interactive)
(elfeed-db-load)
(elfeed))
(defun my-elfeed-quit ()
(interactive)
(elfeed-search-quit-window)
(elfeed-db-unload)))
(require 'browse-url)
(defun my-lookup-wikipedia ()
"Look up the word under cursor in Wikipedia.
If there is a text selection, use that."
(interactive)
(let (word)
(setq word
(if (use-region-p)
(buffer-substring-no-properties (region-beginning) (region-end))
(current-word)))
(setq word (replace-regexp-in-string " " "_" word))
(browse-url (format "https://en.wikipedia.org/wiki/%s" word))))
(autoload 'ispell-get-word "ispell")
(defun my-lookup-wiktionary (word)
"Look up the word under cursor in Wiktionary."
(interactive (list (save-excursion (car (ispell-get-word nil)))))
(browse-url (format "https://en.wiktionary.org/wiki/%s" word)))
(global-set-key (kbd "M-#") 'my-lookup-wiktionary)
(use-package nov
:ensure nil
:mode ("\\.epub\\'" . nov-mode))
(use-package pdf-tools
:ensure nil
:mode ("\\.pdf\\'" . pdf-view-mode)
:config
(require 'pdf-occur)
(pdf-tools-install))
(use-package debbugs
:ensure nil
:commands (debbugs-gnu
debbugs-org
debbugs-gnu-bugs
debbugs-org-bugs
debbugs-gnu-search
debbugs-org-search)
:config
(setq debbugs-gnu-default-packages '("guix")))
by zwz.github.io
(defun clear-single-linebreak-in-cjk-string (string)
"Clear single line-break between CJK characters that is usually soft
line-breaks"
(let* ((cjk-char "[\u3000-\u303F]\\|[\u4E00-\u9FFF]\\|[\uFF01-\uFF5E]")
(regexp (concat "\\(" cjk-char "\\)\n\\(" cjk-char "\\)"))
(start (string-match regexp string)))
(while start
(setq string (replace-match "\\1\\2" nil nil string)
start (string-match regexp string start))))
string)
(defun ox-html-clear-single-linebreak-for-cjk (string backend info)
(when (org-export-derived-backend-p backend 'html)
(clear-single-linebreak-in-cjk-string string)))
(eval-after-load "ox"
'(add-to-list 'org-export-filter-final-output-functions
'ox-html-clear-single-linebreak-for-cjk))
(when (string-match-p "office" (system-name))
(with-eval-after-load 'org
(setq org-directory "~/Office")
(setq org-agenda-files (list org-directory))
(setq org-default-notes-file
(expand-file-name "Office.org" org-directory))
(setq my-org-inbox-file (expand-file-name "Office.org" org-directory)))
(use-package nyan-mode
:ensure t
:config
(nyan-mode 1))
(use-package spacemacs-theme
:ensure t
:defer t
:init (load-theme 'spacemacs-dark 'no-confirm)))
Load an optional post init file.
(load (locate-user-emacs-file "local.post.init.el") 'noerror)