170 Commits

Author SHA1 Message Date
laily c95a1d70b1 fix: docker-install skip installed packages and suspend needrestart
Avoid upgrading already-installed packages and restarting unrelated
services on Ubuntu 24.04, where apt-pinvoke -m u overrides NEEDRESTART_MODE.
2026-08-29 14:37:36 +08:00
laily d6eee6465b feat: update mise 2026-08-28 14:49:34 +08:00
laily 2aba5d7162 feat: modify skiff to pouch 2026-08-25 15:32:09 +08:00
laily a0ea27099b feat: add upstream gitea 2026-08-10 12:22:52 +08:00
laily 8072e344ac feat: add ssh2 2026-08-04 14:59:54 +08:00
laily 4382de9ddc feat: improve scan-ip device identification 2026-07-28 15:47:24 +08:00
laily 8f2ebfc3de feat: add skiff to path 2026-07-27 17:48:01 +08:00
laily 6a92e31a90 feat: sudo by default 2026-07-25 22:16:38 +08:00
laily 045242e2c2 feat: sudo by default 2026-07-25 22:12:11 +08:00
laily 6e57abcec6 feat: sudo by default 2026-07-25 22:04:59 +08:00
laily 7654790973 feat: add ssh-harden 2026-07-25 21:57:16 +08:00
laily c974d858be feat: add ssh-harden 2026-07-25 21:49:20 +08:00
laily 5598ad5b3f feat: add ssh-harden 2026-07-25 21:33:52 +08:00
laily 9617bbbd27 feat: add ssh-harden 2026-07-25 21:27:49 +08:00
laily 1e12ae5c6e feat: add ssh-harden 2026-07-25 21:21:09 +08:00
laily b804e42ef1 feat: add ssh-harden 2026-07-25 21:13:15 +08:00
laily c5d99958d4 feat: add init.sh 2026-07-25 21:02:07 +08:00
laily db8a531b92 feat: add ssh-key-only 2026-07-25 20:58:38 +08:00
laily dc58f0c253 feat: modify scan-ip 2026-07-21 23:35:28 +08:00
laily a376995947 feat: update ghostty ssh term 2026-07-14 21:45:02 +08:00
laily ca88abbfc9 feat: add modify docker config 2026-07-02 12:33:40 +08:00
laily b08868cf16 feat: add sudo write 2026-06-27 14:28:18 +08:00
laily 8dcd6e3ac9 fix: add alias for script 2026-06-27 12:00:04 +08:00
laily a43e8bc885 feat: add git-setup 2026-06-27 11:55:41 +08:00
laily c12b212091 fix: init docker 2026-06-27 11:29:07 +08:00
laily 0548056ca4 fix: toggle-resion 2026-06-27 11:20:47 +08:00
laily acac6c3650 feat: update git credential 2026-06-26 11:18:08 +08:00
laily 783965d826 fix: make help.autocorrect compatible with old Git versions
Use numeric 0 in main config so legacy Git does not fail on parse; keep prompt in platform includes for Git 2.36+.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-26 11:15:24 +08:00
laily 9551225ee9 feat: update git credential 2026-06-26 11:10:23 +08:00
laily 84c7f37c53 docs: add AGENTS.md as shared dotfile maintenance conventions
Point Cursor and Claude rules at AGENTS.md for cross-tool agent guidance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 15:19:25 +08:00
laily 67291a9a50 feat: add script catalog and -h help for all dotfile scripts
Introduce ff script -h with auto descriptions, shared help.sh, and usage flags across script/*.sh.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 15:09:35 +08:00
laily 1f6b042b26 feat: split git credential config by OS on Linux and macOS
Use includeIf so Linux prefers libsecret with cache fallback, while macOS keeps osxkeychain.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 11:04:15 +08:00
laily e8aae9738b feat: add nosudo 2026-06-25 10:46:07 +08:00
laily 0e7fe55474 fix: support ubuntu 2026-06-10 10:26:05 +08:00
laily ff420521ac feat: add script to change debian source 2026-06-04 15:32:13 +08:00
laily 77c9259ade fix: update docker mirror to tsinghua source 2026-06-04 15:26:12 +08:00
laily 81bebadff8 fix: init fish 2026-06-01 00:41:46 +08:00
laily 058c2e58af fix: <C-p> for sidekick 2026-06-01 00:26:19 +08:00
laily e63107f6ff fix: ff update 2026-06-01 00:23:39 +08:00
laily ec19670ebc feat: modify dirsize 2026-05-30 14:30:46 +08:00
laily d2f1ca33a0 feat: add dirsize 2026-05-30 14:21:17 +08:00
laily 21b12675e9 fix: dirsize 2026-05-30 13:42:51 +08:00
laily 609536a15c feat: add move window of tmux 2026-05-27 10:15:53 +08:00
laily cccf5fd750 feat: move windows 2026-05-27 09:50:02 +08:00
laily 64a059b8ec fix: modify sidekick width 2026-05-27 09:43:32 +08:00
laily 082781b4d2 feat: add tags 2026-05-26 17:51:15 +08:00
laily 4e8e3b7073 feat: add notify command, modify sidekick with tmux 2026-05-26 16:54:53 +08:00
laily c32e8b4015 feat: add mise config 2026-05-26 13:07:40 +08:00
laily 137e67503a feat: scan-ip support port 2026-05-25 21:36:14 +08:00
laily d82c9af650 feat: add ghostty 2026-05-24 14:14:38 +08:00
laily a53a3e0030 fix: unzip nvim package 2026-05-21 17:45:49 +08:00
laily 01998497e3 fix: scan-ip 2026-05-17 14:03:17 +08:00
laily 6abd1b7185 fix: neovim install support aarch64 2026-05-14 17:22:24 +08:00
laily b938a04538 fix: neovim install support aarch64 2026-05-14 17:17:37 +08:00
laily 27e5c11ea9 feat: add dirsize 2026-05-13 22:44:10 +08:00
laily 68e6780238 feat: add ghostty 2026-05-12 11:12:14 +08:00
laily e6bff850c3 feat: add lazygit install 2026-05-11 18:01:05 +08:00
laily c2439bfe72 feat: disable some features of snacks 2026-05-10 14:50:09 +08:00
laily fd0d59a7df fix: set zsh as default shell when init it 2026-05-10 14:13:37 +08:00
laily 9edcf1ffb4 fix: load telescopt fail 2026-05-10 14:04:01 +08:00
laily f8635b0969 feat: add zsh 2026-05-10 13:55:06 +08:00
laily 8e32f5c533 feat: update sidekick toggle 2026-05-10 13:44:39 +08:00
laily 34273ee6d5 feat: update toggle sidekick 2026-05-10 12:43:14 +08:00
laily 34f619c172 feat: update toggle region 2026-05-09 19:17:31 +08:00
laily 1101796d39 feat: update toggle region 2026-05-09 19:11:29 +08:00
laily 6be4389e2e feat: update toggle region 2026-05-09 19:08:35 +08:00
laily 89d808a864 feat: update toggle region 2026-05-09 19:02:21 +08:00
laily 67c5128840 feat: update toggle region 2026-05-09 18:32:47 +08:00
laily 2950f6b442 feat: update nvim config 2026-04-01 02:50:48 +08:00
laily 524dd75eb3 feat: update nvim config 2026-04-01 02:28:02 +08:00
laily 9fd296a777 feat: modify sidekick 2026-04-01 00:47:22 +08:00
laily 4ec54aeff7 feat: update nvim config 2026-03-31 16:26:32 +08:00
laily 3bc05c5abb feat: add glow 2026-03-30 12:13:18 +08:00
laily 61c1f088c7 feat: add journalctl --user 2026-03-24 11:35:15 +08:00
laily e4296ed34d feat: update fish 2026-03-24 11:02:45 +08:00
laily 478449d3a8 feat: update 2026-03-18 17:35:07 +08:00
laily df359c6e07 feat: add vim function 2026-03-18 17:34:47 +08:00
laily 96c923d6cc feat: update bigfiles search 2026-03-02 15:38:33 +08:00
laily 9587780c13 feat: add mise env 2026-02-12 10:53:38 +08:00
laily d58bfd63f4 fix: ctrl+p in neovim 2026-01-17 22:24:19 +08:00
laily ff4b73d8ac feat: add mise 2026-01-17 22:04:21 +08:00
laily fba3be8fd8 fix: nvim 2026-01-17 21:52:18 +08:00
laily 72fb4fc412 feat: update nvom 2026-01-17 14:45:11 +08:00
laily 108a8420f9 feat: update nvim and add gemini cli 2026-01-17 14:00:12 +08:00
laily 5e3ed80e39 feat: update nvim script 2026-01-17 13:38:17 +08:00
laily ddc76e7695 feat: update gitconfig 2025-12-26 11:50:12 +08:00
laily 9d15bcc3c4 feat: add scan-port script 2025-12-16 20:59:34 +08:00
laily f3064c2370 feat: support scanip 2025-12-16 15:33:54 +08:00
laily e4e6281742 fix: dc alias 2025-12-13 19:09:30 +08:00
laily 17b983ffb4 feat: support set debian apt source 2025-12-13 15:29:20 +08:00
laily 7f087b9e5f fix: cursor config 2025-12-02 16:23:42 +08:00
laily 5a78b07c51 feat: update 2025-12-01 19:55:54 +08:00
laily 8de370bdf5 feat: update readme 2025-11-29 19:22:45 +08:00
laily ab0812037d feat: add install mihomo 2025-11-29 19:18:33 +08:00
laily 1fe69f6c95 feat: support nvm(fnm) 2025-11-28 16:16:36 +08:00
laily 9bd43f9f9c feat: update git alias 2025-11-18 14:25:09 +08:00
laily d9bce3b9ee feat: modify golangci-lint config 2025-11-11 20:18:34 +08:00
laily 8de75b7faf feat: update golangci-lint config 2025-11-11 20:10:47 +08:00
laily 78b6f9e6c5 feat: add build_script 2025-10-22 11:40:12 +08:00
laily d80f88dbb4 feat: add ff update 2025-10-19 18:13:44 +08:00
laily 01029777d5 feat: update ff command 2025-10-19 18:06:50 +08:00
laily 03b384b819 feat: add command 2025-10-19 18:02:14 +08:00
laily 2bd26fc9ef feat: 增强用户密码设置功能,支持交互式和非交互式环境 2025-07-17 12:23:23 +08:00
laily 246f230b7f feat: 更新代理设置并添加用户初始化脚本 2025-07-17 12:18:01 +08:00
laily 4bf69165e0 feat: modify filename 2025-07-10 11:08:16 +08:00
laily 239640a996 feat: update git and vscode config 2025-07-09 11:21:21 +08:00
laily 2b04c95e48 feat: add vscode keybinding 2025-06-20 21:14:53 +08:00
laily aab4f145ce feat: add pnpm 2025-06-19 16:25:40 +08:00
laily 1189ac8fd1 fix: install golang 2025-02-26 17:24:45 +08:00
laily bbb57da4b5 feat: modify github git config 2025-02-26 17:20:21 +08:00
laily 7df9df1801 feat: modify github git config 2025-02-26 17:10:44 +08:00
laily a55e3ca1e2 feat: add gvm 2025-02-19 17:21:00 +08:00
laily 6c0d9c3d1d feat: add docker compose alias 2025-01-15 17:37:43 +08:00
laily 21058acac5 feat: add docker compose alias 2025-01-15 17:32:26 +08:00
laily 490e9eff3a feat: add docker compose alias 2025-01-15 17:29:00 +08:00
laily ffc4fcd91f fix: add shortcut for tmux mouse on 2025-01-08 11:24:52 +08:00
laily 0bcae45cd9 fix: script function 2024-11-27 11:41:10 +08:00
laily d72b02118c Merge branch 'main' of github.com:hilaily/.dotfile 2024-11-27 11:30:06 +08:00
laily bb752943a5 fix: update fish script 2024-11-27 11:29:56 +08:00
laily d3f12850bd fix: merge 2024-11-22 11:20:48 +00:00
laily 878d67c8e4 Merge branch 'main' of github.com:hilaily/.dotfile 2024-11-18 16:47:35 +08:00
laily 3f7fabc88a chore: update plugin 2024-11-18 16:47:14 +08:00
laily 5dca7835bf fix: iterm mouse scroll 2024-11-18 16:40:30 +08:00
laily cad5e667f8 fix: docker install 2024-11-18 16:32:16 +08:00
laily 11aeacdc88 fix: nvim install 2024-11-18 16:30:29 +08:00
laily d6135e1ac5 feat: add docker-install.sh 2024-11-17 20:11:55 +08:00
laily 8f4ebb0071 fix: fish 2024-11-11 15:58:55 +08:00
laily 5517cd4186 fix: fish 2024-11-11 15:56:56 +08:00
laily f2da334604 fix: mason 2024-11-11 00:27:45 +08:00
laily 0ceb4dc061 fix: modify font 2024-11-10 23:50:11 +08:00
laily eddda52c71 Merge branch 'main' of github.com:hilaily/.dotfile 2024-11-10 23:49:57 +08:00
laily 3c370d80cc fix: 2024-11-10 23:49:52 +08:00
laily 4f10716dcd fix: merge 2024-11-07 11:14:04 +08:00
laily 25871a335b fix: nvim config 2024-11-06 23:23:01 +08:00
laily 80d0449402 fix: install python 2024-11-06 23:09:01 +08:00
laily 041f993017 fix: add command reset-proxy 2024-11-06 23:01:01 +08:00
laily aec3961983 feat: add font 2024-11-06 22:57:50 +08:00
laily efdbffa489 fix: modify font 2024-11-06 18:01:38 +08:00
laily 6ac8de0999 feat: add install firacode 2024-11-06 12:50:59 +08:00
laily dfa04656dd feat: add nvim init 2024-11-05 12:07:29 +08:00
laily 89b7a7c969 Merge branch 'main' of github.com:hilaily/.dotfile 2024-11-04 14:11:51 +08:00
laily 12af360c37 fix: node path 2024-11-01 17:44:30 +08:00
laily 66a781c5d0 feat: modify git remote 2024-10-25 18:14:23 +08:00
laily eaa9c6d924 feat: add iterm2 2024-10-25 18:13:08 +08:00
laily ff4629cafe feat: modify install nvim 2024-10-25 18:02:02 +08:00
laily 8b609eb959 feat: add croncheck.sh 2024-10-15 11:08:30 +08:00
laily b6dc6b839e feat: add sudoo 2024-09-26 11:11:03 +08:00
laily ddb09fb2cf fix: modify gitignore 2024-08-12 14:29:32 +08:00
laily eeb97adf94 feat: add neotest 2024-08-07 15:14:42 +08:00
laily 67c9d89f41 fix: add alias 2024-08-05 17:25:38 +08:00
laily 30dfd1a02d Merge branch 'main' of github.com:hilaily/.dotfile 2024-08-03 17:56:33 +08:00
laily 9d0b63a2e9 Merge branch 'main' of https://github.com/hilaily/.dotfile into main 2024-08-03 08:05:55 +00:00
laily f139016c25 fix 2024-08-03 16:03:23 +08:00
laily a159a4179e fix 2024-08-03 16:02:45 +08:00
laily 8991b192ea temp 2024-08-03 15:42:13 +08:00
laily 8241518dd2 fix: add resurrect for tmux 2024-07-29 11:43:39 +08:00
laily 4812514474 fix: outline width 2024-07-22 17:06:30 +08:00
laily 3ba2f0b62c fix: git editor 2024-07-22 08:54:47 +00:00
laily c22f3b28b0 fix: merge 2024-07-22 08:54:04 +00:00
laily 8433ab381e fix: modify per 2024-07-22 08:53:49 +00:00
laily 5a9193eb38 fix: modify useless plugin 2024-07-19 17:04:44 +08:00
laily dc376f31e3 fix: remove useless code 2024-06-28 15:33:38 +08:00
laily 0247a4c2a0 merge 2024-06-22 00:09:57 +08:00
laily a64b47a65f feat: add shortcut of swith pane 2024-06-20 15:33:12 +08:00
laily 785d8bde8c feat: add tpm for tmux 2024-06-19 12:22:18 +08:00
laily d97fb14d1f fix: modify mason server 2024-06-12 17:49:36 +08:00
laily 8c5df554ed chrore: update fish script 2024-06-11 23:06:19 +08:00
laily a9f48d2d59 fix: add git alias 2024-06-11 17:53:43 +08:00
laily 7bb20c64e2 fix: modify add to path 2024-06-08 17:16:53 +08:00
laily fd96710321 fix: modify fish/git init script 2024-06-08 16:24:22 +08:00
131 changed files with 10573 additions and 1343 deletions
+46
View File
@@ -0,0 +1,46 @@
.PHONY: image tag version
# 默认架构
GOOS ?= linux
GOARCH ?= $(shell go env GOARCH)
# 常用架构组合
PLATFORMS ?= linux/amd64,linux/arm64
# Docker 构建
docker-local:
$(MAKE) check-image-name
GOOS=$(GOOS) GOARCH=$(GOARCH) .build_scripts/build_go.sh
GOOS=$(GOOS) GOARCH=$(GOARCH) .build_scripts/build_image.sh $(IMAGE_NAME) Dockerfile.local
docker-local-amd64:
$(MAKE) check-image-name
GOOS=linux GOARCH=amd64 .build_scripts/build_go.sh
GOOS=linux GOARCH=amd64 .build_scripts/build_image.sh $(IMAGE_NAME) Dockerfile.local
docker-local-arm64:
$(MAKE) check-image-name
GOOS=linux GOARCH=arm64 .build_scripts/build_go.sh
GOOS=linux GOARCH=arm64 .build_scripts/build_image.sh $(IMAGE_NAME) Dockerfile.local
docker-local-multiarch:
$(MAKE) check-image-name
make build-all-multiarch
PLATFORM=$(PLATFORMS) .build_scripts/build_image.sh $(IMAGE_NAME) Dockerfile.local
check-image-name:
@if [ -z "$(IMAGE_NAME)" ]; then \
echo "IMAGE_NAME is not set"; \
exit 1; \
fi; \
tag:
@VERSION=$$(cat VERSION); \
echo "Creating tag: $$VERSION"; \
git tag $$VERSION; \
git push origin $$VERSION; \
echo "Tag $$VERSION created and pushed successfully"
version: .build_scripts/version.sh
@.build_scripts/version.sh "$(filter-out version,$(MAKECMDGOALS))" "$(VERSION)"
+250
View File
@@ -0,0 +1,250 @@
# Scripts 使用说明
这个目录包含项目的构建和版本管理脚本。
## 文件说明
- `Makefile`: 构建、推送 Docker 镜像和版本管理的自动化脚本
- `version.sh`: 版本号管理脚本
## Makefile 使用
### 可配置的环境变量
- `IMAGE_NAME`: Docker 镜像名称
### 独立使用
#### 1. 使用默认镜像名
```bash
cd scripts
make image
```
#### 2. 使用自定义镜像名
```bash
cd scripts
IMAGE_NAME=myregistry/myimage make image
```
或者:
```bash
export IMAGE_NAME=myregistry/myimage
cd scripts
make image
```
### 在其他 Makefile 中引用
有多种方式可以在其他 Makefile 中引用这个 Makefile:
#### 方式一:使用 `$(MAKE) -C` 调用子目录(推荐)
在项目根目录创建主 Makefile:
```makefile
.PHONY: build-image
# 定义镜像名称
IMAGE_NAME = myregistry/myproject
# 调用 scripts 目录下的 Makefile
build-image:
IMAGE_NAME=$(IMAGE_NAME) $(MAKE) -C scripts image
# 或者使用 export 导出环境变量
build-image-export:
export IMAGE_NAME=$(IMAGE_NAME) && $(MAKE) -C scripts image
```
使用:
```bash
make build-image
```
#### 方式二:使用 `include` 包含
在项目根目录的 Makefile 中:
```makefile
# 设置变量(会覆盖被包含文件中的默认值)
IMAGE_NAME = myregistry/myproject
# 包含 scripts 目录的 Makefile
include scripts/Makefile
# 现在可以直接调用 image 目标
.PHONY: build
build: image
```
使用:
```bash
make build
```
**注意**: 使用 `include` 时,相对路径会基于主 Makefile 的位置,可能需要调整路径。
#### 方式三:环境变量传递(跨多层 Makefile)
根目录 `Makefile`:
```makefile
.PHONY: all
# 设置并导出环境变量,使所有子 make 都能访问
export IMAGE_NAME = myregistry/myproject
export VERSION = v1.0.0
all:
@echo "Building with IMAGE_NAME=$(IMAGE_NAME)"
$(MAKE) -C scripts image
```
#### 方式四:通过命令行传递多个变量
```bash
IMAGE_NAME=myregistry/myimage VERSION=v2.0.0 make -C scripts image
```
### 完整示例
假设项目结构:
```
/project-root
├── Makefile # 主 Makefile
├── scripts/
│ ├── Makefile # 本文件
│ └── version.sh
└── ...
```
主 `Makefile` 内容示例:
```makefile
.PHONY: help build-backend build-frontend build-all
# 项目配置
PROJECT_NAME = myproject
REGISTRY = docker.io/myorg
BACKEND_IMAGE = $(REGISTRY)/$(PROJECT_NAME)-backend
FRONTEND_IMAGE = $(REGISTRY)/$(PROJECT_NAME)-frontend
help:
@echo "Available targets:"
@echo " build-backend - Build and push backend image"
@echo " build-frontend - Build and push frontend image"
@echo " build-all - Build and push all images"
build-backend:
@echo "Building backend image..."
IMAGE_NAME=$(BACKEND_IMAGE) $(MAKE) -C scripts image
build-frontend:
@echo "Building frontend image..."
IMAGE_NAME=$(FRONTEND_IMAGE) $(MAKE) -C scripts image
build-all: build-backend build-frontend
@echo "All images built successfully!"
# 也可以创建版本管理的快捷方式
version:
$(MAKE) -C scripts version $(filter-out $@,$(MAKECMDGOALS))
# 允许传递额外参数
%:
@:
```
使用示例:
```bash
# 构建后端镜像
make build-backend
# 构建前端镜像
make build-frontend
# 构建所有镜像
make build-all
# 版本管理
make version patch
make version v1.2.3
```
## 版本管理
### 基本用法
```bash
# 查看当前版本和帮助
make version
# 设置特定版本
make version v1.0.0
# 或者
make version VERSION=v1.0.0
# 递增版本
make version patch # v1.0.0 -> v1.0.1
make version minor # v1.0.0 -> v1.1.0
make version major # v1.0.0 -> v2.0.0
# 预发布版本
make version pre # v1.0.0 -> v1.0.0-rc.1
make version pre alpha # v1.0.0 -> v1.0.0-alpha.1
make version pre beta # v1.0.0 -> v1.0.0-beta.1
make version pre rc 2 # v1.0.0 -> v1.0.0-rc.2
```
## 创建标签
```bash
# 基于 VERSION 文件创建并推送 Git 标签
make tag
```
## 注意事项
1. **环境变量优先级**:
- 命令行传递 > 父 Makefile export > 本 Makefile 默认值
2. **工作目录**:
- 使用 `$(MAKE) -C scripts` 会切换到 scripts 目录执行
- 注意脚本中的相对路径问题
3. **变量传递**:
- `IMAGE_NAME=xxx $(MAKE)`: 只对当前 make 有效
- `export IMAGE_NAME=xxx; $(MAKE)`: 对所有子 make 有效
- `export IMAGE_NAME=xxx` 后再调用: 对整个 shell 会话有效
4. **调试技巧**:
```bash
# 查看实际使用的变量值
make -C scripts image -n # 干运行,只显示命令不执行
```
## 扩展建议
如果需要更复杂的配置,可以创建配置文件:
```makefile
# config.mk
PROJECT_NAME = myproject
REGISTRY = docker.io/myorg
VERSION = v1.0.0
# 在主 Makefile 中
include config.mk
export IMAGE_NAME = $(REGISTRY)/$(PROJECT_NAME)
```
这样可以将配置集中管理,便于维护。
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
# Build Go binary
# Args:
# 1. OUTPUT_DIR: output directory, default is ./output, the full output directory is $OUTPUT_DIR/$GOOS-$GOARCH
set -e
if [ -z $GOOS ]; then
echo "GOOS is not set"
exit 1
fi
if [ -z $GOARCH ]; then
echo "GOARCH is not set"
exit 1
fi
OUTPUT_DIR=${1:-./output/$GOOS-$GOARCH}
mkdir -p $OUTPUT_DIR/
go build -o $OUTPUT_DIR/server ./cmd/
if [ -d ./conf ]; then
mkdir -p $OUTPUT_DIR/conf/
cp -r ./conf/* $OUTPUT_DIR/conf/
fi
if [ -d ./scripts ]; then
mkdir -p $OUTPUT_DIR/scripts/
cp -r ./scripts/* $OUTPUT_DIR/scripts/
fi
if [ -f ./scripts/Makefile ]; then
cp ./scripts/Makefile $OUTPUT_DIR/
fi
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
# Build Docker image
# Args:
# 1. IMAGE_NAME: image name, required
# 2. DOCKER_FILE: docker file, default is Dockerfile
set -e
IMAGE_NAME=$1
DOCKER_FILE=${2:-Dockerfile}
if [ -z "$IMAGE_NAME" ]; then
echo "IMAGE_NAME is not set";
exit 1;
fi;
VERSION=$(cat VERSION);
echo "Building image: $IMAGE_NAME:$VERSION with Dockerfile: $DOCKER_FILE";
docker build -t $IMAGE_NAME:$VERSION -f $DOCKER_FILE .;
docker push $IMAGE_NAME:$VERSION;
if [[ "$VERSION" != *"-"* ]]; then
echo "This is a stable release, also tagging as latest";
docker tag $IMAGE_NAME:$VERSION $IMAGE_NAME:latest;
docker push $IMAGE_NAME:latest;
echo "Latest tag pushed successfully";
else
echo "This is a pre-release version, skipping latest tag";
fi;
echo "Image built and pushed successfully: $IMAGE_NAME:$VERSION"
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
# Build Web
set -e
if [ -z $GOOS ]; then
echo "GOOS is not set"
exit 1
fi
if [ -z $GOARCH ]; then
echo "GOARCH is not set"
exit 1
fi
OUTPUT_DIR=${1:-./output/$GOOS-$GOARCH}
cd web
pnpm install
pnpm build
cd ..
mkdir -p $OUTPUT_DIR/
rm -rf $OUTPUT_DIR/web/*
mkdir -p $OUTPUT_DIR/web/
cp -r web/out/* $OUTPUT_DIR/web/
+152
View File
@@ -0,0 +1,152 @@
#!/bin/bash
# Version management script
# Args:
# 1. ARGS: arguments, optional
# 2. VERSION_VAR: version variable, optional
set -e
ARGS="$1"
VERSION_VAR="$2"
CURRENT_VERSION=$(cat VERSION)
show_usage() {
echo "Current version: $CURRENT_VERSION"
echo "Usage:"
echo " make version VERSION=v1.0.0 # Set specific version"
echo " make version v1.0.0 # Set specific version"
echo " make version patch # Increment patch version"
echo " make version minor # Increment minor version"
echo " make version major # Increment major version"
echo " make version pre # Add/increment pre-release (default: rc)"
echo " make version pre alpha # Add alpha pre-release"
echo " make version pre beta # Add beta pre-release"
echo " make version pre rc # Add rc pre-release"
echo " make version pre alpha 2 # Add specific alpha version"
}
parse_version() {
local version="$1"
# Remove 'v' prefix and split by '-'
local clean_version="${version#v}"
local base_version="${clean_version%-*}"
local pre_release=""
if [[ "$clean_version" == *"-"* ]]; then
pre_release="${clean_version#*-}"
fi
# Split base version
IFS='.' read -r major minor patch <<< "$base_version"
echo "$major $minor $patch $pre_release"
}
increment_version() {
local type="$1"
local version_parts
read -r major minor patch pre_release <<< "$(parse_version "$CURRENT_VERSION")"
case "$type" in
"patch")
patch=$((patch + 1))
echo "v$major.$minor.$patch"
;;
"minor")
minor=$((minor + 1))
patch=0
echo "v$major.$minor.$patch"
;;
"major")
major=$((major + 1))
minor=0
patch=0
echo "v$major.$minor.$patch"
;;
esac
}
handle_prerelease() {
local args=($1)
local version_parts
read -r major minor patch pre_release <<< "$(parse_version "$CURRENT_VERSION")"
local base_version="$major.$minor.$patch"
local pre_type="rc"
local pre_num="1"
# Parse arguments
if [[ ${#args[@]} -ge 3 ]]; then
# make version pre alpha 2 (明确指定版本号)
pre_type="${args[1]}"
pre_num="${args[2]}"
elif [[ ${#args[@]} -ge 2 ]]; then
# make version pre alpha (指定类型,智能处理版本号)
pre_type="${args[1]}"
if [[ -n "$pre_release" ]]; then
# 当前已经是 pre-release
IFS='.' read -r current_type current_num <<< "$pre_release"
if [[ "$current_type" == "$pre_type" ]]; then
# 相同类型,递增版本号
pre_num=$((current_num + 1))
else
# 不同类型,重置为 1
pre_num="1"
fi
else
# 当前是正式版本,从 1 开始
pre_num="1"
fi
else
# make version pre (智能处理)
if [[ -n "$pre_release" ]]; then
# 当前已经是 pre-release,递增版本号
IFS='.' read -r current_type current_num <<< "$pre_release"
pre_type="$current_type"
pre_num=$((current_num + 1))
else
# 当前是正式版本,添加默认 pre-release
pre_type="rc"
pre_num="1"
fi
fi
echo "v$base_version-$pre_type.$pre_num"
}
update_version() {
local new_version="$1"
echo "Updating version from $CURRENT_VERSION to $new_version"
echo "$new_version" > VERSION
git add .
git commit -m "update version to $new_version"
git push origin HEAD
echo "[$new_version] Version file updated and pushed successfully"
}
main() {
if [[ -n "$ARGS" ]]; then
local first_arg="${ARGS%% *}"
case "$first_arg" in
"patch"|"minor"|"major")
new_version=$(increment_version "$first_arg")
;;
"pre")
new_version=$(handle_prerelease "$ARGS")
;;
*)
new_version="$first_arg"
;;
esac
update_version "$new_version"
elif [[ -n "$VERSION_VAR" ]]; then
update_version "$VERSION_VAR"
else
show_usage
fi
}
main "$@"
+10
View File
@@ -0,0 +1,10 @@
---
description: dotfile 维护约定(详见 AGENTS.md)
alwaysApply: true
---
# dotfile 项目
修改本仓库前请先阅读并遵循根目录 **[AGENTS.md](../AGENTS.md)** 中的维护约定(目录结构、`*-install` / `*-init`、脚本 `-h`、`ff` 入口、软链 init 等)。
AGENTS.md 为跨工具单一事实来源(Cursor、Claude Code、Codex 等均可使用)。
+4
View File
@@ -6,3 +6,7 @@ _set_env_*.sh
_set_env.sh _set_env.sh
log log
cn.sh cn.sh
__pycache__
Makefile
.claude/
script/clash.sh
-313
View File
@@ -1,313 +0,0 @@
run:
tests: false
timeout: 1m
linters:
enable:
- govet
- errcheck
- staticcheck
- ineffassign
- typecheck
- exportloopref
- bodyclose
- gofmt
- misspell
- gosimple
- stylecheck
- revive
- errorlint # finds code that will cause problems with the error wrapping scheme introduced in Go 1.13
disable-all: true
linters-settings:
errcheck:
exclude-functions:
- io/ioutil.ReadFile
- io.Copy(*bytes.Buffer)
- io.Copy(os.Stdout)
- net.(*)
staticcheck:
# SAxxxx checks in https://staticcheck.io/docs/configuration/options/#checks
checks: ["all"]
stylecheck:
checks:
[
"all",
"-ST1000",
"-ST1001",
"-ST1003",
"-ST1016",
"-ST1020",
"-ST1021",
"-ST1022",
]
misspell:
# Correct spellings using locale preferences for US or UK.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
# Default is to use a neutral variety of English.
locale: US
ignore-words: []
revive:
# Maximum number of open files at the same time.
# See https://github.com/mgechev/revive#command-line-flags
# Defaults to unlimited.
max-open-files: 2048
# When set to false, ignores files with "GENERATED" header, similar to golint.
# See https://github.com/mgechev/revive#available-rules for details.
# Default: false
ignore-generated-header: true
# Sets the default severity.
# See https://github.com/mgechev/revive#configuration
# Default: warning
severity: error
# Enable all available rules.
# Default: false
enable-all-rules: false
# Sets the default failure confidence.
# This means that linting errors with less than 0.8 confidence will be ignored.
# Default: 0.8
confidence: 0.1
rules:
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#argument-limit
- name: argument-limit
severity: warning
disabled: false
arguments: [6]
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#atomic
- name: atomic
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#banned-characters
- name: banned-characters
severity: warning
disabled: false
arguments: ["Ω", "Σ", "σ"]
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#bool-literal-in-expr
- name: bool-literal-in-expr
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#call-to-gc
- name: call-to-gc
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#cognitive-complexity
- name: cognitive-complexity
severity: warning
disabled: false
arguments: [14]
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#constant-logical-expr
- name: constant-logical-expr
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-as-argument
- name: context-as-argument
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#context-keys-type
- name: context-keys-type
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#cyclomatic
- name: cyclomatic
severity: warning
disabled: false
arguments: [10]
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#datarace
- name: datarace
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#deep-exit
- name: deep-exit
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#defer
- name: defer
severity: warning
disabled: false
arguments:
- ["call-chain", "loop"]
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#duplicated-imports
- name: duplicated-imports
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#early-return
- name: early-return
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-naming
- name: error-naming
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-return
- name: error-return
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#error-strings
- name: error-strings
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#errorf
- name: errorf
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#exported
- name: exported
severity: warning
disabled: false
arguments:
- "checkPrivateReceivers"
- "sayRepetitiveInsteadOfStutters"
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#function-result-limit
- name: function-result-limit
severity: warning
disabled: false
arguments: [4]
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#function-length
- name: function-length
severity: warning
disabled: false
arguments: [100, 0]
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#get-return
- name: get-return
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#identical-branches
- name: identical-branches
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#if-return
- name: if-return
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#increment-decrement
- name: increment-decrement
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#indent-error-flow
- name: indent-error-flow
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#imports-blacklist
- name: imports-blacklist
severity: warning
disabled: false
arguments:
- "crypto/md5"
- "crypto/sha1"
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#modifies-value-receiver
- name: modifies-value-receiver
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#nested-structs
- name: nested-structs
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#optimize-operands-order
- name: optimize-operands-order
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#package-comments
- name: package-comments
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range
- name: range
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-in-closure
- name: range-val-in-closure
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#range-val-address
- name: range-val-address
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#receiver-naming
- name: receiver-naming
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#redefines-builtin-id
- name: redefines-builtin-id
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#string-of-int
- name: string-of-int
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#string-format
- name: string-format
severity: warning
disabled: false
arguments:
- - "core.WriteError[1].Message"
- "/^([^A-Z]|$)/"
- must not start with a capital letter
- - "fmt.Errorf[0]"
- '/(^|[^\.!?])$/'
- must not end in punctuation
- - panic
- '/^[^\n]*$/'
- must not contain line breaks
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#struct-tag
- name: struct-tag
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#superfluous-else
- name: superfluous-else
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#time-equal
- name: time-equal
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#time-naming
- name: time-naming
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-naming
- name: var-naming
severity: warning
disabled: true
arguments:
- ["ID"] # AllowList
- ["VM"] # DenyList
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#var-declaration
- name: var-declaration
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unconditional-recursion
- name: unconditional-recursion
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-naming
- name: unexported-naming
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-return
- name: unexported-return
disabled: true
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unhandled-error
- name: unhandled-error
severity: warning
disabled: true
# bytes.Buffer.Write: package name, structure name, function name
arguments:
- "fmt.Printf"
- "os.(Create|WriteFile|Chmod)"
- "net.*"
- "bytes.Buffer.WriteString"
- "con.WriteString"
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unnecessary-stmt
- name: unnecessary-stmt
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unreachable-code
- name: unreachable-code
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#useless-break
- name: useless-break
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#waitgroup-by-value
- name: waitgroup-by-value
severity: warning
disabled: false
-48
View File
@@ -1,48 +0,0 @@
setw -g mode-keys vi
#unbind ^b
#set -g prefix 'C-a'
#set -g prefix `
#bind-key ` send-prefix
bind r source-file ~/.tmux.conf \; display-message "Config reloaded"
# 切分面板
# unbind '"'
bind - splitw -v -c '#{pane_current_path}'
# unbind %
bind | splitw -h -c '#{pane_current_path}'
# 开启 24bit 真彩色,tmux > 2.2 开始支持
set -g default-terminal "screen-256color"
set-option -ga terminal-overrides ",*256col*:Tc"
set-option -g mouse on
# 绑定hjkl键为面板切换的上下左右键
bind k select-pane -U # 绑定k为↑
bind j select-pane -D # 绑定j为↓
bind h select-pane -L # 绑定h为←
bind l select-pane -R # 绑定l为→
# 绑定Ctrl+hjkl键为面板上下左右调整边缘的快捷指令
bind -r K resizep -U 10 # 绑定Ctrl+k为往↑调整面板边缘10个单元格
bind -r J resizep -D 10 # 绑定Ctrl+j为往↓调整面板边缘10个单元格
bind -r H resizep -L 10 # 绑定Ctrl+h为往←调整面板边缘10个单元格
bind -r L resizep -R 10 # 绑定Ctrl+l为往→调整面板边缘10个单元格
# 设置tmux的延迟,文档说当有干扰的时候可以设置这个参数,比如影响vim编辑的时候
set -s escape-time 1
# 返回上一个窗口
bind g last-window
# 设置窗口名为当前目录名
set-option -g status-interval 10
set-option -g automatic-rename on
set-option -g automatic-rename-format '#{b:pane_current_path}'
set-option -g set-titles on
#set-option -g set-titles-string "#{session_name} - #{host}"
set-option -g set-titles-string "#{session_name}"
# tmux resurrect
run-shell ~/.tmux/plugins/tmux-resurrect/resurrect.tmux
-153
View File
@@ -1,153 +0,0 @@
# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH
# Path to your oh-my-zsh installation.
export ZSH=$HOME/.oh-my-zsh
# Set name of the theme to load. Optionally, if you set this to "random"
# it'll load a random theme each time that oh-my-zsh is loaded.
# See https://github.com/robbyrussell/oh-my-zsh/wiki/Themes
ZSH_THEME="laily"
# Set list of themes to load
# Setting this variable when ZSH_THEME=random
# cause zsh load theme from this variable instead of
# looking in ~/.oh-my-zsh/themes/
# An empty array have no effect
# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" )
# Uncomment the following line to use case-sensitive completion.
# CASE_SENSITIVE="true"
# Uncomment the following line to use hyphen-insensitive completion. Case
# sensitive completion must be off. _ and - will be interchangeable.
# HYPHEN_INSENSITIVE="true"
# Uncomment the following line to disable bi-weekly auto-update checks.
# DISABLE_AUTO_UPDATE="true"
# Uncomment the following line to change how often to auto-update (in days).
# export UPDATE_ZSH_DAYS=13
# Uncomment the following line to disable colors in ls.
# DISABLE_LS_COLORS="true"
# Uncomment the following line to disable auto-setting terminal title.
# DISABLE_AUTO_TITLE="true"
# Uncomment the following line to enable command auto-correction.
# ENABLE_CORRECTION="true"
# Uncomment the following line to display red dots whilst waiting for completion.
# COMPLETION_WAITING_DOTS="true"
# Uncomment the following line if you want to disable marking untracked files
# under VCS as dirty. This makes repository status check for large repositories
# much, much faster.
# DISABLE_UNTRACKED_FILES_DIRTY="true"
# Uncomment the following line if you want to change the command execution time
# stamp shown in the history command output.
# The optional three formats: "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd"
# HIST_STAMPS="mm/dd/yyyy"
# Would you like to use another custom folder than $ZSH/custom?
# ZSH_CUSTOM=/path/to/new-custom-folder
# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*)
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(
git
extract
docker
docker-compose
)
source $ZSH/oh-my-zsh.sh
# User configuration
# export MANPATH="/usr/local/man:$MANPATH"
# You may need to manually set your language environment
# export LANG=en_US.UTF-8
# Preferred editor for local and remote sessions
# if [[ -n $SSH_CONNECTION ]]; then
# export EDITOR='vim'
# else
# export EDITOR='mvim'
# fi
# Compilation flags
# export ARCHFLAGS="-arch x86_64"
# ssh
# export SSH_KEY_PATH="~/.ssh/rsa_id"
# Set personal aliases, overriding those provided by oh-my-zsh libs,
# plugins, and themes. Aliases can be placed here, though oh-my-zsh
# users are encouraged to define aliases within the ZSH_CUSTOM folder.
# For a full list of active aliases, run `alias`.
#
# Example aliases
# alias zshconfig="mate ~/.zshrc"
# alias ohmyzsh="mate ~/.oh-my-zsh"
# Ctrl+b/f 向后/前移动一个词
bindkey "^b" backward-word
bindkey "^f" forward-word
# Turn off all beeps
unsetopt BEEP
# Turn off autocomplete beeps
# unsetopt LIST_BEEP
# brew
export HOMEBREW_BREW_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git"
export HOMEBREW_CORE_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git"
export HOMEBREW_BOTTLE_DOMAIN="https://mirrors.ustc.edu.cn/homebrew-bottles"
# git
export REVIEW_BASE="master"
# go
export GOPATH=$HOME/go:$HOME/workrepo/go
export PATH=$PATH:$HOME/go/bin
export GOPROXY=goproxy.cn
export GOSUMDB="sum.golang.google.cn"
[ -f ~/.zprofile ] && source ~/.zprofile
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
test -e /home/linuxbrew/.linuxbrew/ && export PATH=$PATH:/home/linuxbrew/.linuxbrew/bin
test -e ~/.pri_scripts && export PATH=$PATH:~/.pri_scripts
# add z
if command -v lua >/dev/null; then
eval "$(lua /usr/local/z.lua/z.lua --init zsh)"
fi
export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH"
export PATH="/usr/local/sbin:$PATH"
# add nvim
export PATH=$PATH:/usr/local/nvim/bin:/usr/local/osx-64/nvim/bin
# for terminal notify
# https://github.com/julienXX/terminal-notifier
alias alert='terminal-notifier -title "Terminal" -message "Done with task! Exit status: $?"' -activate com.apple.Terminal
# git
alias gitb="git branch --show-current | tr -d '\n' | pbcopy"
alias gci="golangci-lint run -c=~/.dotfile/.golangci.yml ./..."
alias gmt="go mod tidy"
alias gtc="go test -gcflags=all=-l -cover ./..."
alias swg="swag init -o docs -g "
alias sws="swagger serve -F=swagger"
function gtr(){
go test -gcflags=all=-l -v -run="$1"
}
fpath+=${ZDOTDIR:-~}/.zsh_functions
+97
View File
@@ -0,0 +1,97 @@
# dotfile 维护约定
个人 dotfiles 仓库(`~/.dotfile`)。本文件供 AI coding agent 与维护者共用:新增或改造配置/脚本时请遵循以下规则。
## 常用命令
```bash
ff script -h # 列出 script/ 下所有脚本及说明
ff script <name> # 运行脚本
make -f Makefile.scripts <name> # 同上(make 入口)
ff region # 切换 CN_REGION(国内/国外镜像)
ff reload # 重载 fish 配置
```
## 目录职责
| 路径 | 用途 |
|------|------|
| `script/` | 可执行脚本(安装、初始化、工具);已加入 fish `PATH` |
| `script/common/` | 脚本共享片段(`help.sh`、`os-arch.sh`) |
| `fish/default.fish` | 共享 fish 配置(进 git) |
| `~/.config/fish/config.fish` | 本机 wrapper,仅 `source` default.fish + 可选 `custom.fish` |
| `fish/functions/`、`fish/completions/` | fish 函数与补全;`fish-init` 会软链到 `~/.config/fish/` |
| `git/`、`nvim/`、`tmux/`、`zsh/`、`cursor/`、`ghostty/`、`mise/` 等 | 各工具**真实配置**,由对应 `*-init` 软链到系统路径 |
| `Makefile.scripts` | `make <script-name>` 运行 `script/<name>.sh` |
## 脚本命名
- **`*-install.sh`**:安装软件/运行时(如 `docker-install`、`nvim-install`、`mise-install`)
- **`*-init.sh`**:把 dotfile 配置**软链接**到系统默认路径(如 `git-init`、`fish-init`、`nvim-init`)
- **工具脚本**:动词或名词(`dns-clean`、`scan-ip`、`nosudo`、`docker-group`、`dirsize`)
- 文件名与 `make` / `ff script` 子命令一致(无扩展名调用)
## 新增脚本 checklist
1. 放在 `script/`,shebang + **一行 `#` 功能描述**(供 `ff script -h` 自动展示)
2. `source "$SCRIPT_DIR/common/help.sh"`,实现 `usage()`,支持 **`-h` / `--help`**
3. 需要平台判断时用 `script/common/os-arch.sh`
4. 依赖国内镜像的安装脚本读取 **`CN_REGION=1`**(`toggle-region` / `ff region`)
5. 若需 fish 补全,更新 `fish/completions/ff.fish`(描述从脚本头注释提取)
## init 脚本模式
- 目标路径已有文件:**先备份**(`*.bak` 或 `*.backup.<timestamp>`),再 `ln -sf` 指向 `~/.dotfile/...`
- 已存在且指向正确的软链:**幂等跳过**
- 示例:`git-init` → `~/.gitconfig`;`nvim-init` → `~/.config/nvim`;`ghostty-init` → 各平台 Ghostty 配置目录
- **fish-init** 特殊:不链整个 `config.fish`,只在顶部插入 `source ~/.dotfile/fish/default.fish`,并链 `functions/`、`completions/`
## install 脚本模式
- 优先用系统包管理器(brew/apt),其次官方安装脚本或 Release 二进制到 `~/.local/bin`
- Debian/Ubuntu 安装类脚本应支持 `CN_REGION` 切换镜像(参考 `docker-install.sh`)
- 需要 root 的脚本在 usage 里写 `sudo`,不要静默假设
## Fish / `ff` 入口
- 跑脚本:`ff script <name>` 或 `ff s <name>`(走 `execute-script.fish`)
- 列脚本:`ff script -h`
- 新增 `ff` 子命令时:改 `fish/functions/ff.fish` + `fish/completions/ff.fish`
## Git 配置
- 公共配置在 `git/.gitconfig`
- **凭据**(所有 Git 版本):`git/git-credential.sh` 写在主配置里,使用 `!$HOME/.dotfile/...`(Git 不展开 `~`)
- macOS:`osxkeychain` → 回退 `store`(`~/.git-credentials`)
- Linux:`libsecret` → 回退 `store`
- 平台扩展(可选):`git/.gitconfig.darwin` / `.gitconfig.linux` 仅在高版本 Git 下通过 includeIf 加载
- `help.autocorrect`:主配置为 `0`(兼容旧 Git);Git ≥ 2.36 的平台文件里为 `prompt`
## 边界(不要做的事)
- 不要把密钥、webhook、本机专用路径写进 git(`script/clash.sh` 等已在 `.gitignore`)
- 不要改 `~/.config/fish/config.fish` 进仓库;本机差异放 `custom.fish`
- 不要为 init 复制整份配置到 `$HOME`;**优先软链接**到 dotfile
- 脚本改动保持最小 diff,风格与相邻脚本一致(bash、`set -euo pipefail` 视情况)
- 未经明确要求不要 `git commit` / `git push`
## 参考模板(新 bash 脚本)
```bash
#!/bin/bash
# 一行功能描述
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: ...
选项:
-h, --help 显示此帮助
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
# ... 正文
```
+3
View File
@@ -0,0 +1,3 @@
# Claude Code
本仓库的 AI / 维护约定见 **[AGENTS.md](./AGENTS.md)**。修改 dotfile、脚本或 init 配置时请遵循该文件。
+47
View File
@@ -0,0 +1,47 @@
.PHONY: help all list
# 脚本目录
SCRIPT_DIR := script
# 默认目标:显示帮助信息
help:
@echo "Dotfile Management"
@echo ""
@echo "Usage: make <script-name>"
@echo " Example: make brew-install"
@echo " make fish-init"
@echo " make zsh-init"
@echo " make docker-clean"
@echo ""
@echo "Available scripts:"
@ls -1 $(SCRIPT_DIR)/*.sh $(SCRIPT_DIR)/*.py 2>/dev/null | xargs -n1 basename | sed 's/\.[^.]*$$//' | sort | sed 's/^/ make /'
@echo ""
@echo "Quick commands:"
@echo " make list List all available scripts"
@echo " make help Show this help message"
# 列出所有可用脚本
list:
@echo "Available scripts in $(SCRIPT_DIR)/"
@ls -1 $(SCRIPT_DIR)/*.sh $(SCRIPT_DIR)/*.py 2>/dev/null | xargs -n1 basename
#################################################################
# 通用规则:自动映射命令到脚本文件
#################################################################
# 匹配所有命令,自动执行对应的脚本文件
%:
@if [ -f "$(SCRIPT_DIR)/$@.sh" ]; then \
echo "Running $(SCRIPT_DIR)/$@.sh..."; \
bash $(SCRIPT_DIR)/$@.sh; \
elif [ -f "$(SCRIPT_DIR)/$@.py" ]; then \
echo "Running $(SCRIPT_DIR)/$@.py..."; \
python3 $(SCRIPT_DIR)/$@.py; \
elif [ "$@" = "init-default-user" ]; then \
echo "Running $(SCRIPT_DIR)/init-default-user.sh (requires sudo)..."; \
sudo bash $(SCRIPT_DIR)/init-default-user.sh; \
else \
echo "Error: No script found for '$@'"; \
echo "Run 'make list' to see available scripts"; \
exit 1; \
fi
+7 -35
View File
@@ -1,43 +1,15 @@
### 使用 ### 使用
```shell ```shell
git clone https://github.com/Laily123/.dotfile.git ~/.dotfile git clone https://github.com/hilaily/.dotfile.git ~/.dotfile
``` ```
### zsh 安装 首先安装 fish
安装 zsh `brew install fish` 或者 `apt install fish`
```shell 然后初始化 fish
https://github.com/robbyrussell/oh-my-zsh/wiki/Installing-ZSH
# macOS ```bash
brew install zsh zsh-completions bash ~/.dotfile/script/fish-install.sh
# CentOS
sudo yum -y install zsh
# Ubuntu
apt install zsh
``` ```
安装 oh-my-zsh
```shell
sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"
```
初始化配置
```shell
ln -sf ~/.dotfile/.zshrc ~/
ln -sf ~/.dotfile/laily.zsh-theme ~/.oh-my-zsh/themes/
ln -sf ~/.dotfile/.tmux.conf ~/
ln -sf ~/.dotfile/.gitconfig ~/.gitconfig
```
### spacevim 安装
安装
`curl -sLf https://spacevim.org/install.sh | bash`
初始化配置
`ln -sf ~/.dotfile/.SpaceVim.d ~/`
#
+291
View File
@@ -0,0 +1,291 @@
// 将键绑定放入此文件中以覆盖默认值
[
{
"key": "alt+cmd+left",
"command": "workbench.action.navigateBack",
},
{
"key": "alt+cmd+right",
"command": "workbench.action.navigateForward",
},
{
"key": "alt+cmd+l",
"command": "editor.action.formatSelection",
"when": "editorHasDocumentFormattingProvider && editorHasSelection && editorTextFocus && !editorReadonly",
},
{
"key": "cmd+k m",
"command": "-workbench.action.editor.changeLanguageMode",
"when": "!notebookEditorFocused",
},
{
"key": "ctrl+j",
"command": "selectNextSuggestion",
"when": "suggestWidgetMultipleSuggestions && suggestWidgetVisible && textInputFocus || suggestWidgetVisible && textInputFocus && !suggestWidgetHasFocusedSuggestion",
},
{
"key": "ctrl+n",
"command": "-selectNextSuggestion",
"when": "suggestWidgetMultipleSuggestions && suggestWidgetVisible && textInputFocus || suggestWidgetVisible && textInputFocus && !suggestWidgetHasFocusedSuggestion",
},
{
"key": "ctrl+k",
"command": "-deleteAllRight",
"when": "textInputFocus && !editorReadonly",
},
{
"key": "ctrl+k",
"command": "selectPrevSuggestion",
"when": "suggestWidgetMultipleSuggestions && suggestWidgetVisible && textInputFocus || suggestWidgetVisible && textInputFocus && !suggestWidgetHasFocusedSuggestion",
},
{
"key": "ctrl+p",
"command": "-selectPrevSuggestion",
"when": "suggestWidgetMultipleSuggestions && suggestWidgetVisible && textInputFocus || suggestWidgetVisible && textInputFocus && !suggestWidgetHasFocusedSuggestion",
},
{
"key": "cmd+i",
"command": "composerMode.agent",
},
{
"key": "space",
"command": "vspacecode.space",
"when": "activeEditorGroupEmpty && focusedView == '' && !whichkeyActive && !inputFocus",
},
{
"key": "space",
"command": "vspacecode.space",
"when": "sideBarFocus && !inputFocus && !whichkeyActive",
},
// {
// "key": "tab",
// "command": "extension.vim_tab",
// "when": "editorTextFocus && vim.active && !inDebugRepl && vim.mode != 'Insert' && editorLangId != 'magit'"
// },
// {
// "key": "tab",
// "command": "-extension.vim_tab",
// "when": "editorTextFocus && vim.active && !inDebugRepl && vim.mode != 'Insert'"
// },
{
"key": "x",
"command": "magit.discard-at-point",
"when": "editorTextFocus && editorLangId == 'magit' && vim.mode =~ /^(?!SearchInProgressMode|CommandlineInProgress).*$/",
},
{
"key": "k",
"command": "-magit.discard-at-point",
},
{
"key": "-",
"command": "magit.reverse-at-point",
"when": "editorTextFocus && editorLangId == 'magit' && vim.mode =~ /^(?!SearchInProgressMode|CommandlineInProgress).*$/",
},
{
"key": "v",
"command": "-magit.reverse-at-point",
},
{
"key": "shift+-",
"command": "magit.reverting",
"when": "editorTextFocus && editorLangId == 'magit' && vim.mode =~ /^(?!SearchInProgressMode|CommandlineInProgress).*$/",
},
{
"key": "shift+v",
"command": "-magit.reverting",
},
{
"key": "shift+o",
"command": "magit.resetting",
"when": "editorTextFocus && editorLangId == 'magit' && vim.mode =~ /^(?!SearchInProgressMode|CommandlineInProgress).*$/",
},
{
"key": "shift+x",
"command": "-magit.resetting",
},
{
"key": "x",
"command": "-magit.reset-mixed",
},
{
"key": "ctrl+u x",
"command": "-magit.reset-hard",
},
{
"key": "y",
"command": "-magit.show-refs",
},
{
"key": "y",
"command": "vspacecode.showMagitRefMenu",
"when": "editorTextFocus && editorLangId == 'magit' && vim.mode == 'Normal'",
},
{
"key": "g",
"command": "-magit.refresh",
"when": "editorTextFocus && editorLangId == 'magit' && vim.mode =~ /^(?!SearchInProgressMode|CommandlineInProgress).*$/",
},
{
"key": "g",
"command": "vspacecode.showMagitRefreshMenu",
"when": "editorTextFocus && editorLangId == 'magit' && vim.mode =~ /^(?!SearchInProgressMode|CommandlineInProgress).*$/",
},
{
"key": "ctrl+j",
"command": "workbench.action.quickOpenSelectNext",
"when": "inQuickOpen",
},
{
"key": "ctrl+k",
"command": "workbench.action.quickOpenSelectPrevious",
"when": "inQuickOpen",
},
{
"key": "ctrl+j",
"command": "selectNextSuggestion",
"when": "suggestWidgetMultipleSuggestions && suggestWidgetVisible && textInputFocus",
},
{
"key": "ctrl+k",
"command": "selectPrevSuggestion",
"when": "suggestWidgetMultipleSuggestions && suggestWidgetVisible && textInputFocus",
},
{
"key": "ctrl+l",
"command": "acceptSelectedSuggestion",
"when": "suggestWidgetMultipleSuggestions && suggestWidgetVisible && textInputFocus",
},
{
"key": "ctrl+j",
"command": "showNextParameterHint",
"when": "editorFocus && parameterHintsMultipleSignatures && parameterHintsVisible",
},
{
"key": "ctrl+k",
"command": "showPrevParameterHint",
"when": "editorFocus && parameterHintsMultipleSignatures && parameterHintsVisible",
},
{
"key": "ctrl+j",
"command": "selectNextCodeAction",
"when": "codeActionMenuVisible",
},
{
"key": "ctrl+k",
"command": "selectPrevCodeAction",
"when": "codeActionMenuVisible",
},
{
"key": "ctrl+l",
"command": "acceptSelectedCodeAction",
"when": "codeActionMenuVisible",
},
// Quick Navigation for file browser
{
"key": "ctrl+h",
"command": "file-browser.stepOut",
"when": "inFileBrowser",
},
{
"key": "ctrl+l",
"command": "file-browser.stepIn",
"when": "inFileBrowser",
},
{
"key": "ctrl+h",
"command": "workbench.action.navigateLeft",
"when": "!inQuickOpen && !suggestWidgetVisible && !parameterHintsVisible && !isInDiffEditor",
},
{
"key": "ctrl+j",
"command": "workbench.action.navigateDown",
"when": "!codeActionMenuVisible && !inQuickOpen && !suggestWidgetVisible && !parameterHintsVisible",
},
{
"key": "ctrl+k",
"command": "workbench.action.navigateUp",
"when": "!codeActionMenuVisible && !inQuickOpen && !suggestWidgetVisible && !parameterHintsVisible",
},
{
"key": "ctrl+l",
"command": "workbench.action.navigateRight",
"when": "!codeActionMenuVisible && !inQuickOpen && !suggestWidgetVisible && !parameterHintsVisible && !isInDiffEditor",
},
// Quick Navigation for diff view
{
"key": "ctrl+h",
"command": "workbench.action.compareEditor.focusSecondarySide",
"when": "isInDiffEditor && !isInDiffLeftEditor",
},
{
"key": "ctrl+h",
"command": "workbench.action.navigateLeft",
"when": "isInDiffEditor && isInDiffLeftEditor",
},
{
"key": "ctrl+l",
"command": "workbench.action.compareEditor.focusPrimarySide",
"when": "isInDiffEditor && isInDiffLeftEditor",
},
{
"key": "ctrl+l",
"command": "workbench.action.navigateRight",
"when": "isInDiffEditor && !isInDiffLeftEditor",
},
{
"key": "ctrl+l",
"command": "workbench.action.terminal.clear",
"when": "terminalFocus && terminalHasBeenCreated && !accessibilityModeEnabled || terminalFocus && terminalProcessSupported && !accessibilityModeEnabled || accessibilityModeEnabled && accessibleViewIsShown && terminalHasBeenCreated && accessibleViewCurrentProviderId == 'terminal' || accessibilityModeEnabled && accessibleViewIsShown && terminalProcessSupported && accessibleViewCurrentProviderId == 'terminal'",
},
{
"key": "cmd+k",
"command": "-workbench.action.terminal.clear",
"when": "terminalFocus && terminalHasBeenCreated && !accessibilityModeEnabled || terminalFocus && terminalProcessSupported && !accessibilityModeEnabled || accessibilityModeEnabled && accessibleViewIsShown && terminalHasBeenCreated && accessibleViewCurrentProviderId == 'terminal' || accessibilityModeEnabled && accessibleViewIsShown && terminalProcessSupported && accessibleViewCurrentProviderId == 'terminal'",
},
{
"key": "space",
"command": "vspacecode.space",
"when": "terminalFocus && terminalHasBeenCreated && !accessibilityModeEnabled || terminalFocus && terminalProcessSupported && !accessibilityModeEnabled || accessibilityModeEnabled && accessibleViewIsShown && terminalHasBeenCreated && accessibleViewCurrentProviderId == 'terminal' || accessibilityModeEnabled && accessibleViewIsShown && terminalProcessSupported && accessibleViewCurrentProviderId == 'terminal'",
},
{
"key": "ctrl+o",
"command": "workbench.action.navigateBack",
"when": "canNavigateBack",
},
{
"key": "ctrl+-",
"command": "-workbench.action.navigateBack",
"when": "canNavigateBack",
},
{
"key": "ctrl+o",
"command": "-lineBreakInsert",
"when": "textInputFocus && !editorReadonly",
},
{
"key": "ctrl+\\",
"command": "-glass.openActionMenu",
"when": "isGlassAgentWorkspace && glassActiveTabKind == 'diff'",
},
{
"key": "ctrl+\\",
"command": "-glass.openPlanBuildMenu",
"when": "isGlassAgentWorkspace && glassActiveTabKind == 'plan'",
},
{
"key": "ctrl+cmd+i",
"command": "-workbench.panel.chat",
"when": "workbench.panel.chat.view.copilot.active",
},
{
"key": "ctrl+\\",
"command": "workbench.action.toggleAgentsFromKeyboard",
"when": "!isAuxiliaryWindowFocusedContext && !isGlass",
},
{
"key": "alt+cmd+j",
"command": "-workbench.action.toggleAgentsFromKeyboard",
"when": "!isAuxiliaryWindowFocusedContext && !isGlass",
},
]
+291
View File
@@ -0,0 +1,291 @@
{
"editor.fontLigatures": true,
"editor.fontSize": 16,
"editor.renderControlCharacters": true,
"workbench.iconTheme": "Monokai Classic Icons",
"workbench.welcome.enabled": false,
"workbench.colorTheme": "Dracula Theme Soft",
"vim.overrideCopy": false,
"vim.enableNeovim": true,
"vim.neovimPath": "/usr/local/bin/nvim",
"vim.disableAnnoyingNeovimMessage": true,
// Vim easymotion is required for Jump menu - <SPC> j
"vim.easymotion": true,
// Use system clipboard for vim
"vim.useSystemClipboard": true,
// Trigger the main which key menu with in the active editor with vim
// This cannot be put into keybindings.json because it will
// create conflict with Vim.
// https://github.com/stevenguh/spacecode/issues/3
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["<space>"],
"commands": ["vspacecode.space"]
},
{
"before": [","],
"commands": [
"vspacecode.space",
{
"command": "whichkey.triggerKey",
"args": "m"
}
]
}
],
"vim.visualModeKeyBindingsNonRecursive": [
{
"before": ["<space>"],
"commands": ["vspacecode.space"]
},
{
"before": [","],
"commands": [
"vspacecode.space",
{
"command": "whichkey.triggerKey",
"args": "m"
}
]
},
{
"before": [">"],
"commands": ["editor.action.indentLines"]
},
{
"before": ["<"],
"commands": ["editor.action.outdentLines"]
}
],
"workbench.panel.location": "right",
"gitHistory.hideCommitViewExplorer": true,
"python.linting.pylintEnabled": false,
"python.pythonPath": "/usr/local/bin/python3",
"editor.wordWrap": "on",
"editor.suggestSelection": "first",
"vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
"sync.gist": "3c4e02a02a0d110622006b8c8b058fa5",
"go.languageServerFlags": ["-rpc.trace"],
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"files.associations": {
"*.html": "html",
"*.json": "jsonc",
"NOTES.txt": "helm",
"Dockerfile": "dockerfile"
},
"[helm]": {
"editor.defaultFormatter": "redhat.vscode-yaml"
// "editor.formatOnSave": false // alternatively, force it to leave you alone
},
"gitlens.codeLens.recentChange.enabled": false,
"gitlens.codeLens.authors.enabled": false,
"sync.forceUpload": true,
"gitlens.currentLine.enabled": false,
"emmet.triggerExpansionOnTab": true,
// "terminal.integrated.shell.osx": "/bin/zsh",
"editor.fontFamily": "Fira Code, Sarasa Fixed SC Nerd Font, Menlo, Monaco, 'Courier New', monospace",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"search.followSymlinks": false,
"go.autocompleteUnimportedPackages": true,
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"vscode-neovim.mouseSelectionStartVisualMode": true,
"go.lintTool": "golangci-lint",
"go.lintFlags": ["--config=~/.dotfile/golang/golangci.yml"],
"go.liveErrors": {
"enabled": false,
"delay": 500
},
"python.languageServer": "Pylance",
"go.overwriteGoplsMiddleware": {},
"go.useLanguageServer": true,
"[go]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
},
"editor.snippetSuggestions": "none",
"editor.defaultFormatter": "golang.go"
},
"[go.mod]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
"gopls": {
"usePlaceholders": true,
"staticcheck": false
},
"go.testFlags": ["-v"],
"vscode-neovim.neovimExecutablePaths.darwin": "/usr/local/bin/nvim",
"go.buildOnSave": "off",
"vim.autoSwitchInputMethod.defaultIM": "com.apple.keylayout.ABC",
"vim.autoSwitchInputMethod.obtainIMCmd": "/usr/local/bin/im-select",
"vim.autoSwitchInputMethod.switchIMCmd": "/usr/local/bin/im-select {im}",
"vim.autoSwitchInputMethod.enable": true,
"editor.cursorStyle": "line",
"editor.insertSpaces": false,
"editor.lineNumbers": "on",
"editor.wordSeparators": "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-",
"security.workspace.trust.untrustedFiles": "open",
"workbench.tree.indent": 4,
"[html]": {
"editor.defaultFormatter": "vscode.html-language-features"
},
"python.defaultInterpreterPath": "/usr/local/bin/python3",
"[python]": {
"editor.formatOnType": true,
"editor.defaultFormatter": "ms-python.python"
},
"[go][go.mod]": {
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
"update.showReleaseNotes": false,
"terminal.integrated.defaultProfile.osx": "fish",
"extensions.experimental.affinity": {
"asvetliakov.vscode-neovim": 1
},
"makefile.configureOnOpen": false,
"python.terminal.activateEnvInCurrentTerminal": true,
"remote.SSH.enableAgentForwarding": false,
"remote.SSH.defaultForwardedPorts": [],
"remote.SSH.useLocalServer": false,
"remote.SSH.connectTimeout": 30,
"remote.SSH.localServerDownload": "always",
"remote.SSH.remotePlatform": {
"box1": "linux",
"hx80": "linux",
"hx20": "linux",
"pc30": "linux"
},
"editor.formatOnSave": true,
"pylint.enabled": false,
"python.analysis.typeCheckingMode": "standard",
"python.analysis.packageIndexDepths": [
{
"name": "sklearn",
"depth": 2
},
{
"name": "matplotlib",
"depth": 2
},
{
"name": "scipy",
"depth": 2
},
{
"name": "django",
"depth": 2
},
{
"name": "flask",
"depth": 2
},
{
"name": "fastapi",
"depth": 2
}
],
"[shellscript]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
// "[dockerfile]": {
// "editor.defaultFormatter": "foxundermoon.shell-format"
// },
"[ignore]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"[properties]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"editor.codeActionsOnSave": {
// "source.organizeImports": "explicit",
"source.fixAll.eslint": "explicit"
},
"[proto3]": {
"editor.defaultFormatter": "zxh404.vscode-proto3"
},
"[dotenv]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"typescript.preferences.quoteStyle": "single",
"javascript.preferences.quoteStyle": "single",
"go.toolsManagement.autoUpdate": true,
"pretty-formatter.quoteConvert": "single",
"html.completion.attributeDefaultValue": "singlequotes",
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"prettier.jsxSingleQuote": true,
"go.buildFlags": ["-tags=wireinject"],
"[yaml]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.insertSpaces": true,
"editor.tabSize": 2,
"editor.autoIndent": "advanced",
"diffEditor.ignoreTrimWhitespace": false,
"editor.defaultColorDecorators": "never"
},
"html.format.unformatted": "",
"editor.defaultFormatter": "esbenp.prettier-vscode",
"notebook.defaultFormatter": "esbenp.prettier-vscode",
"workbench.activityBar.orientation": "vertical", // cursor test
"vspacecode.bindingOverrides": [
{
"keys": ["space"],
"name": "Space (Global Leader)",
"type": "bind",
"command": "vspacecode.space",
"when": "editorTextFocus || explorerViewletVisible || terminalFocus"
},
{
"keys": "w.t",
"name": "Toggle Terminal",
"type": "command",
"command": "workbench.action.terminal.toggleTerminal"
},
{
"keys": "w.w",
"name": "Toggle AI Sidebar",
"type": "command",
"command": "workbench.action.toggleAuxiliaryBar"
},
{
"keys": "w.e",
"name": "Focus First Editor Group",
"type": "command",
"command": "workbench.action.focusFirstEditorGroup"
}
],
"[java]": {
"editor.suggest.snippetsPreventQuickSuggestions": false
},
"git.confirmSync": false,
"editor.dropIntoEditor.preferences": [],
"whichkey.bindingOverrides": [],
"workbench.colorCustomizations": {},
"javascript.format.enable": false,
"typescript.format.enable": false,
"terminal.integrated.env.linux": {
"ANTHROPIC_AUTH_TOKEN": "sk-cp-QvKTjyX6D0bf5u0f9mB-mpaYcyCwdXq3nubxEzTFFtiGuYmLmC_nyxGOsK3jzmJSCMix2rXJ90iSFb6Xva0R30ZY1ilwMLf44npGnAzTWgtwUIqoGwHmQsc",
"ANTHROPIC_BASE_URL": "https://api.minimaxi.com/anthropic",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "MiniMax-M2.1",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "MiniMax-M2.1",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "MiniMax-M2.1",
"ANTHROPIC_MODEL": "MiniMax-M2.1",
"API_TIMEOUT_MS": "3000000",
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": 1
},
"claudeCode.preferredLocation": "panel",
"window.autoDetectColorScheme": false,
"vim.disableExtension": true
}
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
set -e
set -x
# 设置环境变量
export CURSOR_VERSION=
export CURSOR_COMMIT=
export REMOTE_ARCH="x64" # or arm64
export REMOTE_OS="linux"
# 创建目录结构
mkdir -p ${HOME}/.cursor-server/cli/servers/Stable-${CURSOR_COMMIT}/server/
# 下载并解压第一个压缩包 (cli-alpine)
CLI_URL="https://cursor.blob.core.windows.net/remote-releases/${CURSOR_COMMIT}/cli-alpine-${REMOTE_ARCH}.tar.gz"
curl -L "${CLI_URL}" -o ${HOME}/.cursor-server/cursor-cli.tar.gz
tar -xzf ${HOME}/.cursor-server/cursor-cli.tar.gz -C ${HOME}/.cursor-server/
mv ${HOME}/.cursor-server/cursor ${HOME}/.cursor-server/cursor-$CURSOR_COMMIT
# 下载并解压第二个压缩包 (vscode-reh)
VSCODE_URL="https://cursor.blob.core.windows.net/remote-releases/${CURSOR_VERSION}-${CURSOR_COMMIT}/vscode-reh-${REMOTE_OS}-${REMOTE_ARCH}.tar.gz"
curl -L "${VSCODE_URL}" -o ${HOME}/.cursor-server/cursor-vscode-server.tar.gz
tar -xzf ${HOME}/.cursor-server/cursor-vscode-server.tar.gz -C ${HOME}/.cursor-server/cli/servers/Stable-${CURSOR_COMMIT}/server/ --strip-components=1
echo "Cursor server installation completed!"
+7
View File
@@ -0,0 +1,7 @@
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3"
}
}
+5
View File
@@ -0,0 +1,5 @@
{
"registry-mirrors": [
"https://docker.1ms.run"
]
}
+89
View File
@@ -0,0 +1,89 @@
# Completions for ff command
complete -c ff -f
set -l ff_subcommands reload edit fish dotfile pon poff pst make script s update help region ssh init copy dirsize help region
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "reload" -d "Reload fish configuration"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "edit" -d "Edit custom fish configuration"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "fish" -d "Change to fish config directory"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "dotfile" -d "Change to dotfile directory"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "pon" -d "Enable proxy (proxy on)"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "poff" -d "Disable proxy (proxy off)"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "pst" -d "Show proxy status"
# complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "make" -d "Run dotfile Makefile commands"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "script" -d "Run script from script directory"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "s" -d "Run script (alias for script)"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "help" -d "Show this help message"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "region" -d "Toggle or set CN_REGION (mirror/proxy region)"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "ssh" -d "SSH init (keys + config.d) or copy config to remote"
complete -c ff -n "not __fish_seen_subcommand_from $ff_subcommands" -a "dirsize" -d "Show directory sizes"
complete -c ff -n "__fish_seen_subcommand_from dirsize" -s a -l all -d "Recursively show all subdirectories"
complete -c ff -n "__fish_seen_subcommand_from dirsize" -s d -l depth -d "Recursion depth (default 1)" -r
complete -c ff -n "__fish_seen_subcommand_from dirsize" -s n -l top -d "Show top N only" -r
complete -c ff -n "__fish_seen_subcommand_from dirsize" -s r -l reverse -d "Sort smallest first"
complete -c ff -n "__fish_seen_subcommand_from dirsize" -s h -l help -d "Show help"
complete -c ff -n "__fish_seen_subcommand_from dirsize" -a "(__fish_complete_directories)" -d "Directory"
complete -c ff -n "__fish_seen_subcommand_from ssh; and not __fish_seen_subcommand_from init copy help" -a init -d "Ensure SSH key and config.d Include"
complete -c ff -n "__fish_seen_subcommand_from ssh; and not __fish_seen_subcommand_from init copy help" -a copy -d "Copy specified SSH config file(s) to remote"
complete -c ff -n "__fish_seen_subcommand_from ssh; and not __fish_seen_subcommand_from init copy help" -a help -d "Show ssh subcommand help"
function __ff_ssh_config_d_files
for d in $HOME/.ssh/config.d $HOME/.dotfile/ssh/config.d
if test -d $d
for f in $d/*
if test -f $f
basename $f
end
end
end
end
end
complete -c ff -n "__fish_seen_subcommand_from ssh copy; and test (count (commandline -opc)) -eq 2" -a "(__fish_ssh_hosts 2>/dev/null; or __fish_print_hostnames)" -d "SSH host"
complete -c ff -n "__fish_seen_subcommand_from ssh copy; and test (count (commandline -opc)) -ge 3" -a "(__ff_ssh_config_d_files)" -d "Config file"
# # make 子命令的补全 - 直接使用脚本文件名
# complete -c ff -n "__fish_seen_subcommand_from make" -a "help" -d "Show all make targets"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "list" -d "List all available scripts"
# Install scripts
# complete -c ff -n "__fish_seen_subcommand_from make" -a "brew-install" -d "Install Homebrew"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "docker-install" -d "Install Docker"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "nvim-install" -d "Install Neovim"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "python-install" -d "Install Python"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "gvm-install" -d "Install Go Version Manager"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "firacode-install" -d "Install FiraCode font"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "font-install" -d "Install fonts"
# # Init scripts
# complete -c ff -n "__fish_seen_subcommand_from make" -a "fish-init" -d "Initialize Fish shell"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "git-init" -d "Initialize Git config"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "nvim-init" -d "Initialize Neovim config"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "tmux-init" -d "Initialize Tmux config"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "cursor-init" -d "Initialize Cursor config"
# complete -c ff -n "__fish_seen_subcommand_from make" -a "init-default-user" -d "Initialize default user (sudo)"
# script 子命令的补全 - 动态列出 script 目录下的脚本
function __ff_list_scripts
if not functions -q script-list-names
source ~/.dotfile/fish/functions/script-catalog.fish
end
script-list-names
end
function __ff_complete_scripts
if not functions -q script-extract-description
source ~/.dotfile/fish/functions/script-catalog.fish
end
for name in (script-list-names)
set -l path (script-resolve-path $name)
set -l desc (script-extract-description $path)
printf "%s\t%s\n" $name $desc
end
end
complete -c ff -n "__fish_seen_subcommand_from script s; and test (count (commandline -opc)) -eq 2" -s h -l help -d "List all scripts and descriptions"
complete -c ff -n "__fish_seen_subcommand_from script s; and test (count (commandline -opc)) -eq 2" -a help -d "List all scripts and descriptions"
complete -c ff -n "__fish_seen_subcommand_from script s; and not __fish_seen_subcommand_from help -h --help (__ff_list_scripts)" -a '(__ff_complete_scripts)' -d "Script name"
+51
View File
@@ -0,0 +1,51 @@
# ----- Git worktree native completions -----
# 列出分支
function __git_branches
git branch --format="%(refname:short)" 2>/dev/null
end
# 列出 worktree 路径
function __git_worktree_paths
git worktree list --porcelain 2>/dev/null \
| awk '/worktree/ {print $2}'
end
# -----------------------
# Worktree 别名补全
# -----------------------
# git wtl → worktree list
complete -f -c git -n '__fish_seen_subcommand_from wtl' -a ''
# git wtp → worktree prune
complete -f -c git -n '__fish_seen_subcommand_from wtp' -a ''
# git wta → worktree add <path> <branch>
complete -c git -n '__fish_seen_subcommand_from wta' \
-a '(__git_branches)' \
-d "Branch to add worktree for"
# git wtb → worktree add -b <newbranch> <path> <base>
complete -c git -n '__fish_seen_subcommand_from wtb' \
-a '(__git_branches)' \
-d "Base branch to create new branch from"
# git wtr → worktree remove <path>
complete -c git -n '__fish_seen_subcommand_from wtr' \
-a '(__git_worktree_paths)' \
-d "Existing worktree paths"
# ------------------------------
# 原生 git worktree 补全增强
# ------------------------------
# git worktree add <path> <branch>
complete -c git -n '__fish_seen_subcommand_from worktree; and __fish_seen_subcommand_from add' \
-a '(__git_branches)' \
-d "Branch to checkout"
# git worktree remove <path>
complete -c git -n '__fish_seen_subcommand_from worktree; and __fish_seen_subcommand_from remove' \
-a '(__git_worktree_paths)' \
-d "Worktree path"
+2
View File
@@ -0,0 +1,2 @@
# Inherit ssh-copy-id options and host completions
complete -c ssh2 -w ssh-copy-id
-53
View File
@@ -1,53 +0,0 @@
fish_vi_key_bindings
## set environment
# brew
set -gx HOMEBREW_BREW_GIT_REMOTE "https://mirrors.ustc.edu.cn/brew.git"
set -gx HOMEBREW_CORE_GIT_REMOTE "https://mirrors.ustc.edu.cn/homebrew-core.git"
set -gx HOMEBREW_BOTTLE_DOMAIN "https://mirrors.ustc.edu.cn/homebrew-bottles"
# go
set -gx GOPATH $HOME/go:$HOME/workrepo/go
set -gx GOPROXY "goproxy.cn,direct"
set -gx GOSUMDB "sum.golang.google.cn"
set -gx PATH $PATH $HOME/go/bin
set -gx PATH $PATH $HOME/.yarn/bin $HOME/.config/yarn/global/node_modules/.bin
set -gx PATH $PATH /usr/local/sbin
# add nvim
set -gx PATH $PATH /usr/local/nvim/bin /usr/local/osx-64/nvim/bin
set -gx EDITOR vim
# add my script
set -gx PATH $PATH $HOME/.dotfile/script $HOME/.app00/script
# alias
# git
alias gitb="git branch --show-current | tr -d '\n' | pbcopy"
alias gci="golangci-lint run -c=~/.dotfile/.golangci.yml ./..."
alias gmt="go mod tidy"
alias gtc="go test -gcflags=all=-l -cover ./..."
alias swg="swag init -o docs -g "
alias sws="swagger serve -F=swagger"
function gtr
go test -gcflags=all=-l -v -run=$argv
end
if test -f ~/.config/fish/custom.fish
source ~/.config/fish/custom.fish
end
if status is-interactive
# Commands to run in interactive sessions can go here
end
+247
View File
@@ -0,0 +1,247 @@
#################################################################
# option
fish_vi_key_bindings
# Vi 模式下:Ctrl+A / Ctrl+E 行首、行尾(readline 习惯)
bind --mode insert \ca beginning-of-line
bind --mode insert \ce end-of-line
bind --mode default \ca beginning-of-line
bind --mode default \ce end-of-line
#################################################################
# basic
# 定义一个函数来检查并添加路径到 PATH
function add_to_path
# 遍历传递给函数的所有参数
for path in $argv
# 检查路径是否存在
if test -d $path
# 如果路径存在且不在 PATH 中,则添加到 PATH
if not contains $path $PATH
#echo "Adding $path to PATH"
set -gx PATH $PATH $path
else
#echo "$path is already in PATH"
end
else
#echo "$path does not exist"
end
end
end
function is_command_exists
if command -v $argv[1] >/dev/null 2>&1
return 0
else
return 1
end
end
# set environment
set paths_to_check /usr/sbin /usr/local/bin /usr/bin /bin /usr/sbin /sbin /opt/bin /opt/sbin /usr/syno/sbin /usr/syno/bin /usr/local/sbin $HOME/.local/bin $HOME/.pouch/bin
for path in $paths_to_check do
add_to_path $path
end
function sudoo
eval sudo $history[1]
end
# add my script
add_to_path $HOME/.dotfile/script $HOME/.app00/script
if test -f ~/.config/fish/custom.fish
source ~/.config/fish/custom.fish
end
#################################################################
# brew
set -gx HOMEBREW_BREW_GIT_REMOTE "https://mirrors.ustc.edu.cn/brew.git"
set -gx HOMEBREW_CORE_GIT_REMOTE "https://mirrors.ustc.edu.cn/homebrew-core.git"
set -gx HOMEBREW_BOTTLE_DOMAIN "https://mirrors.ustc.edu.cn/homebrew-bottles"
#################################################################
# java 17 + android sdk (local debug builds; no Android Studio)
if test -d /usr/local/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home
set -gx JAVA_HOME /usr/local/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home
else if test -d /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home
set -gx JAVA_HOME /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home
else if test -d /home/linuxbrew/.linuxbrew/opt/openjdk@17
set -gx JAVA_HOME /home/linuxbrew/.linuxbrew/opt/openjdk@17
end
if set -q JAVA_HOME
if not contains $JAVA_HOME/bin $PATH
set -gx PATH $JAVA_HOME/bin $PATH
end
end
if test -d $HOME/Library/Android/sdk
set -gx ANDROID_HOME $HOME/Library/Android/sdk
else if test -d $HOME/Android/Sdk
set -gx ANDROID_HOME $HOME/Android/Sdk
end
if set -q ANDROID_HOME
set -gx ANDROID_SDK_ROOT $ANDROID_HOME
add_to_path $ANDROID_HOME/cmdline-tools/latest/bin $ANDROID_HOME/platform-tools
end
#################################################################
# go
set -gx GOPATH $HOME/go:$HOME/workrepo/go
set -gx GOPROXY "goproxy.cn,direct"
set -gx GOSUMDB "sum.golang.google.cn"
set -gx EDITOR vim
add_to_path $HOME/go/bin
add_to_path $HOME/.yarn/bin $HOME/.config/yarn/global/node_modules/.bin
function gtr
go test -gcflags=all=-l -v -run=$argv
end
#################################################################
# python
set -gx PYENV_ROOT $HOME/.pyenv
# Pyenv initialization
if command -v pyenv 1>/dev/null 2>&1
pyenv init - | source
end
add_to_path $PYENV_ROOT/bin
# pnpm
set -gx PNPM_HOME $HOME/.pnpm
if not string match -q -- $PNPM_HOME $PATH
set -gx PATH "$PNPM_HOME" $PATH
end
#################################################################
# git
# alias
alias gitb="git branch --show-current | tr -d '\n' | clip-copy.sh"
alias gci="golangci-lint run -c=~/.dotfile/golang/golangci.yml ./..."
alias gmt="go mod tidy"
alias gtc="go test -gcflags=all=-l -cover ./..."
alias swg="swag init -o docs -g "
alias sws="swagger serve -F=swagger"
alias sourceit="source ~/.config/fish/config.fish"
#################################################################
# docker
function dc
# 检查第一个参数是否是 is_sudo
set use_sudo false
set args $argv
if test (count $argv) -gt 0; and test "$argv[1]" = is_sudo
set use_sudo true
set args $argv[2..-1]
end
# 检查 docker-compose 是否可用
if command -v docker-compose >/dev/null
set compose_cmd docker-compose
else
set compose_cmd docker compose
end
# 构建执行命令(如果需要 sudo,添加 sudo 前缀)
if test $use_sudo = true
set exec_cmd command sudo $compose_cmd
else
set exec_cmd $compose_cmd
end
switch $args[1]
case lf
$exec_cmd logs -f $args[2..-1]
case upd
$exec_cmd up -d $args[2..-1] && $exec_cmd logs -f $args[2..-1]
case reupd
$exec_cmd up -d --force-recreate $args[2..-1] && $exec_cmd logs -f $args[2..-1]
case '*'
$exec_cmd $args
end
end
#################################################################
# systemctl
function sc
systemctl $argv
end
function scu
systemctl --user $argv
end
function jc
journalctl $argv
end
function jcu
journalctl --user $argv
end
# 智能 sudo 包装,支持展开函数别名
function sudo --wraps sudo
if test (count $argv) -gt 0
set cmd $argv[1]
switch $cmd
case sc
command sudo systemctl $argv[2..-1]
case jc
command sudo journalctl $argv[2..-1]
case dc
# 调用 dc 函数并传递 is_sudo 参数
dc is_sudo $argv[2..-1]
case '*'
command sudo $argv
end
else
command sudo $argv
end
end
#################################################################
# other
function ctl
systemctl $argv
end
if status is-interactive
# Commands to run in interactive sessions can go here
end
# source env
function source_env
for line in (cat $argv | grep -v '^#' | grep -v '^\s*$')
set item (string split -m 1 '=' $line)
set -gx $item[1] (eval echo $item[2])
end
end
function make2
make -f Makefile.local $argv
end
# Added by OrbStack: command-line tools and integration
# This won't be added again if you remove it.
source ~/.orbstack/shell/init2.fish 2>/dev/null || :
# mise (formerly rtx)
if command -v mise >/dev/null
add_to_path $HOME/.local/bin
add_to_path $HOME/.local/share/mise/shims
mise activate fish | source
end
function vim
if command -q nvim
command nvim $argv
else if command -q vim
command vim $argv
else
command vi $argv
end
end
# bun
set --export BUN_INSTALL "$HOME/.bun"
set --export PATH $BUN_INSTALL/bin $PATH
+7
View File
@@ -0,0 +1,7 @@
function _notify_emit --argument-names title body
if set -q TMUX
printf '\ePtmux;\e\e]777;notify;%s;%s\a\e\\' "$title" "$body"
else
printf '\e]777;notify;%s;%s\a' "$title" "$body"
end
end
@@ -0,0 +1,13 @@
function _notify_human_duration --argument-names ms
test -z "$ms"; and set ms 0
set -l s (math --scale=0 $ms / 1000)
if test $s -lt 1
echo {$ms}ms
else if test $s -lt 60
echo {$s}s
else if test $s -lt 3600
echo (math --scale=0 $s / 60)m(math $s % 60)s
else
echo (math --scale=0 $s / 3600)h(math --scale=0 ($s % 3600) / 60)m
end
end
+52
View File
@@ -0,0 +1,52 @@
# Execute script from script directory
function execute-script
if not functions -q script-show-catalog
source ~/.dotfile/fish/functions/script-catalog.fish
end
set -l dotfile_dir ~/.dotfile
set -l script_dir $dotfile_dir/script
set -l script_name $argv[1]
# ff script|s -h / --help / help
if test -z "$script_name"; or contains -- $script_name -h --help help
if test -z "$script_name"; or test (count $argv) -eq 1
script-show-catalog
return 0
end
end
if test -z "$script_name"
script-show-catalog
return 1
end
set -l script_path (script-resolve-path $script_name 2>/dev/null; or echo "")
if test -n "$script_path" -a -f "$script_path"
echo "Running: $script_path"
set -l run_status 0
if test -x $script_path
$script_path $argv[2..-1]
set run_status $status
else if string match -q "*.py" $script_path
python3 $script_path $argv[2..-1]
set run_status $status
else
bash $script_path $argv[2..-1]
set run_status $status
end
if test "$script_name" = toggle-region
if not functions -q region_apply_from_custom
source ~/.dotfile/fish/functions/region.fish
end
region_apply_from_custom
end
return $run_status
end
echo "Error: Script not found: $script_name"
echo ""
script-show-catalog
return 1
end
+181
View File
@@ -0,0 +1,181 @@
# ff ssh: local init (keys + config.d) and copy config to remote
function __ff_ssh_has_key
for f in $HOME/.ssh/id_*
if test -f $f; and not string match -q '*.pub' -- $f
return 0
end
end
return 1
end
function __ff_ssh_ensure_keys
if __ff_ssh_has_key
echo "SSH key exists, skip generation"
return 0
end
set -l key_path "$HOME/.ssh/id_ed25519"
set -l comment "$USER@"(hostname -s 2>/dev/null; or echo localhost)
mkdir -p "$HOME/.ssh"
chmod 700 "$HOME/.ssh"
echo "No SSH key found, generating ed25519: $key_path"
if test -t 0
ssh-keygen -t ed25519 -f $key_path -C $comment
else
ssh-keygen -t ed25519 -f $key_path -C $comment -N ""
echo "Non-interactive mode: created with empty passphrase"
end
end
function __ff_ssh_ensure_config_d
set -l ssh_config "$HOME/.ssh/config"
set -l include_line "Include ~/.ssh/config.d/*"
mkdir -p "$HOME/.ssh/config.d"
chmod 700 "$HOME/.ssh"
if not test -f $ssh_config
printf '%s\n' $include_line > $ssh_config
chmod 600 $ssh_config
echo "Created $ssh_config with $include_line"
else if grep -qE 'Include[[:space:]]+.*config\.d' $ssh_config
echo "config.d Include already in $ssh_config"
else
printf '\n# config.d\n%s\n' $include_line >> $ssh_config
echo "Appended to $ssh_config: $include_line"
end
end
function __ff_ssh_resolve_path --argument path
if test -L $path
set path (readlink $path)
if not string match -q '/*' -- $path
set path "$HOME/.ssh/$path"
end
end
echo $path
end
function __ff_ssh_remote_has_include --argument host
ssh -q $host 'test -f ~/.ssh/config && grep -qE "Include[[:space:]]+.*config\.d" ~/.ssh/config'
end
function __ff_ssh_remote_ensure_include --argument host
ssh $host 'mkdir -p ~/.ssh/config.d && chmod 700 ~/.ssh
if [ -f ~/.ssh/config ] && grep -qE "Include[[:space:]]+.*config\.d" ~/.ssh/config; then
echo "Remote config.d Include already exists"
elif [ -f ~/.ssh/config ]; then
printf "\n# config.d\nInclude ~/.ssh/config.d/*\n" >> ~/.ssh/config
chmod 600 ~/.ssh/config
echo "Appended config.d Include on remote"
else
printf "%s\n" "Include ~/.ssh/config.d/*" > ~/.ssh/config
chmod 600 ~/.ssh/config
echo "Created remote config with config.d Include"
fi'
end
function __ff_ssh_resolve_copy_src --argument file
set -l src $file
if test -f $src
echo $src
return 0
end
set -l in_config_d "$HOME/.ssh/config.d/$file"
if test -f $in_config_d
echo $in_config_d
return 0
end
set -l dotfile_src "$HOME/.dotfile/ssh/config.d/$file"
if test -f $dotfile_src
echo $dotfile_src
return 0
end
return 1
end
function __ff_ssh_copy_remote --argument-names argv
set -l host $argv[1]
set -l files $argv[2..-1]
set -l ssh_dir "$HOME/.ssh"
set -l main_config "$ssh_dir/config"
if test -z "$host"
echo "Usage: ff ssh copy <host> <config-file>..."
echo " host: SSH alias or user@hostname"
echo " file: path, or name under ~/.ssh/config.d/"
return 1
end
if test (count $files) -eq 0
echo "Usage: ff ssh copy <host> <config-file>..."
echo ""
echo "Examples:"
echo " ff ssh copy mynas 30-hanxi.conf"
echo " ff ssh copy mynas ~/.dotfile/ssh/config.d/20-personal.conf"
if test -d "$ssh_dir/config.d"
echo ""
echo "Available in ~/.ssh/config.d/:"
ls -1 "$ssh_dir/config.d/"
end
return 1
end
echo "Checking remote Include on $host ..."
ssh -q $host "mkdir -p ~/.ssh/config.d && chmod 700 ~/.ssh"
if __ff_ssh_remote_has_include $host
echo "Remote config.d Include: OK"
else
echo "Remote missing config.d Include, adding ..."
__ff_ssh_remote_ensure_include $host
end
for f in $files
set -l src (__ff_ssh_resolve_copy_src $f 2>/dev/null)
if test $status -ne 0 -o -z "$src"
echo "Error: file not found: $f"
return 1
end
set -l resolved_main (__ff_ssh_resolve_path $main_config)
set -l name (basename $src)
if test "$src" = "$resolved_main"; or test "$name" = config
set -l ts (date +%Y%m%d%H%M%S)
ssh -q $host "test -f ~/.ssh/config && cp ~/.ssh/config ~/.ssh/config.bak.$ts || true"
scp -q $src "$host:.ssh/config"
ssh -q $host "chmod 600 ~/.ssh/config"
echo "Copied $src -> $host:~/.ssh/config"
else
scp -q $src "$host:.ssh/config.d/$name"
ssh -q $host "chmod 600 ~/.ssh/config.d/$name"
echo "Copied $src -> $host:~/.ssh/config.d/$name"
end
end
echo "Done."
end
function ff_ssh --argument-names argv
set -l sub (test (count $argv) -ge 1; and echo $argv[1]; or echo init)
switch $sub
case init ''
__ff_ssh_ensure_keys
__ff_ssh_ensure_config_d
case copy
__ff_ssh_copy_remote $argv[2..-1]
case help -h
echo "Usage: ff ssh [init|copy <host> <file>...|help]"
echo ""
echo " init Ensure SSH key and config.d Include (default)"
echo " copy <host> <file> Check remote Include, then scp specified config file(s)"
echo " help Show this help"
case '*'
echo "Unknown subcommand: $sub"
echo "Run 'ff ssh help' for usage"
return 1
end
end
+133
View File
@@ -0,0 +1,133 @@
# Fast commands management
function ff
# 定义命令和描述(格式:命令|描述)
set -l commands \
"reload|Reload fish configuration" \
"edit|Edit custom fish configuration" \
"fish|Change to fish config directory" \
"dotfile|Change to dotfile directory" \
"pon|Enable proxy (proxy on)" \
"poff|Disable proxy (proxy off)" \
"pst|Show proxy status" \
"make|Run dotfile Makefile commands" \
"script|Run script from script directory" \
"s|Alias for script" \
"update|Update dotfile" \
"region|Toggle or set CN_REGION (mirror/proxy region)" \
"ssh|SSH init (keys + config.d) or copy config to remote" \
"dirsize|Show directory sizes (du wrapper)" \
"help|Show this help message"
# 确保 execute-script 可用(在 fish 自动加载前手动引入一次)
if not functions -q execute-script
set -l execute_script_path ~/.dotfile/fish/functions/execute-script.fish
if test -f $execute_script_path
source $execute_script_path
end
end
switch $argv[1]
case reload
source ~/.config/fish/config.fish
echo "Fish configuration reloaded!"
case edit
vim ~/.config/fish/custom.fish
case fish
cd ~/.config/fish/
case dotfile
cd ~/.dotfile
case pon
set -gx https_proxy http://127.0.0.1:7890
set -gx http_proxy http://127.0.0.1:7890
set -gx all_proxy socks5://127.0.0.1:7890
echo "✓ Proxy enabled"
export | grep -i proxy
case poff
set -e http_proxy
set -e https_proxy
set -e ftp_proxy
set -e all_proxy
set -e HTTP_PROXY
set -e HTTPS_PROXY
set -e FTP_PROXY
set -e ALL_PROXY
echo "✓ Proxy disabled"
export | grep -i proxy
case pst
export | grep -i proxy
case make
# 切换到 dotfile 目录执行脚本管理 makefile
set -l dotfile_dir ~/.dotfile
if test -d $dotfile_dir
make -f $dotfile_dir/Makefile.scripts -C $dotfile_dir $argv[2..-1]
else
echo "Error: Dotfile directory not found at $dotfile_dir"
end
case script s
if not functions -q execute-script
source ~/.dotfile/fish/functions/execute-script.fish
end
execute-script $argv[2..-1]
case help
echo "Usage: ff <command>"
echo ""
echo "Commands:"
# 自动生成帮助信息
for cmd in $commands
set -l parts (string split '|' $cmd)
printf " %-10s %s\n" $parts[1] $parts[2]
end
case update
set -l dotfile_dir ~/.dotfile
if not test -d $dotfile_dir
echo "Error: Dotfile directory not found at $dotfile_dir"
return 1
end
set -l prev_dir (pwd)
cd $dotfile_dir
if git pull origin main
cd $prev_dir
echo "Reloading fish configuration..."
ff reload
else
cd $prev_dir
echo "Error: git pull failed, skip reload"
return 1
end
case ssh
if not functions -q ff_ssh
source ~/.dotfile/fish/functions/ff-ssh.fish
end
ff_ssh $argv[2..-1]
case dirsize
set -l script_path ~/.dotfile/script/dirsize.sh
if test -f $script_path
bash $script_path $argv[2..-1]
else
echo "Error: dirsize script not found at $script_path"
return 1
end
case region
if not functions -q region_toggle
source ~/.dotfile/fish/functions/region.fish
end
set -l sub toggle
if test (count $argv) -ge 2
set sub $argv[2]
end
switch $sub
case toggle
region_toggle
case '*'
echo "Usage: ff region [toggle]"
echo "Unknown subcommand: $sub"
end
case '*'
if test -z "$argv[1]"
echo "Error: No command specified"
else
echo "Error: Unknown command '$argv[1]'"
end
echo "Run 'ff help' for usage information"
end
end
+24
View File
@@ -0,0 +1,24 @@
function notify-done --description '前置包装:运行命令并在完成时发送 OSC 777 通知'
if test (count $argv) -eq 0
echo "Usage: notify-done <command> [args...]" >&2
return 2
end
set -l start (date +%s)
$argv
set -l rc $status
set -l elapsed (math (date +%s) - $start)
set -l human (_notify_human_duration (math $elapsed \* 1000))
set -l label
if test $rc -eq 0
set label "完成: $argv[1]"
else
set label "失败 exit=$rc: $argv[1]"
end
set -l body "$human · "(hostname -s)" · "(string join ' ' $argv)
_notify_emit "$label" "$body"
return $rc
end
+18
View File
@@ -0,0 +1,18 @@
function notify --description '发送 OSC 777 通知;无参时复用上一条命令的状态与耗时'
set -l rc $status
set -l dur $CMD_DURATION
set -l label
if test (count $argv) -gt 0
set label (string join ' ' $argv)
else if test $rc -eq 0
set label "完成"
else
set label "失败 exit=$rc"
end
set -l body (_notify_human_duration $dur)" · "(hostname -s)" · "(pwd | string replace $HOME '~')
_notify_emit "$label" "$body"
return $rc
end
+7
View File
@@ -0,0 +1,7 @@
function pwdc --description 'Copy current directory path to clipboard'
set -l dir (pwd -P)
if not printf '%s' $dir | clip-copy.sh
return 1
end
echo "Copied: "(string replace $HOME '~' $dir)
end
+58
View File
@@ -0,0 +1,58 @@
# CN_REGION 读写 ~/.config/fish/custom.fish(与 script/common/region.sh 约定一致)
function region_custom_path
echo ~/.config/fish/custom.fish
end
function region_read
set -l path (region_custom_path)
if test -f $path
set -l matches (grep -E '^\s*set\s+-gx\s+CN_REGION\s+' $path 2>/dev/null)
if test (count $matches) -gt 0
set -l line $matches[-1]
echo (string trim (string replace -r '.*\s' '' $line))
return
end
end
if set -q CN_REGION
echo $CN_REGION
else
echo 0
end
end
function region_write
set -l new $argv[1]
set -l path (region_custom_path)
mkdir -p (dirname $path)
set -l tmp (mktemp)
if test -f $path
grep -Ev '^\s*# dotfile: CN_REGION|^\s*set\s+-gx\s+CN_REGION\s+' $path >$tmp 2>/dev/null; or true
else
touch $tmp
end
echo "# dotfile: CN_REGION (managed by ff region / toggle-region)" >>$tmp
echo "set -gx CN_REGION $new" >>$tmp
mv $tmp $path
set -gx CN_REGION $new
end
function region_toggle
set -l current (region_read)
set -l new
if test "$current" = "1"
set new 0
echo "Switched to: 0 (国外)"
else
set new 1
echo "Switched to: 1 (国内)"
end
region_write $new
echo "Persisted to ~/.config/fish/custom.fish"
end
function region_apply_from_custom
set -gx CN_REGION (region_read)
end
+126
View File
@@ -0,0 +1,126 @@
# 列举 ~/.dotfile/script 下脚本及从文件头注释提取的简短说明
function script-extract-description --argument filepath
if not test -f "$filepath"
echo "(无描述)"
return
end
set -l past_shebang 0
set -l candidates
for line in (cat "$filepath")
if string match -qr '^#!/' -- $line
set past_shebang 1
continue
end
if test $past_shebang -eq 0
continue
end
set line (string trim $line)
if test -z "$line"
if test (count $candidates) -gt 0
break
end
continue
end
if not string match -qr '^#' -- $line
break
end
set line (string replace -r '^#\s*' '' $line)
if string match -qr '^---' -- $line
continue
end
if string match -qr '^(用法|Usage|示例|Example)' -- $line
continue
end
if string match -qr '^\./' -- $line
continue
end
if string match -qr '^https?://' -- $line
continue
end
# 行内 “# 用法” 类注释
if string match -qr '#\s*(用法|Usage)' -- $line
continue
end
set candidates $candidates $line
if test (count $candidates) -ge 8
break
end
end
if test (count $candidates) -eq 0
echo "(无描述)"
return
end
for c in $candidates
if string match -qr '(脚本|安装|初始化|清理|扫描|切换|配置|用于|镜像|凭据|用户组|免密|Install|Init|Clean|Toggle)' -- $c
echo $c
return
end
end
for c in $candidates
if test (string length $c) -ge 10
echo $c
return
end
end
echo $candidates[1]
end
function script-list-names
set -l script_dir ~/.dotfile/script
set -l names
if not test -d $script_dir
return
end
for script in $script_dir/*.sh $script_dir/*.py
if test -f $script
set -l name (basename $script)
set name (string replace -r '\.(sh|py)$' '' $name)
set names $names $name
end
end
string join \n $names | sort
end
function script-resolve-path --argument name
set -l script_dir ~/.dotfile/script
for ext in sh py
set -l path "$script_dir/$name.$ext"
if test -f $path
echo $path
return 0
end
end
if test -f "$script_dir/$name"
echo "$script_dir/$name"
return 0
end
return 1
end
function script-show-catalog
set -l script_dir ~/.dotfile/script
echo "Usage: ff script <name> [args...] (alias: ff s)"
echo ""
echo "Scripts in $script_dir:"
echo ""
for name in (script-list-names)
set -l path (script-resolve-path $name)
set -l desc (script-extract-description $path)
printf " %-22s %s\n" $name $desc
end
echo ""
echo "提示: ff s <name> -h 查看单个脚本内的详细帮助"
end
+10
View File
@@ -0,0 +1,10 @@
# ssh-copy-id 后交互保存 SSH Host 别名
function ssh2 --wraps ssh-copy-id --description "Copy SSH key and save host alias"
set -l script_path ~/.dotfile/script/ssh2.sh
if not test -f $script_path
echo "Error: ssh2 script not found at $script_path" >&2
return 1
end
bash $script_path $argv
end
-4
View File
@@ -1,4 +0,0 @@
if [ -f "$HOME/.config/fish/config.fish" ]; then
mv $HOME/.config/fish/config.fish $HOME/.config/fish/config.fish.bak
fi
ln -s $HOME/.dotfile/fish/config.fish $HOME/.config/fish/config.fish
+51
View File
@@ -0,0 +1,51 @@
# 主题推荐:Catppuccin, Tokyo Night, 或 Gruvbox
theme = Atom One Dark
# 字体设置 (建议安装带 Nerd Font 图标的字体)
font-family = "FiraCode Nerd Font"
font-size = 16
font-feature = -calt # 如果你不喜欢连字(Ligatures)可以禁用
# 窗口样式:隐藏标题栏,让视觉更纯粹
#window-decoration = true
#macos-titlebar-style = transparent
macos-titlebar-style = tabs
window-title-font-family = "FiraCode Nerd Font"
#fullscreen=non-native
# 背景透明度与模糊 (适合 2017 MBP 的精致感)
background-opacity = 0.95
background-blur-radius = 20
# 将 Option 键映射为 Alt/Meta 键 (对 Neovim/Tmux 极其重要)
macos-option-as-alt = true
# 自动定位到当前 Shell 所在的目录
working-directory = home
# 选中文本时自动复制到剪贴板
copy-on-select = true
# 确认退出(防止误触 Command+Q 关掉正在运行的任务)
confirm-close-surface = true
# 光标样式:块状且闪烁
cursor-style = block
cursor-style-blink = true
# 滚动条设置:通常建议隐藏,通过 Tmux 控制滚动
mouse-scroll-multiplier = 1
scrollback-limit = 10000
# Ghostty 配置
desktop-notifications = true
term = xterm-256color
scrollbar = system
mouse-shift-capture = true
shell-integration-features = ssh-env
# 开启所有 shell 集成特性,包含 ssh-terminfo 自动注入
shell-integration = fish
+79 -9
View File
@@ -1,15 +1,17 @@
[user] [user]
name = Laily name = laily
email = i@laily.net email = i@laily.net
[core] [core]
autocrlf = input autocrlf = input
quotepath = false quotepath = false
editor = nvim editor = vim
excludesfile = ~/.dotfile/git/.gitignore excludesfile = ~/.dotfile/git/.gitignore
[push] [init]
default = current defaultBranch = main
[pull] [tag]
rebase = false sort = version:refname
[column]
ui = auto
[color] [color]
status = auto status = auto
diff = auto diff = auto
@@ -17,17 +19,46 @@
interactive = auto interactive = auto
grep = auto grep = auto
ui = auto ui = auto
[merge] [push]
tool = nvimdiff #default = current
default = simple
autoSetupRemote = true
followTags = true
[fetch]
prune = true
pruneTags = true
all = true
[pull]
rebase = false
[diff]
algorithm = histogram
colorMoved = plain
mnemonicPrefix = true
renames = true
[difftool "nvimdiff"] [difftool "nvimdiff"]
cmd = nvim -d \"$LOCAL\" \"$REMOTE\" cmd = nvim -d \"$LOCAL\" \"$REMOTE\"
[merge]
tool = nvimdiff
[mergetool "nvimdiff"] [mergetool "nvimdiff"]
cmd = nvim -d \"$LOCAL\" \"$REMOTE\" -ancestor \"$BASE\" -merge \"$MERGED\" cmd = nvim -d \"$LOCAL\" \"$REMOTE\" -ancestor \"$BASE\" -merge \"$MERGED\"
trustExitCode = true trustExitCode = true
[includeIf "gitdir:~/workrepo/"] [includeIf "gitdir:~/workrepo/"]
path = ~/.workgitconfig path = ~/.workgitconfig
[rebase]
autoSquash = true
autoStash = true
updateRefs = true
[commit]
verbose = true
[rerere]
enabled = true
autoupdate = true
[help]
# 旧版 Git 仅支持数字(0=仅提示不执行)。Git 2.36+ 见 .gitconfig.darwin / .gitconfig.linux 可改为 prompt
autocorrect = 0
[branch] [branch]
autoSetupMerge = always autoSetupMerge = always
sort = -committerdate
[alias] [alias]
au = add -u au = add -u
co = checkout co = checkout
@@ -38,8 +69,10 @@
ba = branch -a ba = branch -a
bm = branch --merged bm = branch --merged
bn = branch --no-merged bn = branch --no-merged
pl = pull pu = "!git pull origin $(git rev-parse --abbrev-ref HEAD)"
pt = push origin --tags pt = push origin --tags
ph = push origin HEAD
pht = push origin --tags
merge2 = !sh -c '_CURRENT_BRANCH=$(git symbolic-ref --short HEAD) && git checkout $1 && git merge $_CURRENT_BRANCH && git checkout $_CURRENT_BRANCH' - merge2 = !sh -c '_CURRENT_BRANCH=$(git symbolic-ref --short HEAD) && git checkout $1 && git merge $_CURRENT_BRANCH && git checkout $_CURRENT_BRANCH' -
bg = "!f() { git branch | grep $1; }; f" bg = "!f() { git branch | grep $1; }; f"
delbr = "!f(){ git branch -D $(git branch | grep \"\b$1\"); };f" delbr = "!f(){ git branch -D $(git branch | grep \"\b$1\"); };f"
@@ -48,6 +81,7 @@
# list files which have changed since REVIEW_BASE # list files which have changed since REVIEW_BASE
# (REVIEW_BASE defaults to 'master' in my zshrc) # (REVIEW_BASE defaults to 'master' in my zshrc)
files = !git diff --name-only $(git merge-base HEAD \"$REVIEW_BASE\") files = !git diff --name-only $(git merge-base HEAD \"$REVIEW_BASE\")
rmsubmodule = "!f(){ git submodule deinit -f \"$1\"; git rm -f \"$1\"; git commit -m \"Removed submodule $1\"; };f"
# Same as above, but with a diff stat instead of just names # Same as above, but with a diff stat instead of just names
# (better for interactive use) # (better for interactive use)
@@ -62,5 +96,41 @@
# git reviewone foo.js bar.js # git reviewone foo.js bar.js
reviewone = !vim -p +\"tabdo Gdiff $REVIEW_BASE\" +\"let g:gitgutter_diff_base = '$REVIEW_BASE'\" reviewone = !vim -p +\"tabdo Gdiff $REVIEW_BASE\" +\"let g:gitgutter_diff_base = '$REVIEW_BASE'\"
#git filter-branch -f --env-filter "GIT_AUTHOR_NAME='Laily'; GIT_AUTHOR_EMAIL='i@laily.net'; GIT_COMMITTER_NAME='Laily'; GIT_COMMITTER_EMAIL='i@laily.net';" HEAD #git filter-branch -f --env-filter "GIT_AUTHOR_NAME='Laily'; GIT_AUTHOR_EMAIL='i@laily.net'; GIT_COMMITTER_NAME='Laily'; GIT_COMMITTER_EMAIL='i@laily.net';" HEAD
# worktree
# git wt add <路径> <分支名>
# git wt add -b <新分支名> <路径> [基分支名]
wt="worktree"
#wta="worktree add"
#wtb="worktree add -b"
wtr="worktree remove"
wtl="worktree list"
wtp="worktree prune"
# 基于分支创建新分支+worktree
# git wtb <分支名> [<基分支名|当前分支>]
wtb = "!f(){ local base_branch=${2:-HEAD}; local clean_name=$(echo \"$1\" | sed \"s/\\//_/g\"); git worktree add -b \"$1\" \"../$clean_name\" $base_branch; }; f"
# 基于指定分支+worktree
# git wta <分支名>
wta = "!f(){ local base_branch=${1:-HEAD}; local clean_name=$(echo \"$1\" | sed \"s/\\//_/g\"); git worktree add \"../$clean_name\" $base_branch; }; f"
[protocol "file"] [protocol "file"]
allow = always allow = always
# https://hyperzsb.io/posts/git-ssl-error/
[filter "lfs"]
process = git-lfs filter-process
required = true
clean = git-lfs clean -- %f
smudge = git-lfs smudge -- %f
[http]
sslVerify = false
# 凭据:统一 wrapper,不依赖 includeIf ondarwin/onlinux(需 Git 2.36+)
# 低版本 Git 也会加载本节;回退为 git-credential-store(~/.git-credentials)
[credential]
helper = !$HOME/.dotfile/git/git-credential.sh
# 以下 includeIf 需 Git 2.36+;仅用于其它平台差异配置(若有)
[includeIf "ondarwin"]
path = ~/.dotfile/git/.gitconfig.darwin
[includeIf "onlinux"]
path = ~/.dotfile/git/.gitconfig.linux
+3
View File
@@ -0,0 +1,3 @@
# macOS 专用(需 Git 2.36+ includeIf ondarwin)
[help]
autocorrect = prompt
+3
View File
@@ -0,0 +1,3 @@
# Linux 专用(需 Git 2.36+ includeIf onlinux)
[help]
autocorrect = prompt
+5 -3
View File
@@ -32,6 +32,8 @@ _testmain.go
.log .log
go.work go.work
go.work.sum go.work.sum
init_test.go _set_env*.sh
_set_env.sh .env*
_set_env_*.sh !.env.example
Makefile.local
.netrc
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
# 已合并到 git-credential.sh;保留此文件仅为兼容旧配置引用
exec "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/git-credential.sh" "$@"
+43
View File
@@ -0,0 +1,43 @@
#!/bin/bash
# 跨平台 Git 凭据 helper(不依赖 includeIf ondarwin/onlinux,兼容 Git < 2.36)
# macOS: osxkeychain → store
# Linux: libsecret → store
set -euo pipefail
warn_store_fallback() {
local reason="$1"
local marker="${XDG_CACHE_HOME:-$HOME/.cache}/git-credential-store.warned"
[[ -f "$marker" ]] && return 0
mkdir -p "$(dirname "$marker")"
touch "$marker"
cat >&2 <<EOF
提示: Git 凭据使用 store 明文保存到 ~/.git-credentials(${reason})。
建议:
macOS: 通常可用 osxkeychain(Keychain)
Linux: sudo apt install libsecret-1-0 git-credential-libsecret
请确保 ~/.git-credentials 权限为 600。
EOF
}
case "$(uname -s)" in
Darwin)
if command -v git-credential-osxkeychain >/dev/null 2>&1; then
exec git-credential-osxkeychain "$@"
fi
warn_store_fallback "未找到 osxkeychain"
exec git-credential-store "$@"
;;
Linux)
if command -v git-credential-libsecret >/dev/null 2>&1; then
exec git-credential-libsecret "$@"
fi
warn_store_fallback "未找到 git-credential-libsecret"
exec git-credential-store "$@"
;;
*)
warn_store_fallback "未知系统 $(uname -s)"
exec git-credential-store "$@"
;;
esac
+1
View File
@@ -0,0 +1 @@
git remote set-url origin git@github.com:hilaily/.dotfile.git
+255
View File
@@ -0,0 +1,255 @@
version: "2"
run:
allow-parallel-runners: true
timeout: 5m # 超时时间
tests: false
linters:
default: none
enable:
- bodyclose
- errcheck
- errorlint
- govet
- ineffassign
- misspell
- revive
- staticcheck
settings:
errcheck:
exclude-functions:
- io/ioutil.ReadFile
- io.Copy(*bytes.Buffer)
- io.Copy(os.Stdout)
- net.(*)
misspell:
locale: US
revive:
max-open-files: 2048
confidence: 0.1
severity: error
enable-all-rules: false
rules:
- name: argument-limit
arguments:
- 15
severity: warning
disabled: true
- name: atomic
severity: warning
disabled: false
- name: banned-characters
arguments:
- Ω
- Σ
- σ
severity: warning
disabled: false
- name: bool-literal-in-expr
severity: warning
disabled: false
- name: call-to-gc
severity: warning
disabled: false
- name: cognitive-complexity
arguments:
- 25
severity: warning
disabled: false
- name: constant-logical-expr
severity: warning
disabled: false
- name: context-as-argument
severity: warning
disabled: false
- name: context-keys-type
severity: warning
disabled: false
- name: cyclomatic
arguments:
- 25
severity: warning
disabled: false
- name: datarace
severity: warning
disabled: false
- name: deep-exit
severity: warning
disabled: false
- name: defer
arguments:
- - call-chain
- loop
severity: warning
disabled: false
- name: duplicated-imports
severity: warning
disabled: false
- name: early-return
severity: warning
disabled: false
- name: error-naming
severity: warning
disabled: false
- name: error-return
severity: warning
disabled: false
- name: error-strings
severity: warning
disabled: false
- name: errorf
severity: warning
disabled: false
- name: exported
arguments:
- checkPrivateReceivers
- sayRepetitiveInsteadOfStutters
severity: warning
disabled: false
- name: function-result-limit
arguments:
- 6
severity: warning
disabled: false
- name: function-length
arguments:
- 100
- 0
severity: warning
disabled: false
- name: get-return
severity: warning
disabled: false
- name: if-return
severity: warning
disabled: false
- name: increment-decrement
severity: warning
disabled: false
- name: indent-error-flow
severity: warning
disabled: false
- name: modifies-value-receiver
severity: warning
disabled: false
- name: nested-structs
severity: warning
disabled: true
- name: optimize-operands-order
severity: warning
disabled: false
- name: package-comments
severity: warning
disabled: false
- name: range
severity: warning
disabled: false
- name: range-val-in-closure
severity: warning
disabled: false
- name: range-val-address
severity: warning
disabled: false
- name: receiver-naming
severity: warning
disabled: false
- name: redefines-builtin-id
severity: warning
disabled: false
- name: string-of-int
severity: warning
disabled: false
- name: string-format
arguments:
- - core.WriteError[1].Message
- /^([^A-Z]|$)/
- must not start with a capital letter
- - fmt.Errorf[0]
- /(^|[^\.!?])$/
- must not end in punctuation
- - panic
- /^[^\n]*$/
- must not contain line breaks
severity: warning
disabled: false
- name: struct-tag
severity: warning
disabled: false
- name: superfluous-else
severity: warning
disabled: false
- name: time-equal
severity: warning
disabled: false
- name: time-naming
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/HEAD/RULES_DESCRIPTIONS.md#var-naming
- name: var-naming
arguments:
- ["ID", "Id", "id"]
- ["VM"]
- [{ skipInitialismNameChecks = true }]
severity: warning
disabled: true
- name: var-declaration
severity: warning
disabled: false
- name: unconditional-recursion
severity: warning
disabled: false
- name: unexported-naming
severity: warning
disabled: false
- name: unexported-return
disabled: true
- name: unhandled-error
arguments:
- fmt.Printf
- os.(Create|WriteFile|Chmod)
- net.*
- bytes.Buffer.WriteString
- con.WriteString
severity: warning
disabled: true
- name: unnecessary-stmt
severity: warning
disabled: false
- name: unreachable-code
severity: warning
disabled: false
- name: useless-break
severity: warning
disabled: false
- name: waitgroup-by-value
severity: warning
disabled: false
staticcheck:
checks:
- all
- -ST1000
- -ST1001
- -ST1003
- -ST1016
- -ST1020
- -ST1021
- -ST1022
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
Executable
+93
View File
@@ -0,0 +1,93 @@
#!/bin/bash
# 安装并初始化 Fish、tmux 与 Git 的基础 dotfile 环境
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/script/common/help.sh"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/script/common/os-arch.sh"
set -euo pipefail
usage() {
cat <<'EOF'
用法: ./init.sh
安装缺失的基础工具(fish、tmux、git),随后依次执行:
1. fish-init 初始化 Fish 配置、插件与默认 shell
2. tmux-init 初始化 tmux 配置与 TPM 插件
3. git-init 初始化 Git 配置
支持:
macOS Homebrew
Debian/Ubuntu apt
选项:
-h, --help 显示此帮助
说明:
请以需要配置的普通用户运行,不要使用 sudo 运行本脚本。
Linux 安装缺失软件时会请求 sudo;Fish 初始化也会请求 sudo 将 fish
加入 /etc/shells。
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
[[ $# -eq 0 ]] || { echo "错误: 不支持参数: $*" >&2; usage >&2; exit 1; }
die() {
echo "错误: $*" >&2
exit 1
}
run_with_sudo() {
if [[ $EUID -eq 0 ]]; then
"$@"
else
sudo "$@"
fi
}
[[ $EUID -ne 0 ]] || die "请以需要配置的普通用户运行,不要使用 sudo ./init.sh"
[[ -d "$HOME/.dotfile" ]] || die "未找到 $HOME/.dotfile;请将仓库放在该路径后重试"
[[ "$SCRIPT_DIR" -ef "$HOME/.dotfile" ]] || die "当前仓库不是 $HOME/.dotfile;现有初始化脚本依赖该路径"
missing_packages=()
command -v fish >/dev/null 2>&1 || missing_packages+=(fish)
command -v tmux >/dev/null 2>&1 || missing_packages+=(tmux)
command -v git >/dev/null 2>&1 || missing_packages+=(git)
if ((${#missing_packages[@]} == 0)); then
echo "基础工具已安装:fish、tmux、git"
else
echo "安装缺失工具: ${missing_packages[*]}"
case "$(get_os)" in
darwin)
command -v brew >/dev/null 2>&1 || die "未找到 Homebrew;请先运行: bash script/brew-install.sh"
brew install "${missing_packages[@]}"
;;
linux)
command -v apt-get >/dev/null 2>&1 || die "仅支持 apt;请先通过系统包管理器安装: ${missing_packages[*]}"
run_with_sudo apt-get update
run_with_sudo apt-get install -y "${missing_packages[@]}"
;;
*)
die "不支持的系统: $(get_os)"
;;
esac
fi
echo
echo "== 初始化 Fish =="
bash "$SCRIPT_DIR/script/fish-init.sh"
echo
echo "== 初始化 tmux =="
bash "$SCRIPT_DIR/script/tmux-init.sh"
echo
echo "== 初始化 Git =="
bash "$SCRIPT_DIR/script/git-init.sh"
echo
echo "基础环境初始化完成。重新打开终端后 Fish 将作为默认 shell 生效。"
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
defaults write com.googlecode.iterm2.plist LoadPrefsFromCustomFolder -bool true
+3
View File
@@ -0,0 +1,3 @@
#/bin/bash
defaults write com.googlecode.iterm2.plist PrefsCustomFolder -string "~/.dotfile/iterm2"
# then open iterm2, Preferences->General->Settings, Mark 'load preferences from xxx'
-7
View File
@@ -1,7 +0,0 @@
local ret_status="%(?:%{$fg_bold[green]%}➜ :%{$fg_bold[red]%}➜ )"
PROMPT='%{$fg[red]%}%n%{$reset_color%}@%{$fg[blue]%}%m ${ret_status} %{$fg[cyan]%}%c%{$reset_color%} $(git_prompt_info)'
ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[blue]%}git:(%{$fg[red]%}"
ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} "
ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[blue]%}) %{$fg[yellow]%}✗"
ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg[blue]%})"
+1
View File
@@ -0,0 +1 @@
[tools]
+16
View File
@@ -2,6 +2,22 @@ if vim.loader then
vim.loader.enable() vim.loader.enable()
end end
-- 让 Mason / 健康检查能找到本仓库常用的本地 CLI(fd、lazygit、tree-sitter 等)
local _local_bin = vim.fn.expand("~/.local/bin")
if vim.fn.isdirectory(_local_bin) == 1 then
vim.env.PATH = _local_bin .. ":" .. vim.env.PATH
end
-- 全局 npm 包(如 mermaid-cli 的 `mmdc`)通常在 $(npm prefix -g)/bin
do
local ok, out = pcall(vim.fn.system, { "npm", "prefix", "-g" })
if ok and out and out ~= "" then
local npm_bin = vim.fn.trim(out) .. "/bin"
if vim.fn.isdirectory(npm_bin) == 1 then
vim.env.PATH = npm_bin .. ":" .. vim.env.PATH
end
end
end
vim.g.loaded_netrw = 1 vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1 vim.g.loaded_netrwPlugin = 1
+60 -68
View File
@@ -1,73 +1,65 @@
{ {
"FixCursorHold.nvim": { "branch": "master", "commit": "1900f89dc17c603eec29960f57c00bd9ae696495" }, "FixCursorHold.nvim": { "branch": "master", "commit": "1900f89dc17c603eec29960f57c00bd9ae696495" },
"LazyVim": { "branch": "main", "commit": "530e94a9fa19577401e968a9673282c3d79f01e3" }, "LazyVim": { "branch": "main", "commit": "fca0af57cc3851b14f96a795a9c9bfafc5096dd1" },
"LuaSnip": { "branch": "master", "commit": "b152822e1a4bafb6bdf11a16cc26525cbd95ee00" }, "SchemaStore.nvim": { "branch": "main", "commit": "4f1c58a59d3a4da095743dd6f04b73caa0cefc3d" },
"SchemaStore.nvim": { "branch": "main", "commit": "8c46453bdf84ad91877effb95e0b6c7b51ea7dda" }, "avante.nvim": { "branch": "main", "commit": "e89eb79abf5754645e20aa6074da10ed20bba33c" },
"barbar.nvim": { "branch": "master", "commit": "dd852401ee902745b67fc09a83d113b3fe82a96f" }, "barbar.nvim": { "branch": "master", "commit": "53b5a2f34b68875898f0531032fbf090e3952ad7" },
"bufferline.nvim": { "branch": "main", "commit": "73540cb95f8d95aa1af3ed57713c6720c78af915" }, "blink-cmp-avante": { "branch": "master", "commit": "4f494c6e124acbe31a8f5d58effa0c14aa38a6d5" },
"catppuccin": { "branch": "main", "commit": "6af91673ceccbd6e073b66c439e7fce239f72d24" }, "blink.cmp": { "branch": "main", "commit": "451168851e8e2466bc97ee3e026c3dcb9141ce07" },
"cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" }, "bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" },
"cmp-emoji": { "branch": "main", "commit": "e8398e2adf512a03bb4e1728ca017ffeac670a9f" }, "catppuccin": { "branch": "main", "commit": "a7788416689dbefea659d9e9415c87926b0ba5d8" },
"cmp-nvim-lsp": { "branch": "main", "commit": "5af77f54de1b16c34b23cba810150689a3a90312" }, "codecompanion.nvim": { "branch": "main", "commit": "e0780fa9fda504ffb89307cabcb6cbe1ce8eb60c" },
"cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" }, "conform.nvim": { "branch": "master", "commit": "086a40dc7ed8242c03be9f47fbcee68699cc2395" },
"cmp_luasnip": { "branch": "master", "commit": "05a9ab28b53f71d1aece421ef32fee2cb857a843" }, "dashboard-nvim": { "branch": "master", "commit": "0775e567b6c0be96d01a61795f7b64c1758262f6" },
"conform.nvim": { "branch": "master", "commit": "6dc1603ea408f476a57937bbeaf7f86520a21a98" }, "diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" },
"dashboard-nvim": { "branch": "master", "commit": "a0a78099658c7d4be3714f657b18ca8285d5d106" }, "dressing.nvim": { "branch": "master", "commit": "2d7c2db2507fa3c4956142ee607431ddb2828639" },
"dressing.nvim": { "branch": "master", "commit": "5162edb1442a729a885c45455a07e9a89058be2f" }, "flash.nvim": { "branch": "main", "commit": "fcea7ff883235d9024dc41e638f164a450c14ca2" },
"flash.nvim": { "branch": "main", "commit": "7bb4a9c75d1e20cd24185afedeaa11681829ba23" }, "friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" },
"friendly-snippets": { "branch": "main", "commit": "3e9a3f5a0cfcef1741e352c37bda4e82e5eb846a" }, "fzf-lua": { "branch": "main", "commit": "c9e7b7bfbd01f949164988ee1684035468e1995c" },
"gitsigns.nvim": { "branch": "main", "commit": "805610a9393fa231f2c2b49cb521bfa413fadb3d" }, "gemini-cli.nvim": { "branch": "main", "commit": "c9fd62adda823628f5131a939d9c56ef7a898600" },
"indent-blankline.nvim": { "branch": "master", "commit": "3d08501caef2329aba5121b753e903904088f7e6" }, "gitsigns.nvim": { "branch": "main", "commit": "caa98e2e5e4c23a1652c23be839d2e1722cecc29" },
"lazy.nvim": { "branch": "main", "commit": "bef521ac89c8d423f9d092e37b58e8af0c099309" }, "grug-far.nvim": { "branch": "main", "commit": "dc4684e163971bb1f5bfb93fbd4bb3e892bf9b15" },
"lsp_signature.nvim": { "branch": "master", "commit": "c6aeb2f1d2538bbdfdaab1664d9d4c3c75aa9db8" }, "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" },
"lualine.nvim": { "branch": "master", "commit": "0a5a66803c7407767b799067986b4dc3036e1983" }, "lazydev.nvim": { "branch": "main", "commit": "ff2cbcba459b637ec3fd165a2be59b7bbaeedf0d" },
"mason-lspconfig.nvim": { "branch": "main", "commit": "05744f0f1967b5757bd05c08df4271ab8ec990aa" }, "lsp_signature.nvim": { "branch": "master", "commit": "af7e4074d85d785cf6614352ba9ad3b28a1f8a56" },
"mason-nvim-dap.nvim": { "branch": "main", "commit": "67210c0e775adec55de9826b038e8b62de554afc" }, "lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" },
"mason.nvim": { "branch": "main", "commit": "751b1fcbf3d3b783fcf8d48865264a9bcd8f9b10" }, "mason-lspconfig.nvim": { "branch": "main", "commit": "25f609e7fca78af7cede4f9fa3af8a94b1c4950b" },
"mini.ai": { "branch": "main", "commit": "55e9b7217f29e62f734e239bfeed5731a065d801" }, "mason-nvim-dap.nvim": { "branch": "main", "commit": "9a10e096703966335bd5c46c8c875d5b0690dade" },
"mini.bufremove": { "branch": "main", "commit": "931a3bb514147d9e812767275c4beba6b779b1d3" }, "mason.nvim": { "branch": "main", "commit": "44d1e90e1f66e077268191e3ee9d2ac97cc18e65" },
"mini.comment": { "branch": "main", "commit": "f9f1a646fd3d9df7397aa1b9550a875fe8189eb0" }, "mini.ai": { "branch": "main", "commit": "4b0a6207341d895b6cfe9bcb1e4d3e8607bfe4f4" },
"mini.indentscope": { "branch": "main", "commit": "a8274b6ea2d868198d27bd91a31ed5ea3a6a5744" }, "mini.icons": { "branch": "main", "commit": "5b9076dae1bfbe47ba4a14bc8b967cde0ab5d77e" },
"mini.pairs": { "branch": "main", "commit": "5c975d8f68dc1e11bf4b20ced71e7987ed782513" }, "mini.pairs": { "branch": "main", "commit": "b7fde3719340946feb75017ef9d75edebdeb0566" },
"mini.surround": { "branch": "main", "commit": "0f528eb2e1bab420c0569d9e52615144c51db920" }, "neo-tree.nvim": { "branch": "main", "commit": "84c75e7a7e443586f60508d12fc50f90d9aee14e" },
"neo-tree.nvim": { "branch": "v3.x", "commit": "7aad1bf3f6b849cbf108e02c55ad4d701cb4d33a" }, "neotest": { "branch": "master", "commit": "72bc8f1ec62a590fb47368c81f89610e0f353e28" },
"neoconf.nvim": { "branch": "main", "commit": "d4a48c2a6fdeec138605cee4eb6f8c6fafd0b3ed" }, "neotest-golang": { "branch": "main", "commit": "58d07a76d714f8f768bbe27711b06d41ca237728" },
"neodev.nvim": { "branch": "main", "commit": "ce9a2e8eaba5649b553529c5498acb43a6c317cd" }, "noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" },
"neotest": { "branch": "master", "commit": "5caac5cc235d495a2382bc2980630ef36ac87032" }, "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" },
"neotest-go": { "branch": "main", "commit": "27c80deab9cf5cb30b20ee407b3a6c7285518128" }, "nvim-cmp": { "branch": "main", "commit": "f17d9b4394027ff4442b298398dfcaab97e40c4f" },
"neotest-plenary": { "branch": "master", "commit": "dcaf5ed67a9e28a246e9783319e5aa6c9ea1c584" }, "nvim-dap": { "branch": "master", "commit": "4f5deb110d9ff8994d96c21df95e2271d11214f9" },
"noice.nvim": { "branch": "main", "commit": "f4decbc7a80229ccc9f86026b74bdcf0c39e38a7" }, "nvim-dap-go": { "branch": "main", "commit": "b4421153ead5d726603b02743ea40cf26a51ed5f" },
"nui.nvim": { "branch": "main", "commit": "a3597dc88b53489d3fddbddbbd13787355253bb0" }, "nvim-dap-ui": { "branch": "master", "commit": "f5b6673f374626515401c5bc51b005f784a4f252" },
"nvim-cmp": { "branch": "main", "commit": "cd2cf0c124d3de577fb5449746568ee8e601afc8" }, "nvim-dap-virtual-text": { "branch": "master", "commit": "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" },
"nvim-dap": { "branch": "master", "commit": "5a2f7121869394502521c52b2bc581ab22c69447" }, "nvim-lint": { "branch": "master", "commit": "4b03656c09c1561f89b6aa0665c15d292ba9499d" },
"nvim-dap-go": { "branch": "main", "commit": "5faf165f5062187320eaf9d177c3c1f647adc22e" }, "nvim-lspconfig": { "branch": "master", "commit": "5492a24edd68f78d8a778edcb8905d0a28993abc" },
"nvim-dap-ui": { "branch": "master", "commit": "334cf3038c4756e6ab999cbac67c847fb654c190" }, "nvim-nio": { "branch": "master", "commit": "21f5324bfac14e22ba26553caf69ec76ae8a7662" },
"nvim-dap-virtual-text": { "branch": "master", "commit": "3e8e207513e6ef520894950acd76b79902714103" }, "nvim-tree.lua": { "branch": "master", "commit": "3603f069ff783c31986894a56c2a6755331b0802" },
"nvim-lint": { "branch": "master", "commit": "861a04313501563bb1b11f125ae9b7237a517b9b" }, "nvim-treesitter": { "branch": "main", "commit": "7caec274fd19c12b55902a5b795100d21531391f" },
"nvim-lspconfig": { "branch": "master", "commit": "a3d9395455f2b2e3b50a0b0f37b8b4c23683f44a" }, "nvim-treesitter-textobjects": { "branch": "main", "commit": "93d60a475f0b08a8eceb99255863977d3a25f310" },
"nvim-nio": { "branch": "master", "commit": "8765cbc4d0c629c8158a5341e1b4305fd93c3a90" }, "nvim-ts-autotag": { "branch": "main", "commit": "8e1c0a389f20bf7f5b0dd0e00306c1247bda2595" },
"nvim-notify": { "branch": "master", "commit": "5371f4bfc1f6d3adf4fe9d62cd3a9d44356bfd15" }, "nvim-web-devicons": { "branch": "master", "commit": "d7462543c9e366c0d196c7f67a945eaaf5d99414" },
"nvim-spectre": { "branch": "master", "commit": "4651801ba37a9407b7257287aec45b6653ffc5e9" }, "persistence.nvim": { "branch": "main", "commit": "b20b2a7887bd39c1a356980b45e03250f3dce49c" },
"nvim-tree.lua": { "branch": "master", "commit": "64f61e4c913047a045ff90bd188dd3b54ee443cf" },
"nvim-treesitter": { "branch": "master", "commit": "3607d9c59cb16ed5368ecfed53e8ca1735bb98fb" },
"nvim-treesitter-context": { "branch": "master", "commit": "2650e6431f7daba5d9c2c64134fa5eb2312eb3d7" },
"nvim-treesitter-textobjects": { "branch": "master", "commit": "23b820146956b3b681c19e10d3a8bc0cbd9a1d4c" },
"nvim-ts-autotag": { "branch": "main", "commit": "531f48334c422222aebc888fd36e7d109cb354cd" },
"nvim-ts-context-commentstring": { "branch": "main", "commit": "0bdccb9c67a42a5e2d99384dc9bfa29b1451528f" },
"nvim-web-devicons": { "branch": "master", "commit": "5b9067899ee6a2538891573500e8fd6ff008440f" },
"persistence.nvim": { "branch": "main", "commit": "4982499c1636eac254b72923ab826ee7827b3084" },
"playground": { "branch": "master", "commit": "ba48c6a62a280eefb7c85725b0915e021a1a0749" }, "playground": { "branch": "master", "commit": "ba48c6a62a280eefb7c85725b0915e021a1a0749" },
"plenary.nvim": { "branch": "master", "commit": "08e301982b9a057110ede7a735dd1b5285eb341f" }, "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" },
"render-markdown.nvim": { "branch": "main", "commit": "c7188a8f9d2953696b6303caccbf39c51fa2c1b1" },
"sidekick.nvim": { "branch": "main", "commit": "17447a05f9385e5f8372b61530f6f9329cb82421" },
"snacks.nvim": { "branch": "main", "commit": "ad9ede6a9cddf16cedbd31b8932d6dcdee9b716e" },
"symbols-outline.nvim": { "branch": "master", "commit": "564ee65dfc9024bdde73a6621820866987cbb256" }, "symbols-outline.nvim": { "branch": "master", "commit": "564ee65dfc9024bdde73a6621820866987cbb256" },
"telescope-file-browser.nvim": { "branch": "master", "commit": "4d5fd21bae12ee6e9a79232e1c377f43c419d0c5" }, "telescope-file-browser.nvim": { "branch": "master", "commit": "3610dc7dc91f06aa98b11dca5cc30dfa98626b7e" },
"telescope-fzf-native.nvim": { "branch": "main", "commit": "9ef21b2e6bb6ebeaf349a0781745549bbb870d27" }, "telescope-fzf-native.nvim": { "branch": "main", "commit": "6fea601bd2b694c6f2ae08a6c6fab14930c60e2c" },
"telescope.nvim": { "branch": "master", "commit": "fac83a556e7b710dc31433dec727361ca062dbe9" }, "telescope.nvim": { "branch": "master", "commit": "a8c2223ea6b185701090ccb1ebc7f4e41c4c9784" },
"todo-comments.nvim": { "branch": "main", "commit": "a7e39ae9e74f2c8c6dc4eea6d40c3971ae84752d" }, "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" },
"tokyonight.nvim": { "branch": "main", "commit": "67afeaf7fd6ebba000633e89f63c31694057edde" }, "tokyonight.nvim": { "branch": "main", "commit": "cdc07ac78467a233fd62c493de29a17e0cf2b2b6" },
"trouble.nvim": { "branch": "main", "commit": "b9cf677f20bb2faa2dacfa870b084e568dca9572" }, "trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" },
"vim-illuminate": { "branch": "master", "commit": "e522e0dd742a83506db0a72e1ced68c9c130f185" }, "ts-comments.nvim": { "branch": "main", "commit": "123a9fb12e7229342f807ec9e6de478b1102b041" },
"vim-startuptime": { "branch": "master", "commit": "ac2cccb5be617672add1f4f3c0a55ce99ba34e01" }, "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }
"vim-vsnip": { "branch": "master", "commit": "02a8e79295c9733434aab4e0e2b8c4b7cea9f3a9" },
"vim-vsnip-integ": { "branch": "master", "commit": "1914e72cf3de70df7f5dde476cd299aba2440aef" },
"which-key.nvim": { "branch": "main", "commit": "4433e5ec9a507e5097571ed55c02ea9658fb268a" }
} }
+10 -3
View File
@@ -1,10 +1,17 @@
{ {
"extras": [ "extras": [
"lazyvim.plugins.extras.editor.telescope",
"lazyvim.plugins.extras.test.core", "lazyvim.plugins.extras.test.core",
"lazyvim.plugins.extras.lang.go" "lazyvim.plugins.extras.lang.go",
"lazyvim.plugins.extras.lang.typescript",
"lazyvim.plugins.extras.lang.json",
"lazyvim.plugins.extras.dap.core",
"lazyvim.plugins.extras.formatting.prettier",
"lazyvim.plugins.extras.ai.avante"
], ],
"install_version": 7,
"news": { "news": {
"NEWS.md": "3314" "NEWS.md": "11866"
}, },
"version": 3 "version": 8
} }
+6 -2
View File
@@ -1,3 +1,7 @@
vim.api.nvim_create_user_command("W", function()
require("utils").sudo_write()
end, { desc = "Write file with sudo (tee)" })
-- Turn off paste mode when leaving insert -- Turn off paste mode when leaving insert
vim.api.nvim_create_autocmd("InsertLeave", { vim.api.nvim_create_autocmd("InsertLeave", {
pattern = "*", pattern = "*",
@@ -7,12 +11,12 @@ vim.api.nvim_create_autocmd("InsertLeave", {
-- Disable the concealing in some file formats -- Disable the concealing in some file formats
-- The default conceallevel is 3 in LazyVim -- The default conceallevel is 3 in LazyVim
vim.api.nvim_create_autocmd("FileType", { vim.api.nvim_create_autocmd("FileType", {
pattern = {"js","tsx","ts", "json", "jsonc", "markdown","md","css","html" }, pattern = { "js", "tsx", "ts", "json", "jsonc", "markdown", "md", "css", "html" },
callback = function() callback = function()
vim.opt.conceallevel = 0 vim.opt.conceallevel = 0
vim.bo.tabstop = 2 vim.bo.tabstop = 2
vim.bo.softtabstop = 2 vim.bo.softtabstop = 2
vim.bo.shiftwidth = 2 vim.bo.shiftwidth = 2
vim.bo.expand = true -- vim.bo.expand = true
end, end,
}) })
+156 -140
View File
@@ -1,164 +1,180 @@
local keymap = vim.keymap local keymap = vim.keymap
local opts = { noremap = true, silent = true }
-- <Leader>a
keymap.set('n', "<Leader>aa", "<cmd>@:<cr>", {desc="execute last command again" })
-- <Leader>b for buffer -- <Leader>b for buffer
keymap.set('n', "<Leader>bq", "<cmd>q<cr>", {desc="quit" }) keymap.set("n", "<Leader>bq", "<cmd>q<cr>", { desc = "quit" })
keymap.set('n', "<Leader>bs", "<cmd>w<cr>", {desc="save" }) keymap.set("n", "<Leader>bs", "<cmd>w<cr>", { desc = "save" })
keymap.set('n', "<Leader>br", "<cmd>e!<cr>", {desc="reload" }) keymap.set("n", "<Leader>br", "<cmd>e!<cr>", { desc = "reload" })
keymap.set('n', "<Leader>bd", "<cmd>BufferClose<cr>", {desc="close buffer" }) keymap.set("n", "<Leader>bd", "<cmd>BufferClose<cr>", { desc = "close buffer" })
keymap.set({'n','v'}, "<Leader>b/", "<cmd>CommentToggle<CR>", {desc="toggle comment" })
-- <Leader>c -- <Leader>c
keymap.set('n', "<Leader>cs", "<cmd>SymbolsOutline<cr>", { desc = "Symbols Outline" }) keymap.set("n", "<Leader>cs", "<cmd>SymbolsOutline<cr>", { desc = "Symbols Outline" })
-- <Leader>D -- <Leader>D for Trouble (v3 syntax)
keymap.set('n', "<Leader>Dt", "<cmd>TroubleToggle<cr>", {desc="trouble" }) keymap.set("n", "<Leader>Dt", "<cmd>Trouble diagnostics toggle<cr>", { desc = "trouble diagnostics" })
keymap.set('n', "<Leader>Dw", "<cmd>TroubleToggle lsp_workspace_diagnostics<cr>", {desc="workspace" }) keymap.set("n", "<Leader>Dd", "<cmd>Trouble diagnostics toggle filter.buf=0<cr>", { desc = "document diagnostics" })
keymap.set('n', "<Leader>Dd", "<cmd>TroubleToggle lsp_document_diagnostics<cr>", {desc= "document" }) keymap.set("n", "<Leader>Dq", "<cmd>Trouble qflist toggle<cr>", { desc = "quickfix" })
keymap.set('n', "<Leader>Dq", "<cmd>TroubleToggle quickfix<cr>", {desc= "quickfix" }) keymap.set("n", "<Leader>Dl", "<cmd>Trouble loclist toggle<cr>", { desc = "loclist" })
keymap.set('n', "<Leader>Dl", "<cmd>TroubleToggle loclist<cr>", {desc= "loclist" }) keymap.set("n", "<Leader>Dr", "<cmd>Trouble lsp_references toggle<cr>", { desc = "references" })
keymap.set('n', "<Leader>Dr", "<cmd>TroubleToggle lsp_references<cr>", {desc= "references" })
-- <Leader>d
keymap.set('n', "<Leader>dd", "<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<cr>", {desc= "show diagnostics" })
keymap.set('n', "<Leader>dc", "<cmd>lua require'dap'.continue()<cr>", {desc= "continue" })
keymap.set('n', "<Leader>db", ':lua require"dap".toggle_breakpoint()<CR>', {desc= "Toggle Breadpoint" })
keymap.set('n', "<Leader>dj", ':lua require"dap".step_over()<CR>', {desc= "step over" })
keymap.set('n', "<Leader>dk", ':lua require"dap".step_out()<CR>', {desc= "step out" })
keymap.set('n', "<Leader>dl", ':lua require"dap".step_into()<CR>', {desc= "step into" })
keymap.set('n', "<Leader>du", ':lua require"dap".up()<CR>', {desc= "up" })
keymap.set('n', "<Leader>d_", ':lua require"dap".disconnect();require"dap".stop();require"dap".run_last()<CR>', {desc= "disconnect" })
keymap.set('n', "<Leader>di", ':lua require"dap.ui.variables".visual_hover()<CR>', {desc= "visual_hover" })
keymap.set('n', "<Leader>ds", ':lua local widgets=require"dap.ui.widgets";widgets.centered_float(widgets.scopes)<CR>', {desc= "centered_float" })
-- <Leader>d for debug
keymap.set("n", "<Leader>dd", "<cmd>lua vim.diagnostic.open_float()<cr>", { desc = "show diagnostics" })
keymap.set("n", "<Leader>dc", '<cmd>lua require("dap").continue()<cr>', { desc = "continue" })
keymap.set("n", "<Leader>db", '<cmd>lua require("dap").toggle_breakpoint()<cr>', { desc = "Toggle Breakpoint" })
keymap.set("n", "<Leader>dj", '<cmd>lua require("dap").step_over()<cr>', { desc = "step over" })
keymap.set("n", "<Leader>dk", '<cmd>lua require("dap").step_out()<cr>', { desc = "step out" })
keymap.set("n", "<Leader>dl", '<cmd>lua require("dap").step_into()<cr>', { desc = "step into" })
keymap.set("n", "<Leader>du", '<cmd>lua require("dap").up()<cr>', { desc = "up" })
keymap.set("n", "<Leader>d_", '<cmd>lua require("dap").disconnect();require("dap").stop();require("dap").run_last()<cr>', { desc = "disconnect" })
keymap.set("n", "<Leader>di", '<cmd>lua require("dap.ui.variables").visual_hover()<cr>', { desc = "visual hover" })
keymap.set("n", "<Leader>ds", '<cmd>lua local w=require("dap.ui.widgets");w.centered_float(w.scopes)<cr>', { desc = "scopes" })
-- <Leader>f -- <Leader>f
keymap.set('n', "<Leader>fm", "<cmd>lua require'utils'.open_md()<cr>", {desc= "open a markdown file in vscode" }) keymap.set("n", "<Leader>fm", "<cmd>lua require('utils').open_md()<cr>", { desc = "open markdown in external app" })
keymap.set('n', "<Leader>fs", "<cmd>w<cr>", {desc= "save file" }) keymap.set("n", "<Leader>fs", "<cmd>w<cr>", { desc = "save file" })
keymap.set('n', "<Leader>ft", "<cmd>NvimTreeToggle<cr>", {desc= "toggle nvim tree" }) keymap.set("n", "<Leader>ft", "<cmd>NvimTreeToggle<cr>", { desc = "toggle nvim tree" })
keymap.set('n', "<Leader>fr", "<cmd>RnvimrToggle<cr>", {desc= "toggle rnvimr" }) keymap.set("n", "<Leader>fy", "<cmd>lua require('utils').yank_filepath()<cr>", { desc = "copy file path" })
keymap.set('n', "<Leader>fy", "<cmd>lua require'utils'.yank_filepath()<cr>", {desc= "copy the file path" }) keymap.set("n", "<Leader>fd", "<cmd>lua require('utils').yank_file_dir()<cr>", { desc = "copy dir path" })
keymap.set('n', "<Leader>fd", "<cmd>lua require'utils'.yank_file_dir()<cr>", {desc= "copy the file path" }) keymap.set("n", "<Leader>fl", "<cmd>NvimTreeFindFile<CR>", { desc = "find file in tree" })
keymap.set('n', "<Leader>fl", "<cmd>NvimTreeFindFile<CR>", {desc= "find file" })
-- <Leader>g -- <Leader>g
keymap.set('n', "<Leader>gj", "<cmd>lua require 'gitsigns'.next_hunk()<cr>", {desc= "Next Hunk" }) keymap.set("n", "<Leader>gj", "<cmd>lua require('gitsigns').next_hunk()<cr>", { desc = "Next Hunk" })
keymap.set('n', "<Leader>gk", "<cmd>lua require 'gitsigns'.prev_hunk()<cr>", {desc= "Prev Hunk" }) keymap.set("n", "<Leader>gk", "<cmd>lua require('gitsigns').prev_hunk()<cr>", { desc = "Prev Hunk" })
keymap.set('n', "<Leader>gl", "<cmd>lua require 'gitsigns'.blame_line()<cr>", {desc= "Blame" }) keymap.set("n", "<Leader>gl", "<cmd>lua require('gitsigns').blame_line()<cr>", { desc = "Blame" })
keymap.set('n', "<Leader>gp", "<cmd>lua require 'gitsigns'.preview_hunk()<cr>", {desc= "Preview Hunk" }) keymap.set("n", "<Leader>gp", "<cmd>lua require('gitsigns').preview_hunk()<cr>", { desc = "Preview Hunk" })
keymap.set('n', "<Leader>gr", "<cmd>lua require 'gitsigns'.reset_hunk()<cr>", {desc= "Reset Hunk" }) keymap.set("n", "<Leader>gr", "<cmd>lua require('gitsigns').reset_hunk()<cr>", { desc = "Reset Hunk" })
keymap.set('n', "<Leader>gR", "<cmd>lua require 'gitsigns'.reset_buffer()<cr>", {desc= "Reset Buffer" }) keymap.set("n", "<Leader>gR", "<cmd>lua require('gitsigns').reset_buffer()<cr>", { desc = "Reset Buffer" })
keymap.set('n', "<Leader>gs", "<cmd>lua require 'gitsigns'.stage_hunk()<cr>", {desc= "Stage Hunk" }) keymap.set("n", "<Leader>gs", "<cmd>lua require('gitsigns').stage_hunk()<cr>", { desc = "Stage Hunk" })
keymap.set('n', "<Leader>gS", "<cmd>lua require 'gitsigns'.stage_buffer()<cr>", {desc= "Stage Buffer" }) keymap.set("n", "<Leader>gS", "<cmd>lua require('gitsigns').stage_buffer()<cr>", { desc = "Stage Buffer" })
keymap.set('n', "<Leader>gu", "<cmd>lua require 'gitsigns'.undo_stage_hunk()<cr>", {desc= "Undo Stage Hunk", }) keymap.set("n", "<Leader>gu", "<cmd>lua require('gitsigns').undo_stage_hunk()<cr>", { desc = "Undo Stage Hunk" })
keymap.set('n', "<Leader>go", "<cmd>Telescope git_status<cr>", {desc= "Open changed file" }) keymap.set("n", "<Leader>go", "<cmd>Telescope git_status<cr>", { desc = "Open changed file" })
keymap.set('n', "<Leader>gb", "<cmd>Telescope git_branches<cr>", {desc= "Checkout branch" }) keymap.set("n", "<Leader>gb", "<cmd>Telescope git_branches<cr>", { desc = "Checkout branch" })
keymap.set('n', "<Leader>gc", "<cmd>Telescope git_commits<cr>", {desc= "Checkout commit" }) keymap.set("n", "<Leader>gc", "<cmd>Telescope git_commits<cr>", { desc = "Checkout commit" })
keymap.set('n', "<Leader>gC", "<cmd>Telescope git_bcommits<cr>", {desc= "Checkout commit(for current file)", }) keymap.set("n", "<Leader>gC", "<cmd>Telescope git_bcommits<cr>", { desc = "Checkout commit(for current file)" })
keymap.set('n', "<Leader>gd", "<cmd>Gitsigns diffthis HEAD<cr>", {desc= "Git Diff", }) keymap.set("n", "<Leader>gd", "<cmd>Gitsigns diffthis HEAD<cr>", { desc = "Git Diff" })
-- <Leader>h -- <Leader>h
keymap.set('n', '<Leader>h', ':set hlsearch!<CR>', { noremap = true, silent = true }) -- no hl keymap.set("n", "<Leader>h", ":set hlsearch!<CR>", { noremap = true, silent = true, desc = "toggle hlsearch" })
-- <Leader>l for lsp
keymap.set('n', '<Leader>l', "", {desc="+Language"})
keymap.set({'n','v'}, '<Leader>la', "<cmd>lua vim.lsp.buf.code_action()<cr>", {desc="Code Action" })
--keymap.set('n', '<Leader>lA', "<cmd>Lspsaga range_code_action<cr>", {desc="Selected Action" })
keymap.set('n', '<Leader>ld', "<cmd>Telescope lsp_document_diagnostics<cr>", {desc="Document Diagnostics" })
keymap.set('n', '<Leader>lD', "<cmd>Telescope lsp_workspace_diagnostics<cr>", {desc="Workspace Diagnostics" })
keymap.set('n', '<Leader>lf', "<cmd>LspFormatting<cr>", {desc="Format" })
--keymap.set('n', '<Leader>lF', "<cmd>Lspsaga lsp_finder<cr>", {desc="LSP Finder" })
keymap.set('n', '<Leader>li', "<cmd>lua vim.lsp.buf.implementation()<cr>", {desc="implement" })
keymap.set('n', '<Leader>ln', "<cmd>lua vim.lsp.buf.hover()<cr>", {desc="hover" })
--keymap.set('n', '<Leader>lL', "<cmd>Lspsaga show_line_diagnostics<cr>", {desc="Line Diagnostics" })
keymap.set('n', '<Leader>lk', "<cmd>: LspRestart<cr>", {desc="restart lsp server" })
keymap.set('n', '<Leader>ll', "<cmd>lua vim.diagnostic.goto_next()<cr>", {desc="next diagnostic" })
keymap.set('n', '<Leader>lo', "<cmd>: SymbolsOutline<cr>", {desc="symbols outline" })
keymap.set('n', '<Leader>lp', "<cmd>lua vim.diagnostic.goto_prev()<cr>", {desc="prev diagnostic" })
--keymap.set('n', '<Leader>lP', "<cmd>Lspsaga preview_definition<cr>", {desc="Preview Definition" })
keymap.set('n', '<Leader>lq', "<cmd>Telescope quickfix<cr>", {desc="Quickfix" })
keymap.set('n', '<Leader>lr', "<cmd>lua vim.lsp.buf.references()<cr>", {desc="references" })
keymap.set('n', '<leader>lR', "<cmd>lua vim.lsp.buf.rename()<cr>", { desc = "Rename" })
--keymap.set('n', '<Leader>lR', "<cmd>Lspsaga rename<cr>", {desc="Rename" })
keymap.set('n', '<Leader>lt', "<cmd>LspTypeDefinition<cr>", {desc="Type Definition" })
keymap.set('n', '<Leader>lx', "<cmd>cclose<cr>", {desc="Close Quickfix" })
keymap.set('n', '<Leader>ls', "<cmd>Telescope lsp_document_symbols<cr>", {desc="Document Symbols" })
keymap.set('n', '<Leader>lS', "<cmd>Telescope lsp_dynamic_workspace_symbols<cr>", {desc="Workspace Symbols" })
keymap.set('n', '<Leader>lz', "<cmd>LspInfo<cr>", {desc="Info" })
keymap.set('n', '<Leader>l,', "<cmd>LspInstallInfo<cr>", {desc="LSP servers" })
-- <Leader>q -- <Leader>q
keymap.set('n', "<Leader>qq", "<cmd>qall<cr>", {desc= "quit" }) keymap.set("n", "<Leader>qq", "<cmd>qall<cr>", { desc = "quit all" })
-- <Leader>s for search
keymap.set("n", "<Leader>sb", "<cmd>Telescope git_branches<cr>", { desc = "Checkout branch" })
keymap.set("n", "<Leader>sc", "<cmd>nohl<cr>", { desc = "no highlight" })
keymap.set("n", "<Leader>sd", "<cmd>Telescope diagnostics bufnr=0<cr>", { desc = "Document Diagnostics" })
keymap.set("n", "<Leader>sD", "<cmd>Telescope diagnostics<cr>", { desc = "Workspace Diagnostics" })
keymap.set("n", "<Leader>sf", "<cmd>Telescope find_files<cr>", { desc = "Find File" })
keymap.set("n", "<Leader>sr", function()
require("telescope.builtin").oldfiles({ cwd = vim.uv.cwd() })
end, { desc = "Old File" })
keymap.set("n", "<Leader>sm", "<cmd>Telescope marks<cr>", { desc = "Marks" })
keymap.set("n", "<Leader>sM", "<cmd>Telescope man_pages<cr>", { desc = "Man Pages" })
keymap.set("n", "<Leader>sR", "<cmd>Telescope registers<cr>", { desc = "Registers" })
keymap.set("n", "<Leader>st", "<cmd>Telescope live_grep<cr>", { desc = "Text" })
keymap.set("n", "<Leader>s,", function()
local ok, fzf_lua = pcall(require, "fzf-lua")
if ok then
fzf_lua.grep_cword()
else
require("telescope.builtin").grep_string({ word_match = "-w" })
end
end, { desc = "Search word under cursor" })
-- <Leader>s -- <Leader>t for test
keymap.set('n', "<Leader>sb", "<cmd>Telescope git_branches<cr>", {desc= "Checkout branch" }) keymap.set("n", "<Leader>tt", '<cmd>lua require("neotest").run.run()<cr>', { desc = "TestNearest" })
keymap.set('n', "<Leader>sc", "<cmd>:nohl<cr>", {desc= "no highlight" }) keymap.set("n", "<Leader>tf", '<cmd>lua require("neotest").run.run(vim.fn.expand("%"))<cr>', { desc = "TestFile" })
keymap.set('n', "<Leader>sd", "<cmd>Telescope lsp_document_diagnostics<cr>", {desc= "Document Diagnostics" }) keymap.set("n", "<Leader>tc", "<cmd>GoCover<cr>", { desc = "go coverage" })
keymap.set('n', "<Leader>sD", "<cmd>Telescope lsp_workspace_diagnostics<cr>", {desc= "Workspace Diagnostics" }) keymap.set("n", "<Leader>tC", "<cmd>GoCoverClear<cr>", { desc = "go coverage clear" })
keymap.set('n', "<Leader>sf", "<cmd>Telescope find_files<CR><cr>", {desc= "Find File" }) keymap.set("n", "<Leader>tb", '<cmd>lua require("dap").toggle_breakpoint()<cr>', { desc = "set break point" })
keymap.set('n', "<Leader>sr", function() require("telescope.builtin").oldfiles({ cwd = vim.loop.cwd() }) end, {desc= "Old File" }) keymap.set("n", "<Leader>tr", '<cmd>lua require("dap").continue()<cr>', { desc = "continue" })
keymap.set('n', "<Leader>sm", "<cmd>Telescope marks<cr>", {desc= "Marks" })
keymap.set('n', "<Leader>sM", "<cmd>Telescope man_pages<cr>", {desc= "Man Pages" })
keymap.set('n', "<Leader>sR", "<cmd>Telescope registers<cr>", {desc= "Registers" })
keymap.set('n', "<Leader>st", "<cmd>Telescope live_grep<cr>", {desc= "Text" })
keymap.set('n', "<Leader>sT", "<cmd>Telescope live_grep<cr>", {desc= "Text" })
keymap.set('n', "<Leader>s,", "<cmd>FzfLua grep_cword<cr>", {desc= "Search word under cursor" })
-- <Leader>S
keymap.set('n', "<Leader>Ss", "<cmd>SessionSave<cr>", {desc= "Save Session" })
keymap.set('n', "<Leader>Sl", "<cmd>SessionLoad<cr>", {desc= "Load Session" })
-- <Leader>t
keymap.set('n', "<Leader>ta", "<cmd>TestSuite -v -cover<cr>", {desc= "TestSuite" })
keymap.set('n', "<Leader>tt", "<cmd>lua require('neotest').run.run() <cr>", {desc= "TestNearest" })
keymap.set('n', "<Leader>tf", '<cmd>lua require("neotest").run.run(vim.fn.expand("%"))<cr>', {desc= "TestFile" })
keymap.set('n', "<Leader>tc", "<cmd>GoCover<cr>", {desc="go coverage" })
keymap.set('n', "<Leader>tC", "<cmd>GoCoverClear<cr>", {desc= "go coverage clear" })
keymap.set('n', "<Leader>tb", "<cmd>lua require'dap'.toggle_breakpoint()<cr>", {desc= "set break point" })
keymap.set('n', "<Leader>tr", "<cmd>lua require'dap'.continue()<cr>", {desc= "continue" })
keymap.set('n', "<Leader>zs", "<cmd>TZBottom<cr>", {desc="toggle status line" })
keymap.set('n', "<Leader>zt", "<cmd>TZTop<cr>", {desc= "toggle tab bar" })
keymap.set('n', "<Leader>zz", "<cmd>TZAtaraxis<cr>", {desc= "toggle zen" })
-- <Leader>; -- <Leader>;
keymap.set('n', '<Leader>;', ':Dashboard<CR>', { noremap = true, silent = true }) keymap.set("n", "<Leader>;", "<cmd>Dashboard<CR>", { noremap = true, silent = true, desc = "Dashboard" })
-- Ctrl -- Ctrl-p: find files with recent-first boost
keymap.set('n', '<C-p>', ":Telescope find_files<CR>", { noremap = true, silent = true }) keymap.set("n", "<C-p>", function()
-- better window movement local builtin = require("telescope.builtin")
keymap.set('n', '<C-h>', '<C-w>h', { silent = true }) local recent_paths = {}
keymap.set('n', '<C-j>', '<C-w>j', { silent = true }) for _, file in ipairs(vim.v.oldfiles) do
keymap.set('n', '<C-k>', '<C-w>k', { silent = true }) if vim.fn.filereadable(file) == 1 then
keymap.set('n', '<C-l>', '<C-w>l', { silent = true }) local abs_path = vim.fn.fnamemodify(file, ":p")
-- resize with arrows local rel_path = vim.fn.fnamemodify(file, ":.")
keymap.set('n', '<C-Up>', ':resize -2<CR>', { silent = true }) recent_paths[abs_path] = true
keymap.set('n', '<C-Down>', ':resize +2<CR>', { silent = true }) recent_paths[rel_path] = true
keymap.set('n', '<C-Left>', ':vertical resize -2<CR>', { silent = true }) recent_paths[vim.fn.fnamemodify(file, ":t")] = true
keymap.set('n', '<C-Right>', ':vertical resize +2<CR>', { silent = true }) end
end
local ok, _ = pcall(require, "telescope._extensions.fzf")
if ok then
builtin.find_files({ hidden = true, no_ignore = false })
else
local sorters = require("telescope.sorters")
builtin.find_files({
hidden = true,
no_ignore = false,
sorter = sorters.Sorter:new({
discard = true,
scoring_function = function(_, prompt, line, entry)
local score = 0
local path = entry.path or entry.value or line
local abs_path = vim.fn.fnamemodify(path, ":p")
local rel_path = vim.fn.fnamemodify(path, ":.")
local filename = vim.fn.fnamemodify(path, ":t")
if recent_paths[abs_path] or recent_paths[rel_path] or recent_paths[filename] then
score = 1000
end
if prompt and prompt ~= "" then
if path:lower():find(prompt:lower(), 1, true) then
score = score + 100
end
end
return score
end,
}),
})
end
end, { noremap = true, silent = true, desc = "Find Files (Recent First)" })
keymap.set('n', '<C-q>', ':call QuickFixToggle()<CR>', { noremap = true, silent = true }) -- Window movement
keymap.set("n", "<C-h>", "<C-w>h", { silent = true })
keymap.set("n", "<C-j>", "<C-w>j", { silent = true })
keymap.set("n", "<C-k>", "<C-w>k", { silent = true })
keymap.set("n", "<C-l>", "<C-w>l", { silent = true })
-- Resize with arrows
keymap.set("n", "<C-Up>", ":resize -2<CR>", { silent = true })
keymap.set("n", "<C-Down>", ":resize +2<CR>", { silent = true })
keymap.set("n", "<C-Left>", ":vertical resize -2<CR>", { silent = true })
keymap.set("n", "<C-Right>", ":vertical resize +2<CR>", { silent = true })
-- Other -- Quickfix toggle
-- better edit keymap.set("n", "<C-q>", function()
keymap.set('n', 'Y', 'y$', {}) for _, win in pairs(vim.fn.getwininfo()) do
-- better indenting if win.quickfix == 1 then
keymap.set('v', '<', '<gv', { noremap = true, silent = true }) vim.cmd("cclose")
keymap.set('v', '>', '>gv', { noremap = true, silent = true }) return
-- I hate escape end
keymap.set('i', 'jk', '<ESC>', { noremap = true, silent = true }) end
keymap.set('i', 'kj', '<ESC>', { noremap = true, silent = true }) vim.cmd("copen")
keymap.set('i', 'jj', '<ESC>', { noremap = true, silent = true }) end, { noremap = true, silent = true, desc = "Toggle Quickfix" })
-- Tab switch buffer
keymap.set('n', '<TAB>', ':BufferNext<CR>', { noremap = true, silent = true })
keymap.set('n', '<S-TAB>', ':BufferPrevious<CR>', { noremap = true, silent = true })
-- Move selected line / block of text in visual mode
keymap.set('x', 'K', ':move \'<-2<CR>gv-gv', { noremap = true, silent = true })
keymap.set('x', 'J', ':move \'>+1<CR>gv-gv', { noremap = true, silent = true })
-- Two spaces → live_grep
keymap.set("n", " ", function()
require("telescope.builtin").live_grep()
end, { noremap = true, silent = true, desc = "Search in Files" })
-- Misc
keymap.set("n", "Y", "y$", {})
keymap.set("v", "<", "<gv", { noremap = true, silent = true })
keymap.set("v", ">", ">gv", { noremap = true, silent = true })
keymap.set("i", "jk", "<ESC>", { noremap = true, silent = true })
keymap.set("i", "kj", "<ESC>", { noremap = true, silent = true })
keymap.set("i", "jj", "<ESC>", { noremap = true, silent = true })
-- Tab switch buffer (barbar)
keymap.set("n", "<TAB>", "<cmd>BufferNext<CR>", { noremap = true, silent = true })
keymap.set("n", "<S-TAB>", "<cmd>BufferPrevious<CR>", { noremap = true, silent = true })
-- Move selected line / block in visual mode
keymap.set("x", "K", ":move '<-2<CR>gv-gv", { noremap = true, silent = true })
keymap.set("x", "J", ":move '>+1<CR>gv-gv", { noremap = true, silent = true })
+6 -8
View File
@@ -1,5 +1,5 @@
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then if not vim.uv.fs_stat(lazypath) then
-- bootstrap lazy.nvim -- bootstrap lazy.nvim
-- stylua: ignore -- stylua: ignore
vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath }) vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath })
@@ -9,17 +9,15 @@ vim.opt.rtp:prepend(vim.env.LAZY or lazypath)
require("lazy").setup({ require("lazy").setup({
spec = { spec = {
-- add LazyVim and import its plugins -- add LazyVim and import its plugins
-- LazyVim will automatically load extras from lazyvim.json
{ "LazyVim/LazyVim", import = "lazyvim.plugins" }, { "LazyVim/LazyVim", import = "lazyvim.plugins" },
-- import any extras modules here
{ import = "lazyvim.plugins.extras.lang.typescript" },
{ import = "lazyvim.plugins.extras.lang.json" },
{ import = "lazyvim.plugins.extras.lang.go" },
{ import = "lazyvim.plugins.extras.dap.core" },
{ import = "lazyvim.plugins.extras.formatting.prettier" },
-- { import = "lazyvim.plugins.extras.ui.mini-animate" },
-- import/override with your plugins -- import/override with your plugins
{ import = "plugins" }, { import = "plugins" },
}, },
-- 本机未装 luarocks 时避免 Lazy 健康检查报 ERROR;需要 rocks 依赖的插件时再打开
rocks = {
enabled = false,
},
defaults = { defaults = {
-- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup. -- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup.
-- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default. -- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default.
+18 -28
View File
@@ -1,62 +1,52 @@
vim.g.autoformat = true vim.g.autoformat = true
vim.cmd('set iskeyword+=-') -- treat dash separated words as a word text object" -- 关闭不常用的远程宿主,减少 :checkhealth 里无意义的 WARNING
vim.cmd('set shortmess+=c') -- Don't pass messages to |ins-completion-menu|. vim.g.loaded_perl_provider = 0
vim.cmd('set inccommand=split') -- Make substitution work in realtime vim.g.loaded_ruby_provider = 0
-- 明确指向已安装 pynvim 的解释器
vim.g.python3_host_prog = "/usr/bin/python3"
vim.cmd("set iskeyword+=-") -- treat dash separated words as a word text object
vim.cmd("set shortmess+=c") -- Don't pass messages to |ins-completion-menu|.
vim.cmd("set inccommand=split") -- Make substitution work in realtime
vim.opt.hidden = true -- Required to keep multiple buffers open multiple buffers vim.opt.hidden = true -- Required to keep multiple buffers open multiple buffers
vim.opt.title = true vim.opt.title = true
TERMINAL = vim.fn.expand('$TERMINAL') TERMINAL = vim.fn.expand("$TERMINAL")
vim.cmd('let &titleold="'..TERMINAL..'"') vim.cmd('let &titleold="' .. TERMINAL .. '"')
vim.opt.titlestring="%<%F%=%l/%L - nvim" vim.opt.titlestring = "%<%F%=%l/%L - nvim"
vim.wo.wrap = true -- Display long lines as just one line vim.wo.wrap = true -- Display long lines as just one line
vim.cmd('set whichwrap+=<,>,[,],h,l') -- move to next line with theses keys vim.cmd("set whichwrap+=<,>,[,],h,l") -- move to next line with theses keys
vim.cmd('syntax on') -- syntax highlighting
vim.opt.pumheight = 10 -- Makes popup menu smaller vim.opt.pumheight = 10 -- Makes popup menu smaller
vim.opt.fileencoding = "utf-8" -- The encoding written to file vim.opt.fileencoding = "utf-8" -- The encoding written to file
vim.opt.cmdheight = 2 -- More space for displaying messages vim.opt.cmdheight = 2 -- More space for displaying messages
vim.cmd('set colorcolumn=99999') -- fix indentline for now
vim.opt.mouse = "a" -- Enable your mouse vim.opt.mouse = "a" -- Enable your mouse
vim.opt.splitbelow = true -- Horizontal splits will automatically be below vim.opt.splitbelow = true -- Horizontal splits will automatically be below
vim.opt.termguicolors = true -- set term gui colors most terminals support this vim.opt.termguicolors = true -- set term gui colors most terminals support this
vim.opt.splitright = true -- Vertical splits will automatically be to the right vim.opt.splitright = true -- Vertical splits will automatically be to the right
-- vim.opt.t_Co = "256" -- Support 256 colors
vim.opt.conceallevel = 0 -- So that I can see `` in markdown files vim.opt.conceallevel = 0 -- So that I can see `` in markdown files
vim.o.tabstop = 4 vim.o.tabstop = 4
vim.opt.shiftwidth = 4 vim.opt.shiftwidth = 4
vim.opt.expandtab = true vim.opt.expandtab = true
vim.bo.smartindent = true -- Makes indenting smart vim.opt.smartindent = true -- Makes indenting smart
vim.wo.number = true -- set numbered lines vim.wo.number = true -- set numbered lines
vim.wo.relativenumber = true -- set relative number vim.wo.relativenumber = true -- set relative number
vim.wo.cursorline = true -- Enable highlighting of the current line vim.wo.cursorline = true -- Enable highlighting of the current line
vim.opt.showtabline = 2 -- Always show tabs vim.opt.showtabline = 2 -- Always show tabs
vim.opt.showmode = false -- We don't need to see things like -- INSERT -- anymore vim.opt.showmode = false -- We don't need to see things like -- INSERT -- anymore
vim.opt.backup = false -- This is recommended by coc vim.opt.backup = false
vim.opt.writebackup = false -- This is recommended by coc vim.opt.writebackup = false
vim.wo.signcolumn = "yes" -- Always show the signcolumn, otherwise it would shift the text each time vim.wo.signcolumn = "yes" -- Always show the signcolumn, otherwise it would shift the text each time
vim.opt.updatetime = 300 -- Faster completion vim.opt.updatetime = 300 -- Faster completion
vim.opt.timeoutlen = 100 -- By default timeoutlen is 1000 ms vim.opt.timeoutlen = 500 -- By default timeoutlen is 1000 ms
vim.opt.clipboard = "unnamedplus" -- Copy paste between vim and everything else vim.opt.clipboard = "unnamedplus" -- Copy paste between vim and everything else
vim.cmd('filetype plugin on') -- filetype detection
-- vim.opt.guifont = "JetBrainsMono\\ Nerd\\ Font\\ Mono:h18"
-- vim.opt.guifont = "Hack\\ Nerd\\ Font\\ Mono"
-- vim.opt.guifont = "SauceCodePro Nerd Font:h17"
vim.opt.guifont = "FiraCode Nerd Font:h17" vim.opt.guifont = "FiraCode Nerd Font:h17"
-- vim.opt.guifont = "JetBrains\\ Mono\\ Regular\\ Nerd\\ Font\\ Complete"
vim.g.vim_markdown_folding_disabled = 1 vim.g.vim_markdown_folding_disabled = 1
vim.g.vimspector_enable_mappings = 'HUMAN'
vim.g['test#go#rspec#options'] = { nearest= '--v', suite= '--v' }
-- git blame -- git blame
vim.cmd('highlight default link gitblame SpecialComment') vim.cmd("highlight default link gitblame SpecialComment")
vim.g.gitblame_enabled = 0 vim.g.gitblame_enabled = 0
-- last position jump
vim.cmd([[
autocmd BufReadPost * if line("'\"") >= 1 && line("'\"") <= line("$") | exe "normal! g`\"" | endif
]])
-- vim.cmd('let g:nvcode_termcolors=256') -- vim.cmd('let g:nvcode_termcolors=256')
-- --local cc = 'gruvbox' -- --local cc = 'gruvbox'
-- local cc = 'lunar' -- local cc = 'lunar'
+87
View File
@@ -0,0 +1,87 @@
return {
{
"yetone/avante.nvim",
enabled = false, -- 临时禁用 avante
opts = function(_, opts)
-- 强制使用 Gemini CLI 的 ACP (Agent Client Protocol)
-- 注意:必须明确设置,覆盖 LazyVim 的默认配置
opts.provider = "gemini-cli"
opts.auto_suggestions_provider = "gemini-cli"
-- 清除可能存在的 claude 配置(如果 LazyVim 设置了的话)
if opts.claude then
opts.claude = nil
end
-- 配置 ACP providers
-- 使用网页登录(OAuth)方式,不需要 API Key
--
-- 使用步骤:
-- 1. 首次使用前,在终端运行: gemini auth login
-- 2. 这会打开浏览器,完成 Google 账号登录
-- 3. 登录凭证会被缓存到本地(通常在 ~/.gemini 目录)
-- 4. 之后 avante 会自动使用缓存的凭证,无需 API Key
--
-- 注意:如果环境变量中已设置了 GEMINI_API_KEY,Gemini CLI 可能会优先使用它
-- 如果想强制使用网页登录,请临时取消设置该环境变量:
-- unset GEMINI_API_KEY (bash/zsh)
-- 或 set -e GEMINI_API_KEY (fish)
opts.acp_providers = opts.acp_providers or {}
opts.acp_providers["gemini-cli"] = {
command = "gemini",
args = { "--experimental-acp" },
env = {
NODE_NO_WARNINGS = "1",
-- 不设置 GEMINI_API_KEY,让 Gemini CLI 使用已缓存的 OAuth 凭证
-- 如果必须使用 API Key,可以取消下面的注释:
-- GEMINI_API_KEY = os.getenv("GEMINI_API_KEY"),
-- 代理配置(如果需要通过代理访问)
-- 从环境变量读取代理设置,如果没有设置则使用系统默认
HTTP_PROXY = os.getenv("HTTP_PROXY") or os.getenv("http_proxy"),
HTTPS_PROXY = os.getenv("HTTPS_PROXY") or os.getenv("https_proxy"),
ALL_PROXY = os.getenv("ALL_PROXY") or os.getenv("all_proxy"),
NO_PROXY = os.getenv("NO_PROXY") or os.getenv("no_proxy"),
-- 如果需要手动指定代理,可以取消下面的注释并修改为你的代理地址:
-- HTTP_PROXY = "http://127.0.0.1:7890",
-- HTTPS_PROXY = "http://127.0.0.1:7890",
-- 或者使用 SOCKS5 代理:
-- ALL_PROXY = "socks5://127.0.0.1:7890",
},
-- 不设置 auth_method,让 CLI 自动使用已缓存的 OAuth 凭证
}
-- 确保 providers 表中没有 claude 的配置
opts.providers = opts.providers or {}
if opts.providers.claude then
opts.providers.claude = nil
end
-- 可选:配置其他 Gemini provider 设置(用于非 ACP 模式)
opts.providers.gemini = opts.providers.gemini or {
-- 如果将来需要使用 REST API 模式,可以在这里配置
-- api_key = os.getenv("GEMINI_API_KEY"),
}
-- 调试:打印当前配置的 provider(可选,用于验证)
-- vim.notify("Avante provider set to: " .. opts.provider, vim.log.levels.INFO)
return opts
end,
-- LazyVim 会自动调用 setup,这里不需要再次调用
-- 但如果需要验证,可以取消下面的注释
-- config = function(_, opts)
-- vim.defer_fn(function()
-- local avante = require("avante")
-- if avante and avante.config then
-- local current_provider = avante.config.provider or "unknown"
-- vim.notify("Avante provider: " .. current_provider, vim.log.levels.INFO)
-- end
-- end, 1000)
-- end,
-- 确保在 LazyVim 的配置之后加载
priority = 1000,
},
}
+1
View File
@@ -1,4 +1,5 @@
return { return {
{ "akinsho/bufferline.nvim", enabled = false },
{ {
-- tabline -- tabline
'romgrk/barbar.nvim', 'romgrk/barbar.nvim',
+59
View File
@@ -0,0 +1,59 @@
return {
{
"olimorris/codecompanion.nvim",
enabled = false, -- 临时禁用 CodeCompanion
dependencies = {
"nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter",
},
keys = {
{ "<leader>a", nil, desc = "CodeCompanion" },
{ "<leader>ac", "<cmd>CodeCompanionChat<cr>", desc = "CodeCompanion Chat" },
{ "<leader>ai", "<cmd>CodeCompanionInline<cr>", desc = "CodeCompanion Inline" },
{ "<leader>am", "<cmd>CodeCompanionCmd<cr>", desc = "CodeCompanion Cmd" },
{ "<leader>at", "<cmd>CodeCompanionToggle<cr>", desc = "CodeCompanion Toggle" },
},
opts = {
-- 配置策略,使用 gemini_cli adapter
strategies = {
chat = {
adapter = "gemini_cli", -- chat 模式使用 gemini_cli
},
inline = {
adapter = "gemini_cli", -- inline 模式使用 gemini_cli
},
cmd = {
adapter = "gemini_cli", -- cmd 模式使用 gemini_cli
},
},
-- 配置 adapters
adapters = {
acp = {
gemini_cli = function()
return require("codecompanion.adapters").extend("gemini_cli", {
-- 使用 OAuth 登录方式,不使用 API key
defaults = {
auth_method = "oauth", -- 使用 OAuth 网页登录
timeout = 20000,
},
-- 不设置 GEMINI_API_KEY,强制使用 OAuth 登录
env = {
-- 不设置 GEMINI_API_KEY,让 Gemini CLI 使用已缓存的 OAuth 凭证
-- 代理配置(如果需要通过代理访问)
HTTP_PROXY = os.getenv("HTTP_PROXY") or os.getenv("http_proxy"),
HTTPS_PROXY = os.getenv("HTTPS_PROXY") or os.getenv("https_proxy"),
ALL_PROXY = os.getenv("ALL_PROXY") or os.getenv("all_proxy"),
NO_PROXY = os.getenv("NO_PROXY") or os.getenv("no_proxy"),
},
-- Gemini CLI 命令配置
commands = {
default = { "gemini", "cli", "--experimental-acp" },
},
})
end,
},
},
},
},
}
+8 -4
View File
@@ -4,8 +4,12 @@ return {
"stevearc/conform.nvim", "stevearc/conform.nvim",
opts = { opts = {
formatters_by_ft = { formatters_by_ft = {
go = { "goimports"}, javascript = { "prettierd", "prettier" },
} javascriptreact = { "prettierd", "prettier" },
} typescript = { "prettierd", "prettier" },
} typescriptreact = { "prettierd", "prettier" },
go = { "goimports", "gofumpt" },
},
},
},
} }
+3
View File
@@ -3,6 +3,9 @@ return {
"nvimdev/dashboard-nvim", "nvimdev/dashboard-nvim",
event = "VimEnter", event = "VimEnter",
opts = function(_, opts) opts = function(_, opts)
-- 确保 opts.config 存在,避免 nil 错误
opts.config = opts.config or {}
local logo = [[ local logo = [[
███╗ ██╗███████╗ ██████╗ ██╗ ██╗██╗███╗ ███╗ ███╗ ██╗███████╗ ██████╗ ██╗ ██╗██╗███╗ ███╗
+3
View File
@@ -0,0 +1,3 @@
return {
"sindrets/diffview.nvim",
}
+21
View File
@@ -0,0 +1,21 @@
return {
{
"ibhagwan/fzf-lua",
dependencies = {
"nvim-tree/nvim-web-devicons",
},
keys = {
-- 如果需要使用 fzf-lua 的快捷键,可以在这里添加
},
config = function()
require("fzf-lua").setup({
-- fzf-lua 的配置
winopts = {
height = 0.85,
width = 0.80,
},
})
end,
},
}
+40
View File
@@ -0,0 +1,40 @@
return {
{
"marcinjahn/gemini-cli.nvim",
enabled = false, -- 临时禁用 gemini-cli 插件
cmd = "Gemini", -- 懒加载,使用 :Gemini 命令时加载
dependencies = {
"folke/snacks.nvim", -- 必需的依赖
},
keys = {
{ "<leader>a", nil, desc = "Gemini CLI" },
{ "<leader>aq", "<cmd>Gemini ask<cr>", desc = "Ask Gemini" },
{ "<leader>ac", "<cmd>Gemini toggle<cr>", desc = "Toggle Gemini CLI" },
{ "<leader>af", "<cmd>Gemini add_file<cr>", desc = "Add File to Gemini" },
{ "<leader>ar", "<cmd>Gemini --resume<cr>", desc = "Resume Gemini" },
},
config = function()
require("gemini_cli").setup({
-- Gemini CLI 命令
gemini_cmd = "gemini",
-- 传递给 gemini 命令的参数
args = {},
-- 自动重新加载
auto_reload = false,
-- 选择器配置
picker_cfg = {
preset = "vscode",
},
-- 窗口配置
win = {
wo = { winbar = "GeminiCLI" },
style = "gemini_cli",
position = "right", -- 窗口位置:right, left, top, bottom
},
-- 代理配置(如果需要)
-- 代理会从环境变量 HTTP_PROXY, HTTPS_PROXY, ALL_PROXY 自动读取
})
end,
},
}
+26 -17
View File
@@ -3,26 +3,34 @@ return {
"lewis6991/gitsigns.nvim", "lewis6991/gitsigns.nvim",
opts = { opts = {
signs = { signs = {
-- TODO add hl to colorscheme add = { text = '┃' },
add = {hl = 'GitSignsAdd' , text = '▎', numhl='GitSignsAddNr' , linehl='GitSignsAddLn'}, change = { text = '┃' },
change = {hl = 'GitSignsChange', text = '▎', numhl='GitSignsChangeNr', linehl='GitSignsChangeLn'}, delete = { text = '_' },
delete = {hl = 'GitSignsDelete', text = '契', numhl='GitSignsDeleteNr', linehl='GitSignsDeleteLn'}, topdelete = { text = '‾' },
topdelete = {hl = 'GitSignsDelete', text = '契', numhl='GitSignsDeleteNr', linehl='GitSignsDeleteLn'}, changedelete = { text = '~' },
changedelete = {hl = 'GitSignsChange', text = '▎', numhl='GitSignsChangeNr', linehl='GitSignsChangeLn'}, untracked = { text = '┆' },
}, },
numhl = false, signs_staged = {
linehl = false, add = { text = '┃' },
watch_gitdir = { change = { text = '┃' },
interval = 1000 delete = { text = '_' },
topdelete = { text = '‾' },
changedelete = { text = '~' },
untracked = { text = '┆' },
}, },
sign_priority = 6, numhl = false,
update_debounce = 200, linehl = false,
status_formatter = nil, -- Use default watch_gitdir = {
interval = 1000,
},
sign_priority = 6,
update_debounce = 200,
status_formatter = nil, -- Use default
on_attach = function(buffer) on_attach = function(buffer)
local gs = package.loaded.gitsigns local gs = package.loaded.gitsigns
local function map(mode, l, r, desc) local function map(mode, l, r, desc)
vim.keymap.set(mode, l, r, { buffer = buffer, desc = desc }) vim.keymap.set(mode, l, r, { buffer = buffer, desc = desc })
end end
-- stylua: ignore start -- stylua: ignore start
@@ -38,7 +46,8 @@ return {
map("n", "<leader>ghd", gs.diffthis, "Diff This") map("n", "<leader>ghd", gs.diffthis, "Diff This")
map("n", "<leader>ghD", function() gs.diffthis("~") end, "Diff This ~") map("n", "<leader>ghD", function() gs.diffthis("~") end, "Diff This ~")
map({ "o", "x" }, "ih", ":<C-U>Gitsigns select_hunk<CR>", "GitSigns Select Hunk") map({ "o", "x" }, "ih", ":<C-U>Gitsigns select_hunk<CR>", "GitSigns Select Hunk")
end, end,
} },
} },
} }
+72
View File
@@ -0,0 +1,72 @@
return {
-- Override LazyVim's default LSP keymaps
{
"neovim/nvim-lspconfig",
keys = {
-- Delete LazyVim's default gd mapping if it exists
{ "gd", false },
-- Add our custom gd mapping with higher priority
{
"gd",
function()
vim.lsp.buf.definition()
end,
desc = "Goto Definition",
noremap = true,
silent = true,
},
-- Delete and re-add other LSP mappings to ensure they work
{ "gD", false },
{
"gD",
function()
vim.lsp.buf.declaration()
end,
desc = "Goto Declaration",
noremap = true,
silent = true,
},
{ "gi", false },
{
"gi",
function()
vim.lsp.buf.implementation()
end,
desc = "Goto Implementation",
noremap = true,
silent = true,
},
{ "K", false },
{
"K",
function()
vim.lsp.buf.hover()
end,
desc = "Hover Documentation",
noremap = true,
silent = true,
},
{ "gt", false },
{
"gt",
function()
vim.lsp.buf.type_definition()
end,
desc = "Goto Type Definition",
noremap = true,
silent = true,
},
{ "gr", false },
{
"gr",
function()
vim.lsp.buf.references()
end,
desc = "References",
noremap = true,
silent = true,
},
},
},
}
+14 -4
View File
@@ -1,16 +1,26 @@
return { return {
{ {
"williamboman/mason.nvim", "mason-org/mason.nvim",
opts = function(_, opts) opts = function(_, opts)
vim.list_extend(opts.ensure_installed, { vim.list_extend(opts.ensure_installed, {
"stylua", "stylua",
"selene", "selene",
"luacheck", "luacheck",
"shellcheck",
"shfmt", "shfmt",
"tailwindcss-language-server", "pylyzer",
"buf", -- Protocol Buffers LSP
-- TypeScript/JavaScript
"typescript-language-server", "typescript-language-server",
"css-lsp", "eslint-lsp",
"prettierd",
-- Go
"gopls",
"goimports",
"gofumpt",
"golangci-lint",
"delve",
}) })
end, end,
}, },
+20 -18
View File
@@ -1,22 +1,24 @@
return { return {
{ "nvim-neotest/neotest-plenary" },
{ {
"nvim-neotest/neotest", "nvim-neotest/neotest",
dependencies= { dependencies = {
"nvim-lua/plenary.nvim", "nvim-neotest/nvim-nio",
"antoinemadec/FixCursorHold.nvim", "nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter", "antoinemadec/FixCursorHold.nvim",
"nvim-neotest/neotest-go", "nvim-treesitter/nvim-treesitter",
}, "fredrikaverpil/neotest-golang", -- Installation
opts = { },
adapters = { config = function()
require("neotest-go")({ require("neotest").setup({
experimental = { adapters = {
test_table = true, require("neotest-golang"), -- Registration
}, },
args = { "-gcflags=all=-l", "-count=1", "-timeout=60s" } output = {
enabled = true,
open_on_run = true,
},
}) })
} end,
},
}, },
} }
+1 -1
View File
@@ -76,7 +76,7 @@ end
return { return {
{ {
"hrsh7th/nvim-cmp", "hrsh7th/nvim-cmp",
enable = false, enabled = false,
dependencies = { dependencies = {
"hrsh7th/cmp-emoji", "hrsh7th/cmp-emoji",
'hrsh7th/vim-vsnip', 'hrsh7th/vim-vsnip',
+1 -1
View File
@@ -1,7 +1,7 @@
return { return {
"leoluz/nvim-dap-go", "leoluz/nvim-dap-go",
keys = { keys = {
{ "<F5>", function() require("dap").continue({ before = get_args }) end, desc = "Run with Args" }, { "<F5>", function() require("dap").continue() end, desc = "Run/Continue" },
{ "<F6>",":lua require('dap-go').debug_test()<cr>", desc = "Debug Test" }, { "<F6>",":lua require('dap-go').debug_test()<cr>", desc = "Debug Test" },
{ "<F9>", function() require("dap").toggle_breakpoint() end, desc = "Toggle Breakpoint" }, { "<F9>", function() require("dap").toggle_breakpoint() end, desc = "Toggle Breakpoint" },
{ "<F10>", function() require("dap").step_over() end, desc = "Step Over" }, { "<F10>", function() require("dap").step_over() end, desc = "Step Over" },
+34 -28
View File
@@ -1,21 +1,36 @@
return { return {
-- lsp servers
{ {
"neovim/nvim-lspconfig", "neovim/nvim-lspconfig",
event = { 'BufReadPre', 'BufReadPost', 'BufNewFile' },
opts = { opts = {
inlay_hints = { enabled = false }, inlay_hints = { enabled = false },
---@type lspconfig.options
servers = { servers = {
buf_ls = {},
cssls = {}, cssls = {},
tailwindcss = { tailwindcss = {
root_dir = function(...) root_dir = function(...)
return require("lspconfig.util").root_pattern('tailwind.config.js', 'tailwind.config.cjs', 'tailwind.config.mjs', 'tailwind.config.ts', 'postcss.config.js', 'postcss.config.cjs', 'postcss.config.mjs', 'postcss.config.ts', 'package.json', 'node_modules', '.git')(...) return require("lspconfig.util").root_pattern(
"tailwind.config.js",
"tailwind.config.cjs",
"tailwind.config.mjs",
"tailwind.config.ts",
"postcss.config.js",
"postcss.config.cjs",
"postcss.config.mjs",
"postcss.config.ts",
"package.json",
"node_modules",
".git"
)(...)
end, end,
}, },
tsserver = { ts_ls = {
root_dir = function(...) root_dir = function(...)
return require("lspconfig.util").root_pattern("tsconfig.json", "package.json", "jsconfig.json", ".git")(...) return require("lspconfig.util").root_pattern(
"tsconfig.json",
"package.json",
"jsconfig.json",
".git"
)(...)
end, end,
single_file_support = false, single_file_support = false,
settings = { settings = {
@@ -52,7 +67,6 @@ return {
}, },
}, },
lua_ls = { lua_ls = {
-- enabled = false,
single_file_support = true, single_file_support = true,
settings = { settings = {
Lua = { Lua = {
@@ -63,11 +77,6 @@ return {
workspaceWord = true, workspaceWord = true,
callSnippet = "Both", callSnippet = "Both",
}, },
misc = {
parameters = {
-- "--log-level=trace",
},
},
hint = { hint = {
enable = true, enable = true,
setType = false, setType = false,
@@ -84,7 +93,6 @@ return {
}, },
diagnostics = { diagnostics = {
disable = { "incomplete-signature-doc", "trailing-space" }, disable = { "incomplete-signature-doc", "trailing-space" },
-- enable = false,
groupSeverity = { groupSeverity = {
strong = "Warning", strong = "Warning",
strict = "Warning", strict = "Warning",
@@ -117,33 +125,31 @@ return {
}, },
}, },
gopls = { gopls = {
cmd = { "gopls", "serve" }, -- use cmd in path, I can update it easily cmd = { "gopls", "serve" },
settings = { settings = {
gopls = { gopls = {
analyses = { analyses = {
nilness = true, nilness = true,
unusedparams = true, unusedparams = true,
unusedwrite = true, unusedwrite = true,
useany = true, useany = true,
},
staticcheck = false,
usePlaceholders = false,
}, },
staticcheck = false,
usePlaceholders = false,
}
}, },
}, },
pylsp = { pylyzer = {
cmd = { "pylyzer", "--server" },
filetypes = { "python" },
settings = { settings = {
python = { python = {
checkOnType = false, checkOnType = false,
diagnostics = false, diagnostics = false,
inlayHints = true, inlayHints = true,
smartCompletion = true smartCompletion = true,
} },
}, },
single_file_support = true, single_file_support = true,
} },
}, },
setup = {}, setup = {},
}, },
+26 -25
View File
@@ -1,38 +1,38 @@
local function my_on_attach(bufnr) local function my_on_attach(bufnr)
local api = require "nvim-tree.api" local api = require("nvim-tree.api")
local function opts(desc) local function opts(desc)
return { desc = "nvim-tree: " .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true } return { desc = "nvim-tree: " .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true }
end end
-- default mappings -- default mappings
api.config.mappings.default_on_attach(bufnr) api.config.mappings.default_on_attach(bufnr)
-- custom mappings -- custom mappings
vim.keymap.set('n', '<C-t>', api.tree.change_root_to_parent, opts('Up')) vim.keymap.set("n", "<C-t>", api.tree.change_root_to_parent, opts("Up"))
vim.keymap.set('n', '?', api.tree.toggle_help, opts('Help')) vim.keymap.set("n", "?", api.tree.toggle_help, opts("Help"))
vim.keymap.set('n', 'l', api.node.open.edit, opts('Edit')) vim.keymap.set("n", "l", api.node.open.edit, opts("Edit"))
vim.keymap.set('n', 'h', api.node.navigate.parent_close, opts('Parent Close')) vim.keymap.set("n", "h", api.node.navigate.parent_close, opts("Parent Close"))
vim.keymap.set('n', 's', api.node.open.horizontal, opts('Horizontal Split')) vim.keymap.set("n", "s", api.node.open.horizontal, opts("Horizontal Split"))
vim.keymap.set('n', 'v', api.node.open.vertical, opts('Vertical Split')) vim.keymap.set("n", "v", api.node.open.vertical, opts("Vertical Split"))
vim.keymap.set("n", "<S-r>", api.tree.reload, opts("Reload"))
end end
vim.g.nvim_tree_indent_markers = 1 -- "0 by default, this option shows indent markers when folders are open vim.g.nvim_tree_indent_markers = 1 -- "0 by default, this option shows indent markers when folders are open
vim.g.nvim_tree_auto_ignore_ft = 'startify' --empty by default, don't auto open tree on specific filetypes. vim.g.nvim_tree_auto_ignore_ft = "startify" --empty by default, don't auto open tree on specific filetypes.
vim.g.nvim_tree_icons = { vim.g.nvim_tree_icons = {
default = '', default = "",
symlink = '', symlink = "",
git = {unstaged = "", staged = "✓", unmerged = "", renamed = "➜", untracked = ""}, git = { unstaged = "", staged = "✓", unmerged = "", renamed = "➜", untracked = "" },
folder = {default = "", open = "", empty = "", empty_open = "", symlink = ""} folder = { default = "", open = "", empty = "", empty_open = "", symlink = "" },
} }
return { return {
{ {
'nvim-tree/nvim-tree.lua', "nvim-tree/nvim-tree.lua",
dependencies = { dependencies = {
'nvim-tree/nvim-web-devicons', -- optional "nvim-tree/nvim-web-devicons", -- optional
}, },
opts = { opts = {
on_attach = my_on_attach, on_attach = my_on_attach,
@@ -41,7 +41,7 @@ return {
--auto_close = false, --auto_close = false,
filters = { filters = {
dotfiles = false, dotfiles = false,
custom = {} custom = {},
}, },
git = { git = {
enable = true, enable = true,
@@ -50,14 +50,15 @@ return {
}, },
update_focused_file = { update_focused_file = {
-- enables the feature -- enables the feature
enable = true, enable = true,
-- update the root directory of the tree to the one of the folder containing the file if the file is not under the current root directory -- update the root directory of the tree to the one of the folder containing the file if the file is not under the current root directory
-- only relevant when `update_focused_file.enable` is true -- only relevant when `update_focused_file.enable` is true
update_cwd = false, update_cwd = false,
-- list of buffer names / filetypes that will not update the cwd if the file isn't found under the current root directory -- list of buffer names / filetypes that will not update the cwd if the file isn't found under the current root directory
-- only relevant when `update_focused_file.update_cwd` is true and `update_focused_file.enable` is true -- only relevant when `update_focused_file.update_cwd` is true and `update_focused_file.enable` is true
ignore_list = {} ignore_list = {},
}, },
}, },
}, },
} }
+12
View File
@@ -0,0 +1,12 @@
return {
-- Protocol Buffers 支持通过以下方式提供:
-- 1. 语法高亮:通过 treesitter(需要在 treesitter.lua 中添加 "proto")
-- 2. LSP 支持:通过 bufls(已在 nvim-lspconfig.lua 和 mason.lua 中配置)
--
-- 如果需要额外的语法高亮插件,可以使用:
-- {
-- "protocolbuffers/protobuf",
-- ft = { "proto" },
-- },
}
+16
View File
@@ -0,0 +1,16 @@
return {
{
"MeanderingProgrammer/render-markdown.nvim",
dependencies = {
"nvim-treesitter/nvim-treesitter",
"nvim-tree/nvim-web-devicons",
},
ft = { "markdown", "mdx", "quarto", "rmd", "org" },
---@module 'render-markdown'
---@type render.md.UserConfig
opts = {
-- 未安装 tectonic/pdflatex 时关闭 LaTeX 公式渲染,减少健康检查噪音
latex = { enabled = false },
},
},
}
+103
View File
@@ -0,0 +1,103 @@
return {
"folke/sidekick.nvim",
enabled = true,
opts = {
cli = {
win = {
layout = "right",
split = {
width = 0,
height = 20,
},
config = function(terminal)
terminal.opts.split.width = math.floor(vim.o.columns * 0.6)
end,
keys = {
buffers = false,
},
},
mux = {
backend = vim.env.ZELLIJ and "zellij" or "tmux",
enabled = true,
},
},
},
keys = {
{
"<C-\\>",
function()
require("sidekick.cli").toggle()
end,
mode = { "n", "i", "t" },
desc = "Sidekick Toggle",
},
{
"<leader>ao",
function()
require("sidekick.cli").toggle({ focus = true })
end,
desc = "Sidekick Open",
},
{
"<leader>ax",
function()
require("sidekick.cli").hide()
end,
desc = "Sidekick Close",
},
{
"<leader>aa",
function()
require("sidekick.cli").toggle()
end,
desc = "Sidekick Toggle",
},
{
"<leader>as",
function()
require("sidekick.cli").select()
end,
-- Or to select only installed tools:
-- require("sidekick.cli").select({ filter = { installed = true } })
desc = "Select CLI",
},
{
"<leader>ad",
function()
require("sidekick.cli").close()
end,
desc = "Detach a CLI Session",
},
{
"<leader>at",
function()
require("sidekick.cli").send({ msg = "{this}" })
end,
mode = { "x", "n" },
desc = "Send This",
},
{
"<leader>af",
function()
require("sidekick.cli").send({ msg = "{file}" })
end,
desc = "Send File",
},
{
"<leader>av",
function()
require("sidekick.cli").send({ msg = "{selection}" })
end,
mode = { "x" },
desc = "Send Visual Selection",
},
{
"<leader>ap",
function()
require("sidekick.cli").prompt()
end,
mode = { "n", "x" },
desc = "Sidekick Select Prompt",
},
},
}
+13
View File
@@ -0,0 +1,13 @@
return {
{
"folke/snacks.nvim",
opts = {
-- LazyVim 仍依赖 snacks 核心(通知、dashboard 等);关闭 picker,统一用 Telescope。
picker = { enabled = false },
image = {
-- tmux / 部分终端不报 kitty graphics;避免 :checkhealth 里出现 ERROR(仍会 WARN)
force = true,
},
},
},
}
+2
View File
@@ -5,6 +5,8 @@ return {
cmd = "SymbolsOutline", cmd = "SymbolsOutline",
opts = { opts = {
position = "right", position = "right",
width = 35,
}, },
}, },
} }
+52 -13
View File
@@ -1,10 +1,16 @@
return { return {
{ {
"telescope.nvim", "telescope.nvim",
-- 未启用 `editor.telescope` extra 时 Lazy 不会注册 `:Telescope`,自定义 `<cmd>Telescope …` 键会失效。
cmd = { "Telescope" },
dependencies = { dependencies = {
{ {
"nvim-telescope/telescope-fzf-native.nvim", "nvim-telescope/telescope-fzf-native.nvim",
build = "make", build = "make",
-- 确保编译成功,如果 make 失败,尝试 cmake
cond = function()
return vim.fn.executable("make") == 1 or vim.fn.executable("cmake") == 1
end,
}, },
"nvim-telescope/telescope-file-browser.nvim", "nvim-telescope/telescope-file-browser.nvim",
}, },
@@ -115,32 +121,43 @@ return {
local telescope = require("telescope") local telescope = require("telescope")
local actions = require("telescope.actions") local actions = require("telescope.actions")
local fb_actions = require("telescope").extensions.file_browser.actions local fb_actions = require("telescope").extensions.file_browser.actions
local trouble = require("trouble.providers.telescope") local trouble = require("trouble.sources.telescope")
opts.defaults = vim.tbl_deep_extend("force", opts.defaults, { -- 确保 opts 和其子表存在
opts = opts or {}
opts.defaults = vim.tbl_deep_extend("force", opts.defaults or {}, {
wrap_results = true, wrap_results = true,
layout_strategy = "horizontal", layout_strategy = "horizontal",
layout_config = { prompt_position = "top" }, layout_config = { prompt_position = "top" },
sorting_strategy = "ascending", sorting_strategy = "ascending",
winblend = 0, winblend = 0,
-- 确保文件查找器正常工作
file_ignore_patterns = {
"^.git/",
"^node_modules/",
"^.DS_Store",
},
-- 使用 fzf 排序(如果可用)
path_display = { "truncate" },
dynamic_preview_title = true,
mappings = { mappings = {
i = { i = {
["<C-c>"] = actions.close, ["<C-c>"] = actions.close,
["<ESC>"] = actions.close, ["<ESC>"] = actions.close,
["<C-j>"] = actions.move_selection_next, ["<C-j>"] = actions.move_selection_next,
["<C-k>"] = actions.move_selection_previous, ["<C-k>"] = actions.move_selection_previous,
["<c-t>"] = trouble.open_with_trouble, ["<c-t>"] = trouble.open,
["<C-q>"] = actions.smart_send_to_qflist + actions.open_qflist, ["<C-q>"] = actions.smart_send_to_qflist + actions.open_qflist,
}, },
n = { n = {
["<C-j>"] = actions.move_selection_next, ["<C-j>"] = actions.move_selection_next,
["<C-k>"] = actions.move_selection_previous, ["<C-k>"] = actions.move_selection_previous,
["<c-t>"] = trouble.open_with_trouble, ["<c-t>"] = trouble.open,
["<C-q>"] = actions.smart_send_to_qflist + actions.open_qflist ["<C-q>"] = actions.smart_send_to_qflist + actions.open_qflist
}, },
}, },
}) })
opts.pickers = { opts.pickers = vim.tbl_deep_extend("force", opts.pickers or {}, {
diagnostics = { diagnostics = {
theme = "ivy", theme = "ivy",
initial_mode = "normal", initial_mode = "normal",
@@ -148,8 +165,24 @@ return {
preview_cutoff = 9999, preview_cutoff = 9999,
}, },
}, },
} })
opts.extensions = {
-- Configure live_grep: use ripgrep if available, otherwise fallback to grep
-- Note: Install ripgrep for better performance: brew install ripgrep
if vim.fn.executable("rg") == 0 then
vim.notify("ripgrep (rg) not found. live_grep will use grep (slower). Install with: brew install ripgrep", vim.log.levels.WARN)
opts.defaults = opts.defaults or {}
opts.defaults.vimgrep_arguments = {
"grep",
"--recursive",
"--no-heading",
"--with-filename",
"--line-number",
"--column",
"--smart-case",
}
end
opts.extensions = vim.tbl_deep_extend("force", opts.extensions or {}, {
file_browser = { file_browser = {
theme = "dropdown", theme = "dropdown",
-- disables netrw and use telescope-file-browser in its place -- disables netrw and use telescope-file-browser in its place
@@ -178,10 +211,16 @@ return {
}, },
}, },
}, },
} })
telescope.setup(opts) telescope.setup(opts)
require("telescope").load_extension("fzf")
require("telescope").load_extension("file_browser") -- 安全地加载扩展
pcall(function()
require("telescope").load_extension("fzf")
end)
pcall(function()
require("telescope").load_extension("file_browser")
end)
end, end,
}, },
} }
+34 -24
View File
@@ -4,28 +4,37 @@ return {
{ {
"nvim-treesitter/nvim-treesitter", "nvim-treesitter/nvim-treesitter",
opts = { opts = {
ensure_installed = { ensure_installed = {
"astro", "astro",
"cmake", "cmake",
"cpp", "cpp",
"css", "css",
"fish", "fish",
"gitignore", "gitignore",
"go", "go",
"graphql", "graphql",
"html", "html",
"java", "java",
"json", "javascript",
"lua", "json",
"php", "latex",
"rust", -- "lua", "vim", "vimdoc", "query", "markdown" 等由 Neovim 内置,
"scss", -- 不在此安装,避免 nvim-treesitter 装的新版 parser 与内置 query 不兼容。
"sql", "norg",
"svelte", "php",
"toml", "proto", -- Protocol Buffers
"tsx", "regex",
"yaml", "rust",
}, "scss",
"sql",
"svelte",
"toml",
"tsx",
"typescript",
"typst",
"vue",
"yaml",
},
-- matchup = { -- matchup = {
-- enable = true, -- enable = true,
@@ -57,8 +66,9 @@ return {
}, },
}, },
}, },
config = function(_, opts) config = function()
require("nvim-treesitter.configs").setup(opts) -- LazyVim 已经通过 opts 自动调用了 setup
-- 这里只做额外的配置
-- MDX -- MDX
vim.filetype.add({ vim.filetype.add({
+2 -2
View File
@@ -12,7 +12,7 @@ function M.get_loc()
end end
info = info or me info = info or me
local source = info.source:sub(2) local source = info.source:sub(2)
source = vim.loop.fs_realpath(source) or source source = vim.uv.fs_realpath(source) or source
return source .. ":" .. info.linedefined return source .. ":" .. info.linedefined
end end
@@ -47,7 +47,7 @@ function M.dump(...)
if vim.tbl_isempty(value) then if vim.tbl_isempty(value) then
value = nil value = nil
else else
value = vim.tbl_islist(value) and vim.tbl_count(value) <= 1 and value[1] or value value = vim.islist(value) and vim.tbl_count(value) <= 1 and value[1] or value
end end
M._dump(value) M._dump(value)
end end
+40 -200
View File
@@ -1,212 +1,52 @@
local lv_utils = {} local M = {}
function M.yank_filepath()
-- copy current filepath to clipboard local p = vim.fn.expand("%:p")
function lv_utils.yank_filepath() local line = vim.fn.line(".")
local p = vim.fn.expand('%:p') p = p .. ":" .. line
local line = vim.fn.line(".") print(p)
p = p..":"..line vim.fn.setreg("+", p)
print(p)
vim.fn.setreg('+',p)
end end
function lv_utils.yank_file_dir() function M.yank_file_dir()
local p = vim.fn.expand('%:p:h') local p = vim.fn.expand("%:p:h")
print(p) print(p)
vim.fn.setreg('+',p) vim.fn.setreg("+", p)
end end
function M.open_md()
function lv_utils.open_md() local p = vim.fn.expand("%:p")
local p = vim.fn.expand('%:p') vim.fn.system("open -a marktext " .. p)
vim.fn.system("open -a marktext "..p)
end end
function lv_utils.define_augroups(definitions) -- {{{1 function M.file_exists(name)
-- Create autocommand groups based on the passed definitions local f = io.open(name, "r")
-- if f ~= nil then
-- The key will be the name of the group, and each definition io.close(f)
-- within the group should have: return true
-- 1. Trigger end
-- 2. Pattern return false
-- 3. Text
-- just like how they would normally be defined from Vim itself
for group_name, definition in pairs(definitions) do
vim.cmd('augroup ' .. group_name)
vim.cmd('autocmd!')
for _, def in pairs(definition) do
local command = table.concat(vim.tbl_flatten {'autocmd', def}, ' ')
vim.cmd(command)
end
vim.cmd('augroup END')
end
end end
-- lsp --- 无写权限时用 sudo 保存当前文件(对应 :W)
function M.sudo_write()
local name = vim.api.nvim_buf_get_name(0)
if name == "" then
vim.notify("W: 当前 buffer 没有文件名", vim.log.levels.ERROR)
return
end
function lv_utils.add_to_workspace_folder() local ok, err = pcall(function()
vim.lsp.buf.add_workspace_folder() vim.cmd("write !sudo tee % > /dev/null")
vim.cmd("edit!")
end)
if not ok then
local msg = vim.split(tostring(err), "\n", { plain = true })[1]
vim.notify("W: 保存失败 — " .. msg, vim.log.levels.ERROR)
return
end
vim.notify("W: 已保存 " .. name, vim.log.levels.INFO)
end end
function lv_utils.clear_references() return M
vim.lsp.buf.clear_references()
end
function lv_utils.code_action()
vim.lsp.buf.code_action()
end
function lv_utils.declaration()
vim.lsp.buf.declaration()
vim.lsp.buf.clear_references()
end
function lv_utils.definition()
vim.lsp.buf.definition()
vim.lsp.buf.clear_references()
end
function lv_utils.document_highlight()
vim.lsp.buf.document_highlight()
end
function lv_utils.document_symbol()
vim.lsp.buf.document_symbol()
end
function lv_utils.formatting()
vim.lsp.buf.formatting()
end
function lv_utils.formatting_sync()
vim.lsp.buf.formatting_sync()
end
function lv_utils.hover()
vim.lsp.buf.hover()
end
function lv_utils.implementation()
vim.lsp.buf.implementation()
end
function lv_utils.incoming_calls()
vim.lsp.buf.incoming_calls()
end
function lv_utils.list_workspace_folders()
vim.lsp.buf.list_workspace_folders()
end
function lv_utils.outgoing_calls()
vim.lsp.buf.outgoing_calls()
end
function lv_utils.range_code_action()
vim.lsp.buf.range_code_action()
end
function lv_utils.range_formatting()
vim.lsp.buf.range_formatting()
end
function lv_utils.references()
vim.lsp.buf.references()
vim.lsp.buf.clear_references()
end
function lv_utils.remove_workspace_folder()
vim.lsp.buf.remove_workspace_folder()
end
function lv_utils.rename()
vim.lsp.buf.rename()
end
function lv_utils.signature_help()
vim.lsp.buf.signature_help()
end
function lv_utils.type_definition()
vim.lsp.buf.type_definition()
end
function lv_utils.workspace_symbol()
vim.lsp.buf.workspace_symbol()
end
-- diagnostic
function lv_utils.get_all()
vim.lsp.diagnostic.get_all()
end
function lv_utils.get_next()
vim.lsp.diagnostic.get_next()
end
function lv_utils.get_prev()
vim.lsp.diagnostic.get_prev()
end
function lv_utils.goto_next()
vim.lsp.diagnostic.goto_next()
end
function lv_utils.goto_prev()
vim.lsp.diagnostic.goto_prev()
end
function lv_utils.show_line_diagnostics()
vim.lsp.diagnostic.show_line_diagnostics()
end
-- git signs
function lv_utils.next_hunk()
require('gitsigns').next_hunk()
end
function lv_utils.prev_hunk()
require('gitsigns').prev_hunk()
end
function lv_utils.stage_hunk()
require('gitsigns').stage_hunk()
end
function lv_utils.undo_stage_hunk()
require('gitsigns').undo_stage_hunk()
end
function lv_utils.reset_hunk()
require('gitsigns').reset_hunk()
end
function lv_utils.reset_buffer()
require('gitsigns').reset_buffer()
end
function lv_utils.preview_hunk()
require('gitsigns').preview_hunk()
end
function lv_utils.blame_line()
require('gitsigns').blame_line()
end
-- misc
function lv_utils.file_exists(name)
local f = io.open(name, "r")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
return lv_utils
Regular → Executable
+27
View File
@@ -1 +1,28 @@
#!/bin/bash #!/bin/bash
# 清理 Homebrew 缓存与无用文件
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: brew-clean
执行 Homebrew 清理(brew cleanup),删除旧版本与缓存。
选项:
-h, --help 显示此帮助
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
set -euo pipefail
if ! command -v brew &>/dev/null; then
echo "错误: 未找到 brew,请先安装 Homebrew" >&2
exit 1
fi
brew cleanup
Regular → Executable
+22
View File
@@ -1,3 +1,25 @@
#!/bin/bash
# 使用国内镜像安装 Homebrew
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: brew-install
通过中科大镜像安装 Homebrew(设置 HOMEBREW_* 镜像环境变量后执行官方安装脚本)。
选项:
-h, --help 显示此帮助
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
set -euo pipefail
export HOMEBREW_BREW_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git" export HOMEBREW_BREW_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git"
export HOMEBREW_CORE_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git" export HOMEBREW_CORE_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git"
export HOMEBREW_BOTTLE_DOMAIN="https://mirrors.ustc.edu.cn/homebrew-bottles" export HOMEBREW_BOTTLE_DOMAIN="https://mirrors.ustc.edu.cn/homebrew-bottles"
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# 将标准输入复制到系统剪贴板(macOS / Linux X11 / Wayland)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: clip-copy
从 stdin 读取内容并写入系统剪贴板。
支持:
macOS: pbcopy
Wayland: wl-copy
X11: xclip / xsel
选项:
-h, --help 显示此帮助
示例:
echo hello | clip-copy
cat file.txt | clip-copy
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
set -euo pipefail
if command -v pbcopy >/dev/null 2>&1; then
pbcopy
elif [ "${XDG_SESSION_TYPE:-}" = wayland ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then
if command -v wl-copy >/dev/null 2>&1; then
wl-copy --no-newline
else
echo "clip-copy: wl-copy not found (Wayland session)" >&2
exit 1
fi
elif [ -n "${DISPLAY:-}" ]; then
if command -v xclip >/dev/null 2>&1; then
xclip -selection clipboard
elif command -v xsel >/dev/null 2>&1; then
xsel --clipboard --input
else
echo "clip-copy: xclip or xsel not found (DISPLAY=$DISPLAY)" >&2
exit 1
fi
elif command -v xclip >/dev/null 2>&1; then
xclip -selection clipboard
elif command -v xsel >/dev/null 2>&1; then
xsel --clipboard --input
else
echo "clip-copy: no clipboard tool (pbcopy / wl-copy / xclip / xsel)" >&2
exit 1
fi
+11
View File
@@ -0,0 +1,11 @@
# 供 script/*.sh source:统一处理 -h / --help
# 调用方需先定义 usage() 函数
dotfile_help_requested() {
[[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]
}
dotfile_show_help() {
usage
exit 0
}
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# all name are lowercase
# x86_64 -> amd64
# get os and arch
function get_os_arch() {
local os_arch=$(get_os)-$(get_arch)
echo $os_arch
}
function get_os() {
local os=$(uname -s)
os=$(echo $os | tr '[:upper:]' '[:lower:]')
echo $os
}
function get_arch() {
local arch=$(uname -m)
arch=$(echo $arch | tr '[:upper:]' '[:lower:]')
arch=$(echo $arch | sed 's/x86_64/amd64/')
echo $arch
}
+71
View File
@@ -0,0 +1,71 @@
# CN_REGION 持久化到 ~/.config/fish/custom.fish(供 toggle-region / ff region 使用)
dotfile_region_custom_fish() {
echo "${HOME}/.config/fish/custom.fish"
}
dotfile_region_read() {
local custom val
custom="$(dotfile_region_custom_fish)"
if [ -f "$custom" ]; then
val=$(
grep -E '^[[:space:]]*set[[:space:]]+-gx[[:space:]]+CN_REGION[[:space:]]+' "$custom" 2>/dev/null |
tail -1 |
awk '{print $NF}'
)
if [ -n "$val" ]; then
echo "$val"
return 0
fi
fi
if [ -n "${CN_REGION:-}" ]; then
echo "$CN_REGION"
else
echo "0"
fi
}
dotfile_region_write() {
local val="$1"
local custom tmp
custom="$(dotfile_region_custom_fish)"
mkdir -p "$(dirname "$custom")"
tmp="$(mktemp)"
if [ -f "$custom" ]; then
grep -Ev '^[[:space:]]*# dotfile: CN_REGION|^[[:space:]]*set[[:space:]]+-gx[[:space:]]+CN_REGION[[:space:]]+' \
"$custom" >"$tmp" || true
else
: >"$tmp"
fi
{
cat "$tmp"
if [ -s "$tmp" ]; then
echo
fi
echo "# dotfile: CN_REGION (managed by ff region / toggle-region)"
echo "set -gx CN_REGION ${val}"
} >"${custom}.new"
mv "${custom}.new" "$custom"
rm -f "$tmp"
}
dotfile_region_toggle() {
local current next
current="$(dotfile_region_read)"
if [ "$current" = "1" ]; then
next=0
else
next=1
fi
dotfile_region_write "$next"
export CN_REGION="$next"
echo "$next"
}
dotfile_region_label() {
if [ "$1" = "1" ]; then
echo "国内"
else
echo "国外"
fi
}
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
# 执行命令并在失败时通过飞书 Webhook 发送通知
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: croncheck <command> [args...]
执行给定命令;若退出码非 0,向配置的飞书 Webhook 发送失败通知。
最终以原命令的退出码退出。
选项:
-h, --help 显示此帮助
示例:
croncheck /path/to/backup.sh
croncheck docker compose up -d
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
if [ "$#" -lt 1 ]; then
echo "错误: 缺少要执行的命令" >&2
usage
exit 1
fi
WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/808eafd8-a79f-4af0-b730-8442cf15933b"
OUTPUT=$("$@" 2>&1)
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
JSON_DATA=$(cat <<EOF
{
"msg_type": "text",
"content": {
"text": "Cron job fail\n\nCommand: $*\nError: $(echo "$OUTPUT" | sed 's/"/\\"/g')"
}
}
EOF
)
curl -s -X POST -H "Content-Type: application/json" -d "$JSON_DATA" "$WEBHOOK_URL"
fi
exit $EXIT_CODE
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
# 将 Cursor 用户配置链接到 dotfile(macOS)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: cursor-init
链接 ~/.dotfile/cursor/config/ 下的 settings.json、keybindings.json
到 Cursor 用户目录(macOS)。
已有文件会备份为 *.bak。
选项:
-h, --help 显示此帮助
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
set -euo pipefail
echo 'Cursor config init'
src="$HOME/Library/Application Support/Cursor/User/settings.json"
if [ -f "$src" ]; then
mv "$src" "$src.bak"
fi
ln -s "$HOME/.dotfile/cursor/config/settings.json" "$src"
src="$HOME/Library/Application Support/Cursor/User/keybindings.json"
if [ -f "$src" ]; then
mv "$src" "$src.bak"
fi
ln -s "$HOME/.dotfile/cursor/config/keybindings.json" "$src"
+205
View File
@@ -0,0 +1,205 @@
#!/bin/bash
# Debian 国内镜像源更换脚本(交互式选择镜像)
# 支持 Debian 9/10/11/12/13 (stretch/buster/bullseye/bookworm/trixie)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: sudo debian-init
交互式将 Debian apt 源更换为国内镜像(需 root)。
自动检测版本代号,备份原 sources.list。
选项:
-h, --help 显示此帮助
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 检测是否为 root 用户
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}错误: 请使用 root 权限运行此脚本${NC}"
echo "使用: sudo $0"
exit 1
fi
# 检测 Debian 版本
detect_debian_version() {
if [ -f /etc/debian_version ]; then
DEBIAN_VERSION=$(cat /etc/debian_version | cut -d. -f1)
if [ -f /etc/os-release ]; then
. /etc/os-release
CODENAME=$(echo $VERSION_CODENAME | tr '[:upper:]' '[:lower:]')
else
case $DEBIAN_VERSION in
9) CODENAME="stretch" ;;
10) CODENAME="buster" ;;
11) CODENAME="bullseye" ;;
12) CODENAME="bookworm" ;;
13) CODENAME="trixie" ;;
*) CODENAME="bookworm" ;; # 默认使用 bookworm
esac
fi
else
echo -e "${RED}错误: 未检测到 Debian 系统${NC}"
exit 1
fi
}
# 显示可用的镜像源
show_mirrors() {
echo -e "${YELLOW}可用的国内镜像源:${NC}"
echo "1) 阿里云 (aliyun)"
echo "2) 清华大学 (tsinghua)"
echo "3) 中科大 (ustc)"
echo "4) 网易 (163)"
echo "5) 华为云 (huawei)"
echo "6) 腾讯云 (tencent)"
}
# 获取镜像源 URL
get_mirror_url() {
local mirror=$1
local codename=$2
case $mirror in
aliyun)
echo "https://mirrors.aliyun.com/debian/"
;;
tsinghua)
echo "https://mirrors.tuna.tsinghua.edu.cn/debian/"
;;
ustc)
echo "https://mirrors.ustc.edu.cn/debian/"
;;
163)
echo "https://mirrors.163.com/debian/"
;;
huawei)
echo "https://mirrors.huaweicloud.com/debian/"
;;
tencent)
echo "https://mirrors.cloud.tencent.com/debian/"
;;
*)
echo "https://mirrors.aliyun.com/debian/" # 默认使用阿里云
;;
esac
}
# 获取安全更新镜像源 URL
get_security_mirror_url() {
local mirror=$1
case $mirror in
aliyun)
echo "https://mirrors.aliyun.com/debian-security/"
;;
tsinghua)
echo "https://mirrors.tuna.tsinghua.edu.cn/debian-security/"
;;
ustc)
echo "https://mirrors.ustc.edu.cn/debian-security/"
;;
163)
echo "https://mirrors.163.com/debian-security/"
;;
huawei)
echo "https://mirrors.huaweicloud.com/debian-security/"
;;
tencent)
echo "https://mirrors.cloud.tencent.com/debian-security/"
;;
*)
echo "https://mirrors.aliyun.com/debian-security/" # 默认使用阿里云
;;
esac
}
# 生成 sources.list 内容
generate_sources_list() {
local mirror_url=$1
local security_mirror_url=$2
local codename=$3
cat <<EOF
# Debian ${codename} 国内镜像源
# 生成时间: $(date '+%Y-%m-%d %H:%M:%S')
# 默认仓库
deb ${mirror_url} ${codename} main contrib non-free non-free-firmware
deb ${mirror_url} ${codename}-updates main contrib non-free non-free-firmware
deb ${mirror_url} ${codename}-backports main contrib non-free non-free-firmware
# 安全更新
deb ${security_mirror_url} ${codename}-security main contrib non-free non-free-firmware
EOF
}
# 主函数
main() {
echo -e "${GREEN}=== Debian 国内镜像源更换脚本 ===${NC}\n"
# 检测 Debian 版本
detect_debian_version
echo -e "${GREEN}检测到 Debian 版本: ${DEBIAN_VERSION} (${CODENAME})${NC}\n"
# 显示可用镜像源
show_mirrors
echo ""
read -p "请选择镜像源 (1-6,默认 1): " choice
choice=${choice:-1}
case $choice in
1) MIRROR="aliyun" ;;
2) MIRROR="tsinghua" ;;
3) MIRROR="ustc" ;;
4) MIRROR="163" ;;
5) MIRROR="huawei" ;;
6) MIRROR="tencent" ;;
*) MIRROR="aliyun" ;;
esac
MIRROR_URL=$(get_mirror_url $MIRROR $CODENAME)
SECURITY_MIRROR_URL=$(get_security_mirror_url $MIRROR)
echo -e "\n${GREEN}选择的镜像源: ${MIRROR} (${MIRROR_URL})${NC}"
echo -e "${GREEN}安全更新镜像源: ${SECURITY_MIRROR_URL}${NC}\n"
# 备份原有 sources.list
SOURCES_LIST="/etc/apt/sources.list"
BACKUP_FILE="/etc/apt/sources.list.backup.$(date +%Y%m%d_%H%M%S)"
if [ -f "$SOURCES_LIST" ]; then
cp "$SOURCES_LIST" "$BACKUP_FILE"
echo -e "${GREEN}已备份原有 sources.list 到: ${BACKUP_FILE}${NC}"
fi
# 生成新的 sources.list
generate_sources_list "$MIRROR_URL" "$SECURITY_MIRROR_URL" "$CODENAME" > "$SOURCES_LIST"
echo -e "${GREEN}已更新 sources.list${NC}\n"
# 更新软件包列表
echo -e "${YELLOW}正在更新软件包列表...${NC}"
apt update
echo -e "\n${GREEN}✓ 镜像源更换完成!${NC}"
echo -e "${GREEN}备份文件位置: ${BACKUP_FILE}${NC}"
}
# 运行主函数
main
+145
View File
@@ -0,0 +1,145 @@
#!/bin/bash
# Debian 一键更换清华镜像源脚本 (DEB822 格式)
# 支持 Debian 12 (bookworm)、13 (trixie)、14 (forky) 及后续版本
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: sudo debian-tuna
将 Debian apt 源一键替换为清华 DEB822 格式源(需 root)。
会处理 /etc/apt/sources.list.d/debian.sources 与旧版 sources.list。
选项:
-h, --help 显示此帮助
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
TUNA_DEBIAN="https://mirrors.tuna.tsinghua.edu.cn/debian"
SECURITY_DEBIAN="https://security.debian.org/debian-security"
KEYRING="/usr/share/keyrings/debian-archive-keyring.gpg"
SOURCES_FILE="/etc/apt/sources.list.d/debian.sources"
LEGACY_LIST="/etc/apt/sources.list"
# 检测是否为 root 用户
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}错误: 请使用 root 权限运行此脚本${NC}"
echo "使用: sudo $0"
exit 1
fi
# 检测 Debian 版本与代号
detect_debian() {
if [ ! -f /etc/os-release ]; then
echo -e "${RED}错误: 未检测到 /etc/os-release,无法识别系统${NC}"
exit 1
fi
. /etc/os-release
if [ "${ID:-}" != "debian" ]; then
echo -e "${YELLOW}警告: 当前系统 ID 为 '${ID:-未知}',并非纯 Debian,继续操作可能不适用${NC}"
fi
DEBIAN_VERSION=${VERSION_ID:-$(cut -d. -f1 /etc/debian_version 2>/dev/null)}
CODENAME=$(echo "${VERSION_CODENAME:-}" | tr '[:upper:]' '[:lower:]')
# 若 os-release 未提供代号,按主版本号兜底推断
if [ -z "$CODENAME" ]; then
case "${DEBIAN_VERSION%%.*}" in
12) CODENAME="bookworm" ;;
13) CODENAME="trixie" ;;
14) CODENAME="forky" ;;
*)
echo -e "${RED}错误: 无法确定 Debian 代号 (版本: ${DEBIAN_VERSION:-未知})${NC}"
exit 1
;;
esac
fi
case "${DEBIAN_VERSION%%.*}" in
12 | 13 | 14) ;;
*)
echo -e "${YELLOW}警告: 当前 Debian 主版本为 '${DEBIAN_VERSION%%.*}',脚本主要面向 12/13/14,仍将按代号 '${CODENAME}' 生成配置${NC}"
;;
esac
}
# 生成 DEB822 格式的 .sources 内容
generate_sources() {
cat <<EOF
Types: deb
URIs: ${TUNA_DEBIAN}
Suites: ${CODENAME} ${CODENAME}-updates ${CODENAME}-backports
Components: main contrib non-free non-free-firmware
Signed-By: ${KEYRING}
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
# Types: deb-src
# URIs: ${TUNA_DEBIAN}
# Suites: ${CODENAME} ${CODENAME}-updates ${CODENAME}-backports
# Components: main contrib non-free non-free-firmware
# Signed-By: ${KEYRING}
# 以下安全更新软件源为官方源配置
Types: deb
URIs: ${SECURITY_DEBIAN}
Suites: ${CODENAME}-security
Components: main contrib non-free non-free-firmware
Signed-By: ${KEYRING}
# Types: deb-src
# URIs: ${SECURITY_DEBIAN}
# Suites: ${CODENAME}-security
# Components: main contrib non-free non-free-firmware
# Signed-By: ${KEYRING}
EOF
}
main() {
echo -e "${GREEN}=== Debian 一键更换清华镜像源 (DEB822) ===${NC}\n"
detect_debian
echo -e "${GREEN}检测到 Debian ${DEBIAN_VERSION} (${CODENAME})${NC}\n"
local stamp
stamp=$(date +%Y%m%d_%H%M%S)
# 备份并停用旧版 sources.list,避免与 DEB822 配置重复
if [ -s "$LEGACY_LIST" ]; then
cp "$LEGACY_LIST" "${LEGACY_LIST}.backup.${stamp}"
: >"$LEGACY_LIST"
echo -e "${GREEN}已备份并清空旧版 sources.list -> ${LEGACY_LIST}.backup.${stamp}${NC}"
fi
# 备份已有的 .sources 文件
if [ -f "$SOURCES_FILE" ]; then
cp "$SOURCES_FILE" "${SOURCES_FILE}.backup.${stamp}"
echo -e "${GREEN}已备份原有 debian.sources -> ${SOURCES_FILE}.backup.${stamp}${NC}"
fi
mkdir -p "$(dirname "$SOURCES_FILE")"
generate_sources >"$SOURCES_FILE"
echo -e "${GREEN}已写入清华镜像源配置 -> ${SOURCES_FILE}${NC}\n"
echo -e "${YELLOW}正在更新软件包列表...${NC}"
apt update
echo -e "\n${GREEN}✓ 清华镜像源更换完成!${NC}"
}
main
+131
View File
@@ -0,0 +1,131 @@
#!/bin/bash
# 查询目录大小(du 封装,支持排序与 Top N)
set -eu
usage() {
cat <<'EOF'
用法: dirsize [选项] [目录]
查询目录大小,默认列出当前目录下的直接子目录和子文件。
选项:
-a, --all 递归显示所有子目录的大小
-d, --depth N 指定递归深度 (默认 1)
-n, --top N 只显示前 N 名 (默认全部)
-r, --reverse 按从小到大排序 (默认从大到小)
-h, --help 显示帮助信息
示例:
dirsize 当前目录的直接子项大小
dirsize -n 10 当前目录的直接子项,取前 10 名
dirsize -a 递归显示所有子目录
dirsize -d 2 -n 5 深度 2,取前 5 名
dirsize -n 5 /var/log 查看 /var/log 的子项,取前 5 名
EOF
exit 0
}
DEPTH=1
TOP=0
REVERSE=false
ALL=false
TARGET_DIR="."
while [[ $# -gt 0 ]]; do
case "$1" in
-a | --all)
ALL=true
shift
;;
-d | --depth)
DEPTH="$2"
shift 2
;;
-n | --top)
TOP="$2"
shift 2
;;
-r | --reverse)
REVERSE=true
shift
;;
-h | --help) usage ;;
-*)
echo "未知选项: $1" >&2
usage
;;
*)
TARGET_DIR="$1"
shift
;;
esac
done
if [[ ! -d "$TARGET_DIR" ]]; then
echo "错误: '$TARGET_DIR' 不是有效目录" >&2
exit 1
fi
TARGET_DIR="$(cd "$TARGET_DIR" && pwd -P)"
if $ALL; then
DEPTH=999
fi
sort_flag="-rh"
if $REVERSE; then
sort_flag="-h"
fi
list_dir_sizes() {
if [[ "$OSTYPE" == "darwin"* ]]; then
du -h -d "$DEPTH" "$TARGET_DIR" 2>/dev/null
else
du -h --max-depth="$DEPTH" "$TARGET_DIR" 2>/dev/null
fi | awk -v dir="$TARGET_DIR" '$2 != dir {print}'
}
# 用 ls 读取直接子文件(一次 readdir),避免 find 递归
list_direct_file_sizes() {
ls -lA "$TARGET_DIR" 2>/dev/null | awk -v dir="$TARGET_DIR" '
function human(bytes, units, i, size) {
split("B K M G T", units, " ")
i = 1
size = bytes
while (size >= 1024 && i < 5) {
size /= 1024
i++
}
if (i == 1) {
return sprintf("%dB", bytes)
}
return sprintf("%.1f%s", size, units[i])
}
/^-/ {
name = $9
for (i = 10; i <= NF; i++) {
name = name " " $i
}
printf "%s\t%s/%s\n", human($5), dir, name
}
'
}
result=$(
{
list_dir_sizes
list_direct_file_sizes
} | sort $sort_flag
)
if [[ "$TOP" -gt 0 ]]; then
result=$(echo "$result" | head -n "$TOP")
fi
if [[ -z "$result" ]]; then
echo "目录为空"
exit 0
fi
echo "$result"
+95
View File
@@ -0,0 +1,95 @@
#!/bin/bash
# 清理 macOS / Linux 系统 DNS 缓存
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: dns-clean
按当前操作系统清理 DNS 缓存:
macOS: dscacheutil + mDNSResponder
Linux: systemd-resolved / nscd / dnsmasq / unbound(自动检测)
选项:
-h, --help 显示此帮助
说明: 非 root 时会自动使用 sudo。
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
set -e
SUDO=""
[ "$(id -u)" -ne 0 ] && SUDO="sudo"
flush_macos() {
echo "macOS: 清理 DNS 缓存..."
$SUDO dscacheutil -flushcache
$SUDO killall -HUP mDNSResponder 2>/dev/null || true
$SUDO killall mDNSResponderHelper 2>/dev/null || true
echo "macOS DNS 缓存已清理"
}
flush_linux() {
local flushed=0
echo "Linux: 清理 DNS 缓存..."
if command -v resolvectl &>/dev/null; then
if $SUDO resolvectl flush-caches 2>/dev/null; then
echo " - systemd-resolved (resolvectl) 缓存已清理"
flushed=1
fi
elif command -v systemd-resolve &>/dev/null; then
if $SUDO systemd-resolve --flush-caches 2>/dev/null; then
echo " - systemd-resolved (systemd-resolve) 缓存已清理"
flushed=1
fi
fi
if command -v systemctl &>/dev/null; then
if systemctl is-active --quiet nscd 2>/dev/null; then
$SUDO systemctl restart nscd
echo " - nscd 已重启"
flushed=1
fi
if systemctl is-active --quiet dnsmasq 2>/dev/null; then
$SUDO systemctl restart dnsmasq
echo " - dnsmasq 已重启"
flushed=1
fi
if systemctl is-active --quiet unbound 2>/dev/null; then
if command -v rndc &>/dev/null; then
$SUDO rndc flush 2>/dev/null && echo " - unbound 缓存已清理" && flushed=1
else
$SUDO systemctl restart unbound
echo " - unbound 已重启"
flushed=1
fi
fi
fi
if [ "$flushed" -eq 0 ]; then
echo "未检测到常见 DNS 缓存服务 (systemd-resolved / nscd / dnsmasq / unbound)"
echo "若仍有问题,可尝试重启 NetworkManager 或检查本地 DNS 配置"
exit 1
fi
echo "Linux DNS 缓存已清理"
}
case "$(uname -s)" in
Darwin) flush_macos ;;
Linux) flush_linux ;;
*)
echo "错误: 不支持的操作系统: $(uname -s)"
exit 1
;;
esac
Regular → Executable
+23
View File
@@ -1,2 +1,25 @@
#!/bin/bash #!/bin/bash
# 清理 Docker 未使用的镜像、容器与缓存(docker system prune -a)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: docker-clean
执行 docker system prune -a,删除未使用的镜像、容器、网络等。
选项:
-h, --help 显示此帮助
警告: 会删除未使用的镜像,请确认无重要 dangling 资源。
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
set -euo pipefail
docker system prune -a docker system prune -a
+281
View File
@@ -0,0 +1,281 @@
#!/usr/bin/env python3
# 按类别增量更新 /etc/docker/daemon.json(仅补缺失项,不覆盖已有配置)
from __future__ import annotations
import argparse
import copy
import json
import os
import shutil
import subprocess
import sys
from datetime import datetime
from pathlib import Path
from typing import Any
DAEMON_JSON = Path("/etc/docker/daemon.json")
PATCH_DIR_NAME = Path("docker") / "daemon.d"
CATEGORIES: dict[str, str] = {
"base": "日志轮转等基础项(log-driver / log-opts)",
"mirror": "镜像加速(registry-mirrors)",
}
def dotfile_root() -> Path:
return Path(__file__).resolve().parent.parent
def usage_text() -> str:
cats = "\n".join(f" {name:<8} {desc}" for name, desc in CATEGORIES.items())
return f"""用法: docker-daemon-config [选项] [类别 ...]
将 ~/.dotfile/docker/daemon.d/ 下对应片段合并进 /etc/docker/daemon.json。
已有 key 保留不变;仅插入缺失的 key(嵌套对象递归补全)。
类别:
{cats}
all 应用上述全部类别
示例:
sudo ff script docker-daemon-config base
sudo ff script docker-daemon-config mirror
sudo ff script docker-daemon-config all
sudo ff script docker-daemon-config base --dry-run
选项:
-h, --help 显示此帮助
--list 列出可用类别
--dry-run 只打印合并结果,不写文件
--no-backup 不备份现有 daemon.json
--no-restart 合并后不尝试 reload/restart docker
"""
def fill_missing(base: Any, patch: Any) -> Any:
"""仅补 patch 中有、base 中没有的 key;已有 key 不覆盖。"""
if not isinstance(patch, dict):
return base
if not isinstance(base, dict):
return copy.deepcopy(patch)
out = copy.deepcopy(base)
for key, patch_value in patch.items():
if key not in out:
out[key] = copy.deepcopy(patch_value)
elif isinstance(out[key], dict) and isinstance(patch_value, dict):
out[key] = fill_missing(out[key], patch_value)
return out
def load_json(path: Path) -> dict[str, Any]:
text = path.read_text(encoding="utf-8").strip()
if not text:
return {}
data = json.loads(text)
if not isinstance(data, dict):
raise ValueError(f"{path} 根节点必须是 JSON 对象")
return data
def resolve_categories(names: list[str]) -> list[str]:
if not names:
return []
if "all" in names:
return list(CATEGORIES.keys())
unknown = [name for name in names if name not in CATEGORIES]
if unknown:
raise ValueError(f"未知类别: {', '.join(unknown)}")
# 去重并保持顺序
seen: set[str] = set()
ordered: list[str] = []
for name in names:
if name not in seen:
seen.add(name)
ordered.append(name)
return ordered
def patch_path(root: Path, category: str) -> Path:
return root / PATCH_DIR_NAME / f"{category}.json"
def collect_patches(root: Path, categories: list[str]) -> dict[str, dict[str, Any]]:
patches: dict[str, dict[str, Any]] = {}
for category in categories:
path = patch_path(root, category)
if not path.is_file():
raise FileNotFoundError(f"缺少配置片段: {path}")
patches[category] = load_json(path)
return patches
def diff_added(before: dict[str, Any], after: dict[str, Any], prefix: str = "") -> list[str]:
added: list[str] = []
for key, value in after.items():
path = f"{prefix}{key}"
if key not in before:
added.append(path)
continue
if isinstance(value, dict) and isinstance(before.get(key), dict):
added.extend(diff_added(before[key], value, prefix=f"{path}."))
return added
def validate_daemon_json(path: Path) -> None:
with path.open(encoding="utf-8") as fh:
json.load(fh)
dockerd = shutil.which("dockerd")
if not dockerd:
return
try:
subprocess.run(
[dockerd, "--validate", "--config-file", str(path)],
check=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE,
text=True,
)
except subprocess.CalledProcessError as exc:
detail = (exc.stderr or "").strip()
raise RuntimeError(f"dockerd --validate 失败: {detail or exc}") from exc
def reload_docker() -> None:
if shutil.which("systemctl") is None:
print("[INFO] 未找到 systemctl,请手动重启 Docker 使配置生效")
return
for action in ("reload", "restart"):
result = subprocess.run(
["systemctl", action, "docker"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
)
if result.returncode == 0:
print(f"[INFO] 已执行 systemctl {action} docker")
return
print("[WARN] systemctl reload/restart docker 失败,请手动重启 Docker")
if result.stdout.strip():
print(result.stdout.strip())
def write_daemon_json(content: dict[str, Any], dry_run: bool, backup: bool) -> None:
serialized = json.dumps(content, indent=2, ensure_ascii=False) + "\n"
if dry_run:
print(serialized)
return
if os.geteuid() != 0:
print("[ERROR] 写入 /etc/docker/daemon.json 需要 root,请使用 sudo 运行")
sys.exit(1)
DAEMON_JSON.parent.mkdir(parents=True, exist_ok=True)
tmp_path = DAEMON_JSON.with_suffix(".json.tmp")
tmp_path.write_text(serialized, encoding="utf-8")
try:
validate_daemon_json(tmp_path)
except Exception:
tmp_path.unlink(missing_ok=True)
raise
if backup and DAEMON_JSON.is_file():
stamp = datetime.now().strftime("%Y%m%d%H%M%S")
backup_path = DAEMON_JSON.with_name(f"{DAEMON_JSON.name}.bak.{stamp}")
shutil.copy2(DAEMON_JSON, backup_path)
print(f"[INFO] 已备份到 {backup_path}")
tmp_path.replace(DAEMON_JSON)
os.chmod(DAEMON_JSON, 0o644)
print(f"[INFO] 已写入 {DAEMON_JSON}")
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("categories", nargs="*", help="要应用的类别")
parser.add_argument("-h", "--help", action="store_true")
parser.add_argument("--list", action="store_true", help=argparse.SUPPRESS)
parser.add_argument("--dry-run", action="store_true")
parser.add_argument("--no-backup", action="store_true")
parser.add_argument("--no-restart", action="store_true")
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
if args.help:
print(usage_text())
return 0
if args.list:
for name, desc in CATEGORIES.items():
print(f"{name}\t{desc}")
print("all\t应用全部类别")
return 0
try:
categories = resolve_categories(args.categories)
except ValueError as exc:
print(f"[ERROR] {exc}")
print("可用类别:", ", ".join([*CATEGORIES.keys(), "all"]))
return 1
if not categories:
print(usage_text())
return 1
root = dotfile_root()
patch_root = root / PATCH_DIR_NAME
if not patch_root.is_dir():
print(f"[ERROR] 配置目录不存在: {patch_root}")
return 1
existing: dict[str, Any] = {}
if DAEMON_JSON.is_file():
try:
existing = load_json(DAEMON_JSON)
except json.JSONDecodeError as exc:
print(f"[ERROR] {DAEMON_JSON} 不是合法 JSON: {exc}")
return 1
try:
patches = collect_patches(root, categories)
except (FileNotFoundError, ValueError) as exc:
print(f"[ERROR] {exc}")
return 1
merged = copy.deepcopy(existing)
for category in categories:
before = copy.deepcopy(merged)
merged = fill_missing(merged, patches[category])
added = diff_added(before, merged)
if added:
print(f"[INFO] 类别 {category} 新增: {', '.join(added)}")
else:
print(f"[INFO] 类别 {category} 无需变更(相关项已存在)")
if merged == existing:
print("[INFO] daemon.json 无变化")
return 0
try:
write_daemon_json(merged, dry_run=args.dry_run, backup=not args.no_backup)
except Exception as exc:
print(f"[ERROR] {exc}")
return 1
if not args.dry_run and not args.no_restart:
reload_docker()
return 0
if __name__ == "__main__":
sys.exit(main())
+55
View File
@@ -0,0 +1,55 @@
#!/bin/bash
# 将用户加入 docker 组(免 sudo 使用 docker)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
set -euo pipefail
usage() {
cat <<'EOF'
用法: sudo docker-group <user>
将 <user> 加入 docker 组,之后可直接运行 docker(无需 sudo)。
示例:
sudo docker-group xuser
说明:
- 用户需重新登录或 newgrp docker 后生效
- 安装 Docker 时 docker-install.sh 只会把当时的 $USER 加入组
选项:
-h, --help 显示此帮助
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
[[ $# -eq 1 ]] || { usage; exit 1; }
if [[ $EUID -ne 0 ]]; then
echo "错误: 请使用 sudo 运行,例如: sudo $0 $1"
exit 1
fi
user="$1"
if ! id "$user" &>/dev/null; then
echo "错误: 用户不存在: $user"
exit 1
fi
if ! getent group docker &>/dev/null; then
echo "错误: docker 组不存在,请先安装 Docker(例如运行 docker-install.sh)"
exit 1
fi
if id -nG "$user" | tr ' ' '\n' | grep -qx docker; then
echo "用户 $user 已在 docker 组中"
exit 0
fi
usermod -aG docker "$user"
echo "已将 $user 加入 docker 组"
echo "请让用户重新登录,或执行: su - $user -c 'newgrp docker'"
+165
View File
@@ -0,0 +1,165 @@
#!/bin/bash
# 在 Debian/Ubuntu 上安装 Docker CE(支持国内/国外镜像源)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common/help.sh"
usage() {
cat <<'EOF'
用法: docker-install
在 Debian 或 Ubuntu 上安装 Docker CE 及 compose/buildx 插件。
根据环境变量 CN_REGION 选择镜像源:
CN_REGION=1 清华镜像
其他 Docker 官方源
安装完成后将当前用户加入 docker 组。
选项:
-h, --help 显示此帮助
EOF
}
dotfile_help_requested "${1:-}" && dotfile_show_help
set -e
# Ubuntu 24.04 的 apt hook 给 needrestart 传 -m u(强制重启服务),会覆盖
# NEEDRESTART_MODE;只有 NEEDRESTART_SUSPEND 能让 hook 直接跳过。
apt_get() {
sudo env DEBIAN_FRONTEND=noninteractive NEEDRESTART_SUSPEND=1 apt-get "$@"
}
pkg_installed() {
[ "$(dpkg-query -W -f='${Status}' "$1" 2>/dev/null)" = "install ok installed" ]
}
# 只补缺,不升级已装包。已全部装好则不调用 apt,避免触发 needrestart。
apt_get_install() {
local missing=()
local pkg
for pkg in "$@"; do
pkg_installed "$pkg" || missing+=("$pkg")
done
if [ ${#missing[@]} -eq 0 ]; then
return 0
fi
apt_get install -y --no-install-recommends --no-upgrade "${missing[@]}"
}
detect_distro() {
if [ ! -f /etc/os-release ]; then
echo "[ERROR] 未检测到 /etc/os-release,无法识别系统"
exit 1
fi
. /etc/os-release
case "${ID:-}" in
debian | ubuntu)
DISTRO="${ID}"
CODENAME="${UBUNTU_CODENAME:-${VERSION_CODENAME:-$(lsb_release -cs 2>/dev/null)}}"
;;
*)
echo "[ERROR] 不支持的操作系统: ${ID:-未知},仅支持 Debian 和 Ubuntu"
exit 1
;;
esac
if [ -z "$CODENAME" ]; then
echo "[ERROR] 无法确定系统代号"
exit 1
fi
}
remove_conflicting_packages() {
local pkg
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do
pkg_installed "$pkg" || continue
apt_get remove -y "$pkg" || true
done
}
install_prerequisites() {
apt_get update
apt_get_install ca-certificates curl gnupg lsb-release
}
add_user_to_docker_group() {
local target_user="${SUDO_USER:-$USER}"
if [ -z "$target_user" ] || [ "$target_user" = "root" ]; then
echo "[WARN] 无法确定目标用户,请手动执行: sudo docker-group <user>"
return 0
fi
if ! getent group docker >/dev/null 2>&1; then
echo "[WARN] docker 组不存在,跳过加组"
return 0
fi
if id -nG "$target_user" | tr ' ' '\n' | grep -qx docker; then
echo "[INFO] 用户 ${target_user} 已在 docker 组中"
return 0
fi
sudo usermod -aG docker "$target_user"
if id -nG "$target_user" | tr ' ' '\n' | grep -qx docker; then
echo "[INFO] 已将 ${target_user} 加入 docker 组(需重新登录或 newgrp 后当前 shell 才生效)"
else
echo "[WARN] usermod 已执行,但未检测到 ${target_user} 在 docker 组中,请检查: getent group docker"
fi
}
install_docker_cn() {
local repo_base="https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/${DISTRO}"
local keyring="/usr/share/keyrings/docker-archive-keyring.gpg"
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL "${repo_base}/gpg" | sudo gpg --dearmor -o "${keyring}"
echo "deb [arch=$(dpkg --print-architecture) signed-by=${keyring}] ${repo_base} \
${CODENAME} stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
apt_get update
apt_get_install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
add_user_to_docker_group
}
install_docker_intl() {
local repo_base="https://download.docker.com/linux/${DISTRO}"
local keyring="/etc/apt/keyrings/docker.asc"
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL "${repo_base}/gpg" -o "${keyring}"
sudo chmod a+r "${keyring}"
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=${keyring}] ${repo_base} \
${CODENAME} stable" |
sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
apt_get update
apt_get_install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
add_user_to_docker_group
}
detect_distro
remove_conflicting_packages
install_prerequisites
if [ "$CN_REGION" = "1" ]; then
echo "[INFO] 国内环境,使用清华镜像安装 Docker (${DISTRO}/${CODENAME})"
install_docker_cn
else
echo "[INFO] 国外环境,使用官方源安装 Docker (${DISTRO}/${CODENAME})"
install_docker_intl
fi
echo "[INFO] Docker 安装完成"
echo "[INFO] 若 docker 报 permission denied,组变更需新开登录会话才生效,任选其一:"
echo " newgrp docker"
echo " 或重新 SSH 登录 / 重开终端"
echo " 验证: id -nG \$USER | tr ' ' '\\n' | grep -x docker"

Some files were not shown because too many files have changed in this diff Show More