~cytrogen/.emacs.d

5e25bc7ef1918830a1cae3b6e468c2f82dc5640b — Cytrogen a month ago 9e16518
feat(dev): 添加 LSP、Tree-sitter、终端和代码编辑工具

LSP: Eglot 自动检测已安装服务器(JS/TS/Python/CSS/HTML),
仅在服务器可用时启用

Tree-sitter: 语法树精确高亮(level 4),自动 remap 到 -ts-mode
(js-ts-mode、python-ts-mode 等)

终端: Eat 终端模拟器,适配 Darcula 主题 16 色 ANSI 调色板,
128KB 回滚缓冲区,Semi-char 模式 C-c 前缀滚动

代码编辑: Rainbow-delimiters 彩色括号 + Symbol-overlay 符号高亮
(M-i)+ Multiple-cursors 多光标 + Move-dup 移动/复制行
+ Whole-line-or-region 整行操作 + Whitespace-cleanup-mode
+ Highlight-escape-sequences + Show-paren + Electric-pair
+ Flymake 语法检查 + Eldoc 文档提示 + Restclient HTTP 测试
+ Rainbow-mode 颜色预览 + Origami 代码折叠 + Regex-tool
+ Consult-eglot LSP 符号搜索
1 files changed, 168 insertions(+), 1 deletions(-)

M config/pkg-dev.el
M config/pkg-dev.el => config/pkg-dev.el +168 -1
@@ 1,6 1,9 @@
;;; pkg-dev.el --- Development tools and programming support -*- lexical-binding: t -*-

;; Copyright (C) 2024 Cytrogen
;; Copyright (C) 2026 Cytrogen

;; Many package selections and configurations adapted from
;; Steve Purcell's emacs.d: https://github.com/purcell/emacs.d

;; This file contains:
;; - Rainbow delimiters for code readability


@@ 31,8 34,172 @@
(setq show-paren-delay 0)
(setq show-paren-style 'parenthesis)

;; JS/TS/JSON 缩进 2 格
(setq js-indent-level 2)
(setq typescript-ts-mode-indent-offset 2)

;; Development Utilities
;; Helper functions for programming

;; Avy — 2-3 键跳转到屏幕任意位置
(unless (package-installed-p 'avy)
  (package-refresh-contents)
  (package-install 'avy))
(require 'avy)
(setq avy-timeout-seconds 0.3)

;; Multiple Cursors — 多光标编辑
(unless (package-installed-p 'multiple-cursors)
  (package-install 'multiple-cursors))
(require 'multiple-cursors)

;; Symbol Overlay — 高亮/跳转当前符号所有出现
(unless (package-installed-p 'symbol-overlay)
  (package-install 'symbol-overlay))
(require 'symbol-overlay)
(add-hook 'prog-mode-hook #'symbol-overlay-mode)

;; Move-dup — 移动/复制行
(unless (package-installed-p 'move-dup)
  (package-install 'move-dup))
(require 'move-dup)
(global-move-dup-mode 1)
(add-hook 'org-mode-hook (lambda () (move-dup-mode -1)))

;; Whole-line-or-region — 无选区时 C-w/M-w 操作整行
(unless (package-installed-p 'whole-line-or-region)
  (package-install 'whole-line-or-region))
(require 'whole-line-or-region)
(whole-line-or-region-global-mode 1)

;; Whitespace-cleanup-mode — 保存时只清理改过的行的空白
(unless (package-installed-p 'whitespace-cleanup-mode)
  (package-install 'whitespace-cleanup-mode))
(require 'whitespace-cleanup-mode)
(global-whitespace-cleanup-mode 1)

;; Highlight-escape-sequences — 代码中转义序列高亮
(unless (package-installed-p 'highlight-escape-sequences)
  (package-install 'highlight-escape-sequences))
(require 'highlight-escape-sequences)
(add-hook 'prog-mode-hook 'hes-mode)

;; Flymake(内置)— 实时语法检查
(add-hook 'prog-mode-hook 'flymake-mode)

;; 行号(仅编程模式)
(add-hook 'prog-mode-hook 'display-line-numbers-mode)

;; 代码中 URL 可点击
(add-hook 'prog-mode-hook 'goto-address-prog-mode)

;; 注释拼写检查(需系统安装 aspell 或 hunspell)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)

;; Eat — 现代终端模拟器
(unless (package-installed-p 'eat)
  (package-install 'eat))

(with-eval-after-load 'eat
  ;; 关闭闪烁文本,减少视觉干扰
  (setq eat-enable-blinking-text nil)
  ;; 增大回滚缓冲区(默认 131072),方便查看长输出
  (setq eat-term-scrollback-size (* 128 1024))

  ;; Semi-char 模式下用 C-c 前缀滚动回看(不会被 zsh 拦截)
  (define-key eat-semi-char-mode-map (kbd "C-c C-p") #'scroll-down-command)
  (define-key eat-semi-char-mode-map (kbd "C-c C-n") #'scroll-up-command)

  ;; ANSI 调色板适配 darcula 主题 (bg #2B2B2B)
  (custom-set-faces
   '(eat-term-color-0  ((t (:foreground "#1e1e1e" :background "#1e1e1e"))))  ; black
   '(eat-term-color-1  ((t (:foreground "#ff6b68" :background "#ff6b68"))))  ; red
   '(eat-term-color-2  ((t (:foreground "#a8c023" :background "#a8c023"))))  ; green
   '(eat-term-color-3  ((t (:foreground "#d6bf55" :background "#d6bf55"))))  ; yellow
   '(eat-term-color-4  ((t (:foreground "#6a76db" :background "#6a76db"))))  ; blue
   '(eat-term-color-5  ((t (:foreground "#b877db" :background "#b877db"))))  ; magenta
   '(eat-term-color-6  ((t (:foreground "#56b6c2" :background "#56b6c2"))))  ; cyan
   '(eat-term-color-7  ((t (:foreground "#a9b7c6" :background "#a9b7c6"))))  ; white
   '(eat-term-color-8  ((t (:foreground "#6c6c6c" :background "#6c6c6c"))))  ; bright black
   '(eat-term-color-9  ((t (:foreground "#ff8785" :background "#ff8785"))))  ; bright red
   '(eat-term-color-10 ((t (:foreground "#c0d868" :background "#c0d868"))))  ; bright green
   '(eat-term-color-11 ((t (:foreground "#ffe680" :background "#ffe680"))))  ; bright yellow
   '(eat-term-color-12 ((t (:foreground "#88aacc" :background "#88aacc"))))  ; bright blue
   '(eat-term-color-13 ((t (:foreground "#b89ad6" :background "#b89ad6"))))  ; bright magenta
   '(eat-term-color-14 ((t (:foreground "#6ed8c8" :background "#6ed8c8"))))  ; bright cyan
   '(eat-term-color-15 ((t (:foreground "#e8e8e8" :background "#e8e8e8")))))) ; bright white

;; Restclient — 在 buffer 中测试 HTTP 请求
(unless (package-installed-p 'restclient)
  (package-install 'restclient))

;; Rainbow-mode — CSS/Hex 颜色值直接显示对应颜色
(unless (package-installed-p 'rainbow-mode)
  (package-install 'rainbow-mode))
(add-hook 'css-mode-hook 'rainbow-mode)
(add-hook 'html-mode-hook 'rainbow-mode)
(add-hook 'emacs-lisp-mode-hook 'rainbow-mode)

;; Origami — 代码折叠
(unless (package-installed-p 'origami)
  (package-install 'origami))
(add-hook 'prog-mode-hook 'origami-mode)

;; Regex-tool — 交互式正则表达式测试
(unless (package-installed-p 'regex-tool)
  (package-install 'regex-tool))

;; Eldoc — 函数签名/文档自动提示(minibuffer 多行显示)
(setq eldoc-echo-area-use-multiline-p t)

;; Eglot(内置)— LSP 支持(JS/TS/Python/CSS/HTML)
;; 前置: pnpm add -g typescript-language-server typescript
;; 前置: pnpm add -g vscode-langservers-extracted
;; 前置: uv tool install python-lsp-server
(with-eval-after-load 'eglot
  (setq eglot-autoshutdown t))

(defvar my/eglot-server-programs
  '((js-mode . "typescript-language-server")
    (js-ts-mode . "typescript-language-server")
    (typescript-ts-mode . "typescript-language-server")
    (tsx-ts-mode . "typescript-language-server")
    (python-mode . "pylsp")
    (python-ts-mode . "pylsp")
    (css-mode . "vscode-css-language-server")
    (css-ts-mode . "vscode-css-language-server")
    (html-mode . "vscode-html-language-server")
    (html-ts-mode . "vscode-html-language-server"))
  "模式与对应 LSP 服务器可执行文件的映射.")

(defun my/eglot-ensure-if-server ()
  "只在对应 LSP 服务器存在时启用 eglot."
  (when-let* ((server (alist-get major-mode my/eglot-server-programs)))
    (when (executable-find server)
      (eglot-ensure))))

(dolist (entry my/eglot-server-programs)
  (add-hook (intern (concat (symbol-name (car entry)) "-hook"))
            #'my/eglot-ensure-if-server))

(unless (package-installed-p 'consult-eglot)
  (package-install 'consult-eglot))

;; Tree-sitter(内置)— 语法树精确高亮
;; 安装语法: M-x treesit-install-language-grammar RET javascript/typescript/python/...
(setq treesit-font-lock-level 4)

(defvar my/treesit-mode-remap
  '((javascript-mode . (js-ts-mode . javascript))
    (js-json-mode    . (json-ts-mode . json))
    (python-mode     . (python-ts-mode . python))
    (css-mode        . (css-ts-mode . css)))
  "Tree-sitter 模式映射: (旧模式 . (新模式 . 语言)).")

(setq major-mode-remap-alist
      (cl-loop for (old-mode . (new-mode . lang)) in my/treesit-mode-remap
               when (treesit-language-available-p lang)
               collect (cons old-mode new-mode)))

(provide 'pkg-dev)
;;; pkg-dev.el ends here
\ No newline at end of file