Skip to content
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ lspbridge/*
projectile-bookmarks.eld
tramp
.mc-lists*
eln-cache
projects
39 changes: 39 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# AGENTS.md

## What this is

Personal Emacs configuration, intended to be symlinked as `~/.emacs.d`. Emacs Lisp only.

## Entrypoint

`init.el` — sets up package archives, bootstraps `use-package`, then loads modules from `rc/` in this order:

1. `basic` — core packages (magit, theme, company, markdown, avy, elfeed, etc.)
2. `rc-basic` — UI fundamentals (toolbar, fonts, fullscreen, templates)
3. `rc-c` — C/C++ (clangd, clang-format)
4. `rc-org` — Org-mode (TODO keywords, agenda, ox-hugo export)
5. `rc-file-management` — projectile, treemacs
6. `rc-lsp` — LSP (lsp-mode, lsp-ui)
7. `rc-mc` — multiple cursors
8. `rc-wc` — Chinese word count in mode-line
9. `rc-python` — Python (LSP, flycheck, pyvenv)
10. `rc-tramp` — remote editing via SSH
11. `rc-delimiters` — parentheses visualization

Each `rc/*.el` ends with `(provide '<name>)`. The loading order matters — LSP config must load after language mode configs so hooks fire correctly.

## Package management

- `use-package` with `(setq use-package-always-ensure t)` — all `use-package` forms auto-install missing packages from ELPA/MELPA.
- Package archives: GNU ELPA (priority 10), NonGNU ELPA (9), MELPA Stable (8), MELPA (5).
- `elpa/` is gitignored. Packages are installed at runtime, not committed.

## File conventions

- Elisp buffers auto-indent the whole buffer on save (defined in `rc-delimiters.el:20-24`).
- `delete-trailing-whitespace` runs on `before-save-hook` (defined in `basic.el:24`).
- `custom.el` is auto-generated by Emacs `customize` and is **gitignored**. Do not edit it or commit it; it contains user-specific paths and settings.

## No build/test/lint

There are no build, test, lint, or CI commands. This is a declarative config repo. The only "verification" is loading it in Emacs.
23 changes: 19 additions & 4 deletions init.el
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,18 @@

(package-initialize)

;; Ensure use-package is installed (required for Emacs 30+)
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))

;; Configure use-package
(eval-when-compile
(require 'use-package))
(setq use-package-always-ensure t) ; Make :ensure t default

;; load config
(add-to-list 'load-path "~/.emacs.d/rc")
(add-to-list 'load-path (expand-file-name "rc" user-emacs-directory))
(require 'basic)
(require 'rc-basic)
(require 'rc-c)
Expand All @@ -37,6 +47,11 @@
(require 'rc-mc)
(require 'rc-wc)
(require 'rc-python)

(setq custom-file "~/.emacs.d/custom.el")
(load custom-file)
(require 'rc-tramp)
(require 'rc-delimiters)
(require 'rc-scheme)

;; Set custom file and load it if it exists
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (file-exists-p custom-file)
(load custom-file t))
30 changes: 14 additions & 16 deletions rc/basic.el
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
; Linum and auto pair
(display-line-numbers-mode)
; Auto pair
(electric-pair-mode t)

(require 'use-package)

;; magit
(use-package magit
:ensure t
:bind ("C-x g" . magit-status))
:bind ("C-x g" . magit-status)
:config
;; Signed-off-by: add -s by default. If -s doesn't show in the commit
;; popup (c c), press C-x l there to show more options (transient level).
(setq magit-commit-arguments '("--signoff")))

;; theme
(use-package moe-theme
Expand All @@ -16,7 +19,7 @@
:init
(setq moe-theme-highlight-buffer-id t)
:config
(load-theme 'moe-dark t))
(load-theme 'moe-light t))

(add-hook 'before-save-hook 'delete-trailing-whitespace)

Expand All @@ -25,18 +28,14 @@
(add-hook 'prog-mode-hook #'whitespace-mode)
(electric-indent-mode -1)

;; autocomplete
;; auto complete
(use-package auto-complete
:ensure t)
(setq ac-ignore-case nil)
(add-hook 'emacs-lisp-mode-hook (lambda ()
(auto-complete-mode t)
(setq ac-sources (append ac-sources '(ac-source-functions)))))
;; Company for auto-completion (modern replacement for auto-complete)
(use-package company
:ensure t
:init (add-hook 'after-init-hook 'global-company-mode))
(ac-config-default)
:init
(add-hook 'after-init-hook 'global-company-mode)
:config
(setq company-idle-delay 0.5
company-minimum-prefix-length 2))


(set-language-environment "UTF-8")
Expand Down Expand Up @@ -80,8 +79,7 @@
:ensure t)
(xclip-mode 1)

;; trim space
(add-hook 'write-file-hooks 'delete-trailing-whitespace nil t)
;; trim space (already handled by before-save-hook above, but keep for compatibility)

;; rss
(use-package elfeed
Expand Down
15 changes: 9 additions & 6 deletions rc/rc-basic.el
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
(add-to-list 'default-frame-alist
'(fullscreen . maximized))

(add-hook 'window-setup-hook #'toggle-frame-maximized)

(when window-system
(set-frame-font (font-spec :family "Noto Sans Mono" :size 12))
(dolist (script '(han cjk-misc bopomofo))
(ignore-errors
(set-frame-font (font-spec :family "Noto Sans Mono" :size 18))
(dolist (script '(han cjk-misc bopomofo))
(set-fontset-font
(frame-parameter nil 'font)
script
(font-spec :name "Noto Sans CJK SC" :size 12))))
(frame-parameter nil 'font)
script
(font-spec :name "Noto Sans CJK SC" :size 18)))))

(setq-default line-spacing 4)

Expand Down Expand Up @@ -45,7 +48,7 @@
(insert q1)
(setq q2 "\n Q: 昨天工作有什么进展吗?\n A: \n")
(insert q2)
(setq q3 "\n Q: 昨天计划做的事情没有什么进展吗?\n A: \n")
(setq q3 "\n Q: 昨天计划做的事情有什么进展吗?\n A: \n")
(insert q3)
(setq bl (+ (length q3) (length q2) 1))
(backward-char bl))
Expand Down
37 changes: 31 additions & 6 deletions rc/rc-c.el
Original file line number Diff line number Diff line change
@@ -1,11 +1,36 @@
;;; rc-c.el ---
(use-package ggtags
:ensure t)
;;; rc-c.el --- C/C++ configuration

(require 'use-package)

;; clangd LSP for C/C++ (replaces ggtags)
(use-package lsp-mode
:hook ((c-mode . lsp-deferred)
(c++-mode . lsp-deferred))
:config
(setq lsp-clients-clangd-args
'("--header-insertion=never"
"--background-index"
"--clang-tidy"
"--log=error")))

;; clang-format integration
(use-package clang-format
:ensure t
:bind (:map c-mode-base-map
("C-c f" . clang-format-buffer)))

;; C/C++ code style for bpftrace project
(setq-default c-basic-offset 2)
(setq c-default-style '((c-mode . "linux")
(c++-mode . "linux")
(other . "linux")))

(add-hook 'c-mode-common-hook
(lambda ()
(when (derived-mode-p 'c-mode 'c++-mode 'java-mode)
(ggtags-mode 1))))
(lambda ()
(setq indent-tabs-mode nil)
(c-set-offset 'inline-open 0)
(when (derived-mode-p 'c++-mode)
(setq flycheck-clang-language-standard "c++20"))))

(provide 'rc-c)
;;;
36 changes: 36 additions & 0 deletions rc/rc-delimiters.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
;;; rc-delimiters.el --- Delimiter / parentheses visualization

(require 'use-package)

;; Highlight matching paren when cursor is on one
(show-paren-mode 1)
(setq show-paren-style 'expression ; 高亮整个表达式,而非仅括号
show-paren-delay 0 ; 无延迟
show-paren-when-point-inside-paren t
show-paren-when-point-in-periphery t)

;; Rainbow delimiters — color-code nested parens/braces/brackets by depth
(use-package rainbow-delimiters
:ensure t
:hook (prog-mode . rainbow-delimiters-mode))

;; Paredit — structured editing for Lisp
(use-package paredit
:ensure t
:hook ((emacs-lisp-mode . paredit-mode)
(lisp-mode . paredit-mode)
(scheme-mode . paredit-mode))
:config
(setq paredit-use-hard-newlines nil))



;; Elisp formatting — indent whole buffer on save
(defun rc-format-elisp-buffer ()
(indent-region (point-min) (point-max)))
(add-hook 'emacs-lisp-mode-hook
(lambda ()
(add-hook 'before-save-hook #'rc-format-elisp-buffer nil t)))

(provide 'rc-delimiters)
;;;
27 changes: 26 additions & 1 deletion rc/rc-file-management.el
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
;;; rc-file-management.el ---
;;; rc-file-management.el --- File and project management

(require 'use-package)

;; Projectile - Project management (used by treemacs)
(use-package projectile
:ensure t
:config
(projectile-mode +1)
;; Use ripgrep if available (faster than default grep)
;; Projectile will automatically detect and use rg if installed
(when (executable-find "rg")
(setq projectile-grep-command "rg --color=never --files-with-matches"))
:bind
(:map global-map
("C-c p s" . projectile-grep) ; Search keyword in project
("C-c p f" . projectile-find-file) ; Find file in project
("C-c p r" . projectile-replace) ; Replace in project
("C-c p p" . projectile-switch-project) ; Switch project
("C-c p d" . projectile-find-dir))) ; Find directory in project

;; Treemacs - File tree explorer
(use-package treemacs
:ensure t
:defer t
Expand All @@ -10,10 +31,14 @@
("C-x t C-p" . treemacs-previous-project)
("C-x t C-f" . treemacs-create-file)))

;; Treemacs integration with projectile
(use-package treemacs-projectile
:after (treemacs projectile)
:ensure t)

;; Note: If ripgrep (rg) is installed, projectile will use it automatically
;; Install: brew install ripgrep (macOS) or apt-get install ripgrep (Linux)

(provide 'rc-file-management)
;;;

37 changes: 22 additions & 15 deletions rc/rc-lsp.el
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,33 @@
(use-package lsp-mode
:ensure t
:init
;; Set the prefix key for LSP commands
(setq lsp-keymap-prefix "C-c l")
;; Performance optimizations
(setq lsp-idle-delay 0.5)
(setq lsp-keymap-prefix "C-c L")
(setq lsp-idle-delay 0.3)
(setq lsp-log-io nil)
(setq lsp-enable-snippet nil)
(setq lsp-auto-guess-root t)
(setq lsp-restart 'auto-restart)
(setq lsp-completion-provider :capf)
:commands (lsp lsp-deferred)
:hook
;; Enable LSP for shell scripts
(sh-mode . lsp)
;; Optional: Enable origami folding if available
(lsp-after-open-hook . (lambda ()
(when (fboundp 'lsp-origami-try-enable)
(lsp-origami-try-enable))))
((sh-mode . lsp)
(c-mode . lsp-deferred)
(c++-mode . lsp-deferred)
(python-mode . lsp-deferred))
:config
;; General LSP settings
(setq lsp-auto-guess-root t)
(setq lsp-restart 'auto-restart)
;; Configure xref to use LSP backend
(add-to-list 'xref-backend-functions 'lsp-xref-backend))
(when (fboundp 'lsp-xref-backend)
(add-to-list 'xref-backend-functions 'lsp-xref-backend)))

;; lsp-ui - UI enhancements for LSP
(use-package lsp-ui
:ensure t
:config
(setq lsp-ui-doc-enable t
lsp-ui-doc-position 'at-point
lsp-ui-sideline-enable t
lsp-ui-sideline-show-hover t)
:bind (:map lsp-mode-map
("C-c L d" . lsp-ui-doc-show)))

(provide 'rc-lsp)
;;;
6 changes: 5 additions & 1 deletion rc/rc-org.el
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@
(let ((done (or (not org-state) ;; nil when no TODO list
(member org-state org-done-keywords)))
(file (buffer-file-name))
(agenda (funcall (ad-get-orig-definition 'org-agenda-files)) ))
;; Get original org-agenda-files without advice
(agenda (progn
(advice-remove 'org-agenda-files 'dynamic-agenda-files-advice)
(prog1 (org-agenda-files)
(advice-add 'org-agenda-files :filter-return #'dynamic-agenda-files-advice)))))
(unless (member file agenda)
(if done
(save-excursion
Expand Down
Loading