diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e3ebf2..578f366 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,14 @@ # Changelog +## v0.2.0 +### 重大变更 +- 将基于 `vim.lsp.config` 的 Neovim 0.11+ 现代配置提升为默认 `init.lua`,持续提供原 AsyncRun/F 键位等兼容工作流。 +- 将 Windows 平台的 `install-lua.ps1`、`install-local-lua.ps1` 与 `first-launch.ps1` 合并为单一入口脚本,可按需执行本地安装、远程安装与首次插件引导。 + +### 维护记录 +- 首次启动流程整合:自动检测/安装 lazy.nvim,调用 `nvim --headless "+Lazy! sync"`,并提示运行 `:Mason`、`:checkhealth` 等检查步骤。 +- Neovim 0.11.4 兼容性要点:针对 `vim.tbl_*` 废弃警告、Treesitter 查询错误,提供更新插件、临时禁用 Treesitter 或抑制警告的应对策略,并在必要时建议回退至 0.10.x LTS。 +- Mason 推荐安装项:`clangd`、`lua-language-server`、`clang-format`、`stylua`,确保 C/C++ 与 Lua 开发体验一致。 + ## v0.1.0 - 初版:C/C++/嵌入式定位、YCM/ALE/AsyncRun/NERDTree、MagicInstall、快捷键预设。 diff --git a/FIRST_LAUNCH_GUIDE.md b/FIRST_LAUNCH_GUIDE.md deleted file mode 100644 index 0d40367..0000000 --- a/FIRST_LAUNCH_GUIDE.md +++ /dev/null @@ -1,227 +0,0 @@ -# 🚀 首次启动指南 / First Launch Guide - -## ⚠️ 重要提示 - -首次启动 Lua 版本配置时,Neovim 需要: -1. 下载并安装 lazy.nvim 插件管理器 -2. 下载并安装所有插件(~20 个) -3. 编译 Treesitter 语法解析器 - -**这个过程需要 2-5 分钟,请耐心等待!** - ---- - -## 📝 正确的首次启动流程 - -### 步骤 1: 安装配置 - -```powershell -# Windows -.\install-local-lua.ps1 - -# 或远程安装 -Set-ExecutionPolicy Bypass -Scope Process -Force; ` -iwr https://raw.githubusercontent.com/magic-alt/nvim-cpp-ide/main/install-lua.ps1 -UseBasicParsing | iex -``` - -### 步骤 2: 首次启动(重要!) - -```powershell -# 方式 A: 直接启动(推荐) -nvim - -# 首次启动会看到: -# - "Installing lazy.nvim plugin manager..." -# - 插件安装进度条 -# - Treesitter 编译信息 -# - 等待完成后按 Enter 或 q 退出 - -# 方式 B: 强制同步安装(如果方式 A 有问题) -nvim --headless "+Lazy! sync" +qa -``` - -### 步骤 3: 重启 Neovim - -```powershell -nvim -``` - -现在应该没有错误了! - ---- - -## 🔍 常见首次启动问题 - -### 问题 1: "module 'lazy' not found" - -**原因**: Git 克隆 lazy.nvim 失败 - -**解决方案**: -```powershell -# 手动克隆 lazy.nvim -$lazypath = "$env:LOCALAPPDATA\nvim-data\lazy\lazy.nvim" -git clone --filter=blob:none https://github.com/folke/lazy.nvim.git --branch=stable $lazypath - -# 重启 Neovim -nvim -``` - -### 问题 2: 网络超时 - -**原因**: GitHub 连接慢 - -**解决方案 A - 使用镜像**: -```powershell -# 编辑 init.lua,替换 GitHub URL -# 将所有 "https://github.com/" 改为 "https://mirror.ghproxy.com/https://github.com/" -``` - -**解决方案 B - 使用代理**: -```powershell -# 设置 Git 代理 -git config --global http.proxy http://127.0.0.1:7890 -git config --global https.proxy http://127.0.0.1:7890 -``` - -### 问题 3: LSP 服务器未安装 - -**原因**: 只安装了插件,还需要安装 LSP 服务器 - -**解决方案**: -```vim -# 在 Neovim 中执行 -:Mason - -# 在 Mason 界面中: -# 1. 移动到 clangd -# 2. 按 'i' 安装 -# 3. 等待安装完成 -# 4. 重复安装 lua-language-server, clang-format - -# 或者命令行安装 -:MasonInstall clangd lua-language-server clang-format stylua -``` - ---- - -## ✅ 验证安装成功 - -### 1. 检查插件状态 - -```vim -:Lazy -``` - -应该看到所有插件都是绿色 ✓ - -### 2. 检查 LSP 服务器 - -```vim -:Mason -``` - -应该看到已安装的服务器 - -### 3. 测试 LSP 功能 - -```vim -# 打开一个 C++ 文件 -:e test.cpp - -# 输入一些代码 -int main() { - std::cout << "Hello"; -} - -# 按 应该出现补全菜单 -# 将光标放在 std 上按 K 应该显示文档 -``` - -### 4. 运行健康检查 - -```vim -:checkhealth -``` - -查看是否有红色错误。黄色警告通常可以忽略。 - ---- - -## 🎯 完整的首次设置清单 - -- [ ] 安装配置文件 -- [ ] 首次启动 Neovim(等待插件安装) -- [ ] 重启 Neovim -- [ ] 运行 `:Mason` 安装 LSP 服务器 - - [ ] clangd - - [ ] lua-language-server - - [ ] clang-format - - [ ] stylua -- [ ] 运行 `:checkhealth` 验证 -- [ ] 测试代码补全 (``) -- [ ] 测试文件树 (``) -- [ ] 测试 Telescope (`ff`) - ---- - -## 🚨 如果一切都失败了 - -### 完全重置 - -```powershell -# 删除所有 Neovim 数据 -Remove-Item -Recurse -Force "$env:LOCALAPPDATA\nvim" -Remove-Item -Recurse -Force "$env:LOCALAPPDATA\nvim-data" - -# 重新安装 -.\install-local-lua.ps1 -nvim -``` - -### 使用 VimScript 版本 - -如果 Lua 版本持续有问题,可以先使用稳定的 VimScript 版本: - -```powershell -.\install-local.ps1 # 安装 config.vim -nvim -``` - ---- - -## 📊 预期首次启动时间 - -| 阶段 | 时间 | 说明 | -|------|------|------| -| 克隆 lazy.nvim | ~10s | 下载插件管理器 | -| 下载插件 | ~60s | 下载 20+ 个插件 | -| 编译 Treesitter | ~30s | 编译语法解析器 | -| **总计** | **~2 分钟** | 取决于网速 | - -后续启动:~100ms ⚡ - ---- - -## 💡 提示 - -1. **第一次启动很慢是正常的**,不要中途关闭! -2. 看到很多文字滚动是正常的,这是插件在安装 -3. 如果卡住超过 5 分钟,按 `Ctrl+C` 退出,然后重试 -4. 安装完成后重启 Neovim,体验会变得飞快! - ---- - -## 🎉 安装成功后 - -恭喜!你现在拥有一个现代化的 Neovim C/C++ IDE: - -- ⚡ 原生 LSP 补全 -- 🎨 Treesitter 语法高亮 -- 📁 nvim-tree 文件浏览 -- 🔍 Telescope 模糊搜索 -- 🎯 一键格式化 -- 🚀 启动速度 ~80ms - -**按 `` 查看所有快捷键!** - -**阅读 `LUA_MIGRATION_GUIDE.md` 了解更多功能!** diff --git a/LSP_CONFIG_GUIDE.md b/LSP_CONFIG_GUIDE.md index d303e14..018360b 100644 --- a/LSP_CONFIG_GUIDE.md +++ b/LSP_CONFIG_GUIDE.md @@ -11,70 +11,77 @@ nvim-lspconfig is deprecated. Use vim.lsp.config instead. --- -## 📊 三种配置方式对比 +## 📊 两种配置方式对比 -### 方案 A: 抑制警告(推荐 ✅) +### 方案 A: Neovim 0.11+ 原生 API(默认 ✅) -**文件**: `init.lua` (当前使用) +**文件**: `init.lua` **优势**: -- ✅ 使用成熟稳定的 `nvim-lspconfig` -- ✅ 社区支持完善,文档齐全 -- ✅ 兼容 Neovim 0.8+ -- ✅ 只是抑制过渡期警告 -- ✅ 功能完全正常 +- ✅ 直接使用 `vim.lsp.config`,减少对第三方插件的依赖 +- ✅ 与 lazy.nvim、Mason 的初始化流程无缝整合 +- ✅ 代码更精简,便于后续跟随 Neovim 官方演进 + +**注意事项**: +- ⚠️ 需要 Neovim 0.11 nightly 或以上版本(提供 `vim.lsp.config`) +- ⚠️ API 仍在快速演进,如遇到重大变更请关注 `CHANGELOG.md` **实现方式**: ```lua --- 抑制 lspconfig 过渡警告 -local notify = vim.notify -vim.notify = function(msg, ...) - if msg:match("lspconfig") then - return - end - notify(msg, ...) -end - --- 正常使用 nvim-lspconfig -local lspconfig = require("lspconfig") -lspconfig.clangd.setup({ ... }) -lspconfig.lua_ls.setup({ ... }) +vim.lsp.config({ + on_attach = on_attach, + capabilities = capabilities, + servers = { + clangd = { + cmd = { + "clangd", + "--background-index", + "--clang-tidy", + "--header-insertion=iwyu", + "--completion-style=detailed", + "--function-arg-placeholders", + }, + filetypes = { "c", "cpp", "objc", "objcpp", "cuda" }, + }, + lua_ls = { + settings = { + Lua = { + diagnostics = { globals = { "vim" } }, + workspace = { checkThirdParty = false }, + telemetry = { enable = false }, + }, + }, + }, + }, +}) ``` -**适合**: 所有用户,特别是需要稳定环境的项目 +**适合**: 已升级到 Neovim 0.11+、希望体验最新原生 LSP 流程的用户 --- -### 方案 B: 使用新 API(实验性 ⚠️) +### 方案 B: 继续使用 `nvim-lspconfig`(兼容 0.8~0.10 ⚠️) -**文件**: `init-modern.lua` (提供备选) +**文件**: `config.vim`(VimScript 版本)或仓库历史版本中的 `init.lua` **优势**: -- ✅ 使用 Neovim 0.11+ 原生 API -- ✅ 无需 `nvim-lspconfig` 插件 -- ✅ 更简洁的配置语法 +- ✅ 支持稳定版 Neovim 0.8~0.10 以及 Vim 8.0+ +- ✅ 生态成熟,文档、示例丰富 -**劣势**: -- ❌ API 还在开发中(可能变化) -- ❌ 文档不完整 -- ❌ 社区插件可能不兼容 -- ❌ 只支持 Neovim 0.11+ +**注意事项**: +- ⚠️ 需要继续安装 `nvim-lspconfig`、`mason-lspconfig` 等插件 +- ⚠️ 建议通过 `CHANGELOG.md` 确认兼容性更新 -**实现方式**: -```lua --- Neovim 0.11+ 新方式(实验性) -vim.lsp.config({ - on_attach = on_attach, - capabilities = capabilities, - - servers = { - clangd = { cmd = {...}, filetypes = {...} }, - lua_ls = { settings = {...} }, - } -}) +**切换方式**: +```powershell +# 使用 VimScript 版本(兼容 0.8~0.10) +Copy-Item config.vim "$env:LOCALAPPDATA\nvim\init.vim" -Force + +# 或者检出历史版本的 init.lua(v0.1.0 仍基于 nvim-lspconfig) +git checkout v0.1.0 init.lua ``` -**适合**: 尝鲜用户,实验性项目 +**适合**: 仍在使用 Neovim 0.10 及更早版本、或需要 Vim 兼容性的环境 --- @@ -82,39 +89,14 @@ vim.lsp.config({ **实现方式**: 什么都不做 -**问题**: 每次启动都看到警告,影响体验 +**问题**: 每次启动都看到警告,且无法享受新 API 优化 --- ## 🎯 推荐选择 -### 大多数用户 → **方案 A** (当前配置) - -**理由**: -1. `nvim-lspconfig` 是成熟的解决方案 -2. 有数千个项目在使用 -3. 文档完整,社区支持好 -4. 只需抑制警告即可 - -### 尝鲜用户 → **方案 B** (init-modern.lua) - -**如何切换**: -```powershell -# 备份当前配置 -Copy-Item init.lua init-lspconfig.lua - -# 使用新配置 -Copy-Item init-modern.lua init.lua - -# 重启 Neovim -nvim -``` - -**切换回来**: -```powershell -Copy-Item init-lspconfig.lua init.lua -nvim -``` +- **已经升级 Neovim 0.11+** → 选择方案 A(仓库默认配置) +- **必须保持兼容 0.8~0.10 或 Vim** → 选择方案 B(使用 `config.vim` 或 v0.1.0 的 `init.lua`) --- @@ -210,28 +192,24 @@ int main() { ## 🎯 总结 -### 当前配置(推荐)✅ +### 当前配置(默认)✅ **文件**: `init.lua` -- ✅ 使用 `nvim-lspconfig`(成熟) -- ✅ 抑制过渡期警告 -- ✅ 功能完全正常 -- ✅ 社区支持完善 +- ✅ 使用 `vim.lsp.config` 原生 API +- ✅ 与 lazy.nvim、Mason 深度集成 +- ✅ 针对 Neovim 0.11+ 调优 -### 备选配置(实验)⚠️ +### 兼容配置(旧版)⚠️ -**文件**: `init-modern.lua` -- ⚠️ 使用 `vim.lsp.config`(实验) -- ⚠️ API 可能变化 -- ⚠️ 仅供尝鲜 +**文件**: `config.vim` 或 v0.1.0 的 `init.lua` +- ⚠️ 基于 `nvim-lspconfig`,适合 Neovim 0.8~0.10 / Vim 8.0+ +- ⚠️ 需要保留旧版依赖与插件 --- ## 💡 建议 -1. **继续使用当前配置** (`init.lua`) -2. **关注 Neovim 发布说明**,等待 `vim.lsp.config` API 稳定 -3. **定期更新插件**: `:Lazy sync` -4. **如果好奇**,可以测试 `init-modern.lua`,但建议备份 - -**警告已被抑制,功能完全正常,可以放心使用!** ✅ +1. **Neovim 0.11+ 用户** → 按默认 `init.lua` 使用,并定期 `:Lazy sync` / `:Mason` 更新。 +2. **需要旧版兼容** → 复制 `config.vim` 或检出 v0.1.0 的 `init.lua`。 +3. **关注 `CHANGELOG.md`** → 第一时间获知兼容性修复与 API 变动。 +4. **遇到问题** → 可使用 `install-lua.ps1 -FirstLaunchOnly` 重新执行 Lazy 同步。 diff --git a/NEOVIM_COMPAT_FIX.md b/NEOVIM_COMPAT_FIX.md deleted file mode 100644 index e445ade..0000000 --- a/NEOVIM_COMPAT_FIX.md +++ /dev/null @@ -1,247 +0,0 @@ -# 🔧 Neovim 0.11.4 兼容性修复指南 - -## 问题诊断 - -### 1. Deprecated API 警告 -``` -⚠️ vim.tbl_islist → vim.islist -⚠️ vim.tbl_flatten → vim.iter(...):flatten():totable() -⚠️ vim.str_utfindex → vim.str_utfindex(s, encoding, index, strict_indexing) -``` - -**原因**: 插件使用了旧的 Lua API,Neovim 0.11+ 已废弃 - -**影响**: 不影响功能,但会在未来版本中移除 - -### 2. Treesitter Query Error -``` -Query error at 10:3. Impossible pattern: -"~" @markup.heading.4.marker -``` - -**原因**: Neovim 0.11.4 的 treesitter 查询语法更严格,某些插件的查询文件不兼容 - -**影响**: 可能导致语法高亮或某些功能失效 - ---- - -## 🛠️ 修复方案 - -### 方案 A: 禁用 Treesitter(快速解决) - -在 `config.vim` 中添加: - -```vim -" 禁用 Treesitter(如果遇到兼容性问题) -if has('nvim') - lua << EOF - -- 禁用 treesitter - vim.g.loaded_nvim_treesitter = 1 -EOF -endif -``` - -### 方案 B: 更新插件(推荐) - -更新所有插件到最新版本: - -```vim -" 如果使用 vim-plug -:PlugUpdate - -" 如果使用 packer.nvim -:PackerSync - -" 如果使用 lazy.nvim -:Lazy sync -``` - -### 方案 C: 忽略 Deprecated 警告 - -在 `config.vim` 顶部添加: - -```vim -" 临时禁用 deprecated 警告 -if has('nvim') - lua vim.deprecate = function() end -endif -``` - -### 方案 D: 降级到稳定版本 - -如果问题持续,考虑使用 Neovim 0.10.x LTS: - -```powershell -# Windows -winget install Neovim.Neovim --version 0.10.2 - -# 或从 GitHub 下载 -# https://github.com/neovim/neovim/releases/tag/v0.10.2 -``` - ---- - -## 📋 具体修复步骤 - -### Step 1: 添加兼容性配置 - -创建 `config-compat.vim` 补丁文件: - -```vim -" ============================================================================ -" Neovim 0.11+ Compatibility Patch -" ============================================================================ - -if has('nvim-0.11') - lua << EOF - -- 临时禁用 deprecation 警告(可选) - local original_deprecate = vim.deprecate - vim.deprecate = function(name, alternative, version, plugin, backtrace) - -- 静默处理 deprecation,不输出警告 - -- 如果需要看警告,注释掉这行 - return - end - - -- 禁用有问题的 treesitter highlights(如果遇到错误) - pcall(function() - require('nvim-treesitter.configs').setup { - highlight = { - enable = false, -- 暂时禁用 treesitter 高亮 - }, - } - end) -EOF -endif -``` - -### Step 2: 在主配置中引入补丁 - -在 `config.vim` 的开头添加: - -```vim -" Load compatibility patch for Neovim 0.11+ -if filereadable(expand(':p:h') . '/config-compat.vim') - source :p:h/config-compat.vim -endif -``` - ---- - -## 🎯 推荐的完整解决方案 - -我建议采用**渐进式修复**策略: - -### 1. 立即修复(不影响功能) - -```vim -" 在 config.vim 顶部添加 -if has('nvim-0.11') - " 临时抑制 deprecation 警告 - lua vim.deprecate = function() end - - " 如果遇到 treesitter 错误,禁用它 - lua vim.g.loaded_nvim_treesitter = 1 -endif -``` - -### 2. 中期方案(保持简洁) - -使用经典的 Vim 语法高亮,不依赖 Treesitter: - -```vim -" 使用传统语法高亮(更稳定) -syntax on -filetype plugin indent on - -" 不启用 treesitter -let g:loaded_nvim_treesitter = 1 -``` - -### 3. 长期方案(最佳实践) - -**选项 A**: 等待插件更新 -- YouCompleteMe、ALE、NERDTree 等主流插件会持续更新 -- 定期运行 `:PlugUpdate` 或 `:PackerSync` - -**选项 B**: 迁移到 Neovim 0.10 LTS -- 更稳定的版本 -- 插件兼容性更好 - -**选项 C**: 迁移到现代 Lua 配置 -- 使用 `init.lua` 代替 `init.vim` -- 使用 `nvim-lspconfig` 代替 YCM -- 使用原生 LSP 代替 ALE - ---- - -## 🔍 诊断命令 - -```vim -" 检查 Neovim 版本 -:echo nvim_version() - -" 检查加载的插件 -:scriptnames - -" 运行健康检查 -:checkhealth - -" 查看 treesitter 状态 -:TSInstallInfo - -" 查看 LSP 状态 -:LspInfo -``` - ---- - -## 📦 最小化配置示例 - -如果问题持续,尝试这个最小化配置: - -```vim -" minimal-config.vim - 最小化测试配置 -set number -set expandtab shiftwidth=2 -set termguicolors - -" 禁用所有可能有问题的功能 -let g:loaded_nvim_treesitter = 1 -if has('nvim') - lua vim.deprecate = function() end -endif - -" 只加载必要的插件 -" ... -``` - -测试: -```powershell -nvim -u minimal-config.vim -``` - ---- - -## ✅ 验证修复 - -修复后,运行以下命令验证: - -```vim -:checkhealth -:messages " 查看是否还有警告 -``` - -如果没有错误和警告,说明修复成功! - ---- - -## 📝 注意事项 - -1. **不要盲目禁用所有警告** - 某些警告可能指示真正的问题 -2. **定期更新插件** - 保持插件最新可以避免大多数兼容性问题 -3. **备份配置** - 修改前备份 `~/.config/nvim/` -4. **考虑迁移** - 如果大量问题,考虑迁移到 Lua 配置 - ---- - -**建议**: 先尝试方案 A(快速解决),如果不行再考虑其他方案。 \ No newline at end of file diff --git a/QUICKSTART_LUA.md b/QUICKSTART_LUA.md deleted file mode 100644 index 6f74556..0000000 --- a/QUICKSTART_LUA.md +++ /dev/null @@ -1,200 +0,0 @@ -# ⚡ 快速入门 - Lua 版本 - -## 🚀 三步快速安装 - -### Windows - -```powershell -# 1. 安装配置 -.\install-local-lua.ps1 - -# 2. 运行首次启动助手(重要!) -.\first-launch.ps1 - -# 3. 启动 Neovim -nvim -``` - -### 远程安装 (Windows) - -```powershell -# 一键安装 -Set-ExecutionPolicy Bypass -Scope Process -Force; ` -iwr https://raw.githubusercontent.com/magic-alt/nvim-cpp-ide/main/install-lua.ps1 -UseBasicParsing | iex - -# 然后在 Neovim 中等待插件安装(首次启动 ~2 分钟) -nvim -``` - -### Linux/macOS - -```bash -# 安装 -git clone --depth 1 https://github.com/magic-alt/nvim-cpp-ide.git /tmp/nvim-cpp-ide -mkdir -p ~/.config/nvim -cp /tmp/nvim-cpp-ide/init.lua ~/.config/nvim/init.lua - -# 首次启动(等待插件安装) -nvim -``` - ---- - -## 📋 首次启动后必做 - -### 1. 安装 LSP 服务器 - -在 Neovim 中执行: - -```vim -:Mason -``` - -然后: -- 移动到 `clangd`,按 `i` 安装 -- 移动到 `lua-language-server`,按 `i` 安装 -- 移动到 `clang-format`,按 `i` 安装 -- 移动到 `stylua`,按 `i` 安装 - -或者一键安装: - -```vim -:MasonInstall clangd lua-language-server clang-format stylua -``` - -### 2. 验证安装 - -```vim -:checkhealth -``` - -确保没有红色错误。黄色警告通常可以忽略。 - -### 3. 重启 Neovim - -退出并重新打开 Neovim,享受飞速启动! ⚡ - ---- - -## ⌨️ 常用快捷键 - -### 文件操作 -- `` - 打开/关闭文件树 -- `ff` - 查找文件 (Telescope) -- `fg` - 全局搜索 (Telescope) -- `fb` - 查看缓冲区 - -### LSP 功能 -- `gd` - 跳转到定义 -- `gr` - 查找引用 -- `K` - 查看文档 -- `rn` - 重命名 -- `ca` - 代码操作 -- `lf` - 格式化代码 - -### 诊断导航 -- `[e` 或 `[d` - 上一个错误 -- `]e` 或 `]d` - 下一个错误 -- `e` - 显示行诊断 - -### 代码补全 -- `` - 触发补全 -- `` - 选择下一项 -- `` - 选择上一项 -- `` - 确认选择 - -### 构建/运行 (AsyncRun) -- `` - make test -- `` - make -- `` - make run -- `` - 编译当前文件 -- `` - 打开 QuickFix - -### 查看更多 -- 按 `` (空格键) - 显示所有 leader 键位 -- `:WhichKey` - 查看完整键位映射 - ---- - -## 🔥 测试 LSP 功能 - -### 1. 创建测试文件 - -```cpp -// test.cpp -#include -#include - -int main() { - std::vector nums = {1, 2, 3, 4, 5}; - - for (const auto& num : nums) { - std::cout << num << std::endl; - } - - return 0; -} -``` - -### 2. 测试功能 - -- **补全**: 输入 `std::` 然后按 `` -- **悬停文档**: 将光标放在 `vector` 上按 `K` -- **跳转定义**: 将光标放在 `main` 上按 `gd` -- **格式化**: 按 `lf` - ---- - -## 🎯 性能对比 - -| 指标 | VimScript 版 | Lua 版 | -|------|--------------|--------| -| 启动时间 | ~150ms | **~80ms** ⚡ | -| 内存占用 | ~120MB | **~100MB** 💾 | -| 插件数量 | 6-8 个 | **25 个** 🎁 | -| 补全引擎 | YCM | **原生 LSP** 🚀 | - ---- - -## 📚 进阶学习 - -- **完整迁移指南**: `LUA_MIGRATION_GUIDE.md` -- **首次启动指南**: `FIRST_LAUNCH_GUIDE.md` -- **原始 VimScript 版**: 使用 `.\install-local.ps1` - ---- - -## ❓ 遇到问题? - -### 常见问题 - -1. **"module 'lazy' not found"** - - 运行 `.\first-launch.ps1` 自动修复 - -2. **LSP 不工作** - - 运行 `:Mason` 安装 LSP 服务器 - - 运行 `:LspInfo` 检查状态 - -3. **补全不触发** - - 按 `` 手动触发 - - 确保 LSP 服务器已安装 - -4. **启动很慢** - - 首次启动慢是正常的(安装插件) - - 第二次启动应该很快 (~100ms) - -### 获取帮助 - -```vim -:help lua-guide -:help lsp -:checkhealth -``` - ---- - -## 🎉 开始使用 - -现在你拥有一个现代化的 Neovim C/C++ IDE! - -**开始编码吧!** 🚀 diff --git a/README.md b/README.md index 30ba239..016d680 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,14 @@ https://github.com/magic-alt/nvim-cpp-ide 我们提供了**两个版本**供您选择: -### 🔥 **Lua 版本(推荐 / Recommended for Neovim 0.10+)** -- ⚡ **lazy.nvim** - 极速插件管理 -- 🎯 **Native LSP** - clangd, lua_ls -- 💎 **nvim-cmp** - 现代化补全 -- 🌲 **Treesitter** - 精准语法高亮 -- 📦 **Mason** - LSP 服务器一键安装 -- 🚀 **更快的启动速度** (~80ms vs ~150ms) +### 🔥 **Lua 版本(推荐 / Recommended for Neovim 0.11+)** +- ⚡ **lazy.nvim** - 极速插件管理 +- 🎯 **Native LSP** - clangd, lua_ls +- 💎 **nvim-cmp** - 现代化补全 +- 🌲 **Treesitter** - 精准语法高亮 +- 📦 **Mason** - LSP 服务器一键安装 +- 🚀 **更快的启动速度** (~80ms vs ~150ms) +- ⚠️ **Neovim 0.11+** - 利用 `vim.lsp.config` 原生接口 👉 **[查看 Lua 迁移指南 / See Lua Migration Guide →](LUA_MIGRATION_GUIDE.md)** @@ -43,8 +44,9 @@ https://github.com/magic-alt/nvim-cpp-ide ## ✨ Highlights / 功能亮点 -- 🚀 **One-command setup / 一键部署**:`install.sh` 或内置 `:MagicInstall`(Vim/Neovim 均可)。 -- 💡 **Smart completion**:**YouCompleteMe** tuned for C/C++/Python(2-char trigger,clangd)。 +- 🚀 **One-command setup / 一键部署**:`install.sh` 或内置 `:MagicInstall`(Vim/Neovim 均可)。 +- 🪟 **Unified Windows bootstrap**:`install-lua.ps1` 支持远程安装、本地调试与首次插件同步。 +- 💡 **Smart completion**:**YouCompleteMe** tuned for C/C++/Python(2-char trigger,clangd)。 - 🛡️ **On-the-fly diagnostics**:**ALE** 预置 GCC/C++17/交叉编译参数。 - ⚙️ **Async build/run**:**AsyncRun** 预置 `make test/run`、单文件 GCC 快速编译。 - 🌳 **Project nav**:NERDTree 快速跳转(`e`/`f`/`m`)。 @@ -75,11 +77,13 @@ nvim ``` #### Windows (PowerShell) -```powershell -# 一键安装 Lua 版本 / One-command install (Lua) -Set-ExecutionPolicy Bypass -Scope Process -Force; ` -iwr https://raw.githubusercontent.com/magic-alt/nvim-cpp-ide/main/install-lua.ps1 -UseBasicParsing | iex -``` +```powershell +# 一键安装 Lua 版本 / One-command install (Lua) +Set-ExecutionPolicy Bypass -Scope Process -Force; ` +iwr https://raw.githubusercontent.com/magic-alt/nvim-cpp-ide/main/install-lua.ps1 -UseBasicParsing | iex +``` + +> 脚本会自动备份旧配置、安装最新 `init.lua` 并执行 `Lazy! sync`。如需仅重新引导插件,运行 `.\install-lua.ps1 -FirstLaunchOnly`;本地仓库调试可使用 `.\install-lua.ps1 -Local`(默认会触发同样的首次同步)。 ### 📦 VimScript 版本(兼容 Vim 8.0+ / Neovim 0.8+) @@ -109,12 +113,12 @@ iwr https://raw.githubusercontent.com/magic-alt/nvim-cpp-ide/main/install.ps1 -U ## 🧩 Features Matrix / 配置特性一览 -### Lua 版本 (init.lua - Neovim 0.10+) +### Lua 版本 (init.lua - Neovim 0.11+) | 功能 | 插件 | 说明 | | -------------- | --------------------------------- | ------------------------- | | Plugin Manager | **lazy.nvim** | 懒加载、极速启动 | -| LSP | **nvim-lspconfig**, **mason.nvim** | clangd, lua_ls 原生支持 | +| LSP | **vim.lsp.config** (Neovim 0.11+), **mason.nvim** | clangd, lua_ls 原生支持 | | Completion | **nvim-cmp**, **LuaSnip** | 现代化补全引擎 | | Formatting | **conform.nvim** | clang-format 等一键格式化 | | Diagnostics | Native LSP diagnostics | 实时错误提示 | diff --git a/first-launch.ps1 b/first-launch.ps1 deleted file mode 100644 index f142873..0000000 --- a/first-launch.ps1 +++ /dev/null @@ -1,128 +0,0 @@ -# first-launch.ps1 - 首次启动助手 / First Launch Helper -$ErrorActionPreference = "Stop" - -Write-Host "╔════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan -Write-Host "║ Neovim 首次启动助手 / First Launch Helper ║" -ForegroundColor Cyan -Write-Host "╚════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan -Write-Host "" - -$nvimData = "$env:LOCALAPPDATA\nvim-data" -$lazyPath = "$nvimData\lazy\lazy.nvim" - -Write-Host "检查 Neovim 配置... / Checking Neovim config..." -ForegroundColor Yellow -Write-Host "" - -# 步骤 1: 检查 init.lua -$initLua = "$env:LOCALAPPDATA\nvim\init.lua" -if (-not (Test-Path $initLua)) { - Write-Host "❌ 未找到 init.lua 配置文件" -ForegroundColor Red - Write-Host "请先运行: .\install-local-lua.ps1" -ForegroundColor Yellow - exit 1 -} -Write-Host "✓ 找到 init.lua 配置" -ForegroundColor Green - -# 步骤 2: 手动安装 lazy.nvim(如果需要) -if (-not (Test-Path $lazyPath)) { - Write-Host "" - Write-Host "正在安装 lazy.nvim 插件管理器..." -ForegroundColor Cyan - Write-Host "Installing lazy.nvim plugin manager..." -ForegroundColor DarkGray - - try { - New-Item -ItemType Directory -Force -Path (Split-Path $lazyPath) | Out-Null - - $gitOutput = git clone --filter=blob:none ` - https://github.com/folke/lazy.nvim.git ` - --branch=stable $lazyPath 2>&1 - - if ($LASTEXITCODE -eq 0) { - Write-Host "✓ lazy.nvim 安装成功!" -ForegroundColor Green - } else { - Write-Host "❌ Git 克隆失败" -ForegroundColor Red - Write-Host $gitOutput -ForegroundColor DarkRed - Write-Host "" - Write-Host "可能的原因:" -ForegroundColor Yellow - Write-Host " 1. 网络连接问题" -ForegroundColor White - Write-Host " 2. 防火墙阻止" -ForegroundColor White - Write-Host " 3. Git 未安装或配置不正确" -ForegroundColor White - Write-Host "" - Write-Host "解决方案:" -ForegroundColor Yellow - Write-Host " 1. 检查网络连接" -ForegroundColor White - Write-Host " 2. 尝试使用 VPN 或代理" -ForegroundColor White - Write-Host " 3. 参考 FIRST_LAUNCH_GUIDE.md" -ForegroundColor White - exit 1 - } - } catch { - Write-Host "❌ 安装失败: $_" -ForegroundColor Red - exit 1 - } -} else { - Write-Host "✓ lazy.nvim 已安装" -ForegroundColor Green -} - -# 步骤 3: 同步插件 -Write-Host "" -Write-Host "正在同步插件..." -ForegroundColor Cyan -Write-Host "Synchronizing plugins (this may take 2-5 minutes)..." -ForegroundColor DarkGray -Write-Host "" -Write-Host "⏳ 请耐心等待..." -ForegroundColor Yellow -Write-Host "" - -try { - # 使用 headless 模式强制同步 - $syncOutput = nvim --headless "+Lazy! sync" +qa 2>&1 - - if ($LASTEXITCODE -eq 0 -or $LASTEXITCODE -eq $null) { - Write-Host "✓ 插件同步完成!" -ForegroundColor Green - } else { - Write-Host "⚠️ 同步过程中有一些警告(通常可以忽略)" -ForegroundColor Yellow - Write-Host "Exit code: $LASTEXITCODE" -ForegroundColor DarkYellow - } -} catch { - Write-Host "⚠️ 同步过程中出现错误" -ForegroundColor Yellow - Write-Host $_.Exception.Message -ForegroundColor DarkYellow -} - -# 步骤 4: 验证安装 -Write-Host "" -Write-Host "验证安装..." -ForegroundColor Cyan - -$pluginDirs = Get-ChildItem -Path "$nvimData\lazy" -Directory -ErrorAction SilentlyContinue -if ($pluginDirs) { - Write-Host "✓ 已安装 $($pluginDirs.Count) 个插件" -ForegroundColor Green - Write-Host "" - Write-Host "已安装的插件:" -ForegroundColor DarkGray - $pluginDirs | Select-Object -First 10 | ForEach-Object { - Write-Host " - $($_.Name)" -ForegroundColor DarkGray - } - if ($pluginDirs.Count -gt 10) { - Write-Host " ... 还有 $($pluginDirs.Count - 10) 个插件" -ForegroundColor DarkGray - } -} else { - Write-Host "⚠️ 未检测到已安装的插件" -ForegroundColor Yellow -} - -# 完成 -Write-Host "" -Write-Host "╔════════════════════════════════════════════════════════════════╗" -ForegroundColor Green -Write-Host "║ 🎉 首次设置完成!/ First-time setup complete! ║" -ForegroundColor Green -Write-Host "╚════════════════════════════════════════════════════════════════╝" -ForegroundColor Green -Write-Host "" -Write-Host "下一步 / Next Steps:" -ForegroundColor Cyan -Write-Host "" -Write-Host "1. 启动 Neovim:" -ForegroundColor White -Write-Host " nvim" -ForegroundColor Cyan -Write-Host "" -Write-Host "2. 安装 LSP 服务器 (在 Neovim 中执行):" -ForegroundColor White -Write-Host " :Mason" -ForegroundColor Cyan -Write-Host " 然后按 'i' 安装: clangd, lua-language-server, clang-format" -ForegroundColor DarkGray -Write-Host "" -Write-Host "3. 检查健康状态:" -ForegroundColor White -Write-Host " :checkhealth" -ForegroundColor Cyan -Write-Host "" -Write-Host "4. 查看快捷键:" -ForegroundColor White -Write-Host " 按 (空格键)" -ForegroundColor Cyan -Write-Host "" -Write-Host "📖 阅读完整指南:" -ForegroundColor Magenta -Write-Host " FIRST_LAUNCH_GUIDE.md" -ForegroundColor White -Write-Host " LUA_MIGRATION_GUIDE.md" -ForegroundColor White -Write-Host "" diff --git a/init-modern.lua b/init-modern.lua deleted file mode 100644 index 06800dd..0000000 --- a/init-modern.lua +++ /dev/null @@ -1,499 +0,0 @@ --- init-modern.lua — Neovim 0.11+ 原生 LSP 配置(实验性) --- --- ⚠️ 警告:此配置使用 vim.lsp.config (Neovim 0.11+) --- 这是 Neovim 未来的 LSP 配置方式,但目前还不稳定 --- --- 推荐使用 init.lua(基于 nvim-lspconfig),除非你想尝鲜 --- --- 如果要使用此配置: --- 1. 备份当前 init.lua: mv init.lua init-lspconfig.lua --- 2. 重命名此文件: mv init-modern.lua init.lua --- 3. 重启 Neovim - ------------------------------------------------------------- --- 0) 基础选项(与 init.lua 相同) ------------------------------------------------------------- -vim.g.mapleader = " " -vim.g.maplocalleader = " " - --- 基本设置 -vim.opt.number = true -vim.opt.relativenumber = true -vim.opt.cursorline = true -vim.opt.termguicolors = true -vim.opt.updatetime = 250 -vim.opt.signcolumn = "yes" -vim.opt.hidden = true -vim.opt.mouse = "a" -vim.opt.splitright = true -vim.opt.splitbelow = true -vim.opt.clipboard = "unnamedplus" - --- 缩进和搜索 -vim.opt.expandtab = true -vim.opt.shiftwidth = 2 -vim.opt.tabstop = 2 -vim.opt.softtabstop = 2 -vim.opt.smartindent = true -vim.opt.ignorecase = true -vim.opt.smartcase = true -vim.opt.incsearch = true -vim.opt.hlsearch = true - --- 路径设置 -vim.opt.path:append("**") -vim.opt.wildmenu = true - ------------------------------------------------------------- --- 1) lazy.nvim 插件管理(与 init.lua 相同) ------------------------------------------------------------- -local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" -if not vim.loop.fs_stat(lazypath) then - print("Installing lazy.nvim plugin manager...") - print("This may take a minute on first launch...") - local output = vim.fn.system({ - "git", "clone", "--filter=blob:none", - "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath - }) - - if vim.v.shell_error ~= 0 then - vim.api.nvim_err_writeln("Failed to clone lazy.nvim!") - vim.api.nvim_err_writeln("Please check your Git installation and internet connection.") - vim.api.nvim_err_writeln("Error output: " .. output) - return - end - - print("lazy.nvim installed successfully!") - print("Neovim will now install plugins. Please wait...") -end -vim.opt.rtp:prepend(lazypath) - ------------------------------------------------------------- --- 2) 插件声明(与 init.lua 类似,但不需要 nvim-lspconfig) ------------------------------------------------------------- -local lazy_ok, lazy = pcall(require, "lazy") -if not lazy_ok then - vim.api.nvim_err_writeln("Failed to load lazy.nvim!") - vim.api.nvim_err_writeln("Please restart Neovim or run: :lua vim.fn.delete(vim.fn.stdpath('data') .. '/lazy', 'rf')") - return -end - -lazy.setup({ - -- 配色方案 - { - "tomasr/molokai", - lazy = false, - priority = 1000, - config = function() - vim.cmd([[colorscheme molokai]]) - end, - }, - - -- 文件树 - { - "nvim-tree/nvim-tree.lua", - dependencies = { "nvim-tree/nvim-web-devicons" }, - keys = { - { "", "NvimTreeToggle", desc = "Toggle file tree" }, - { "e", "NvimTreeToggle", desc = "Toggle file tree" }, - { "f", "NvimTreeFindFile", desc = "Find current file" }, - }, - config = function() - vim.g.loaded_netrw = 1 - vim.g.loaded_netrwPlugin = 1 - require("nvim-tree").setup({ - view = { width = 32 }, - renderer = { group_empty = true }, - filters = { dotfiles = false }, - git = { enable = true, ignore = false }, - }) - - -- 兼容命令 - vim.api.nvim_create_user_command("NERDTreeToggle", "NvimTreeToggle", {}) - vim.api.nvim_create_user_command("NERDTreeFind", "NvimTreeFindFile", {}) - end, - }, - - -- 状态栏 - { - "nvim-lualine/lualine.nvim", - dependencies = { "nvim-tree/nvim-web-devicons" }, - config = function() - require("lualine").setup({ options = { theme = "auto" } }) - end, - }, - - -- which-key - { - "folke/which-key.nvim", - event = "VeryLazy", - config = function() - require("which-key").setup({ plugins = { spelling = true } }) - end, - }, - - -- Git 增强 - { - "lewis6991/gitsigns.nvim", - event = { "BufReadPre", "BufNewFile" }, - opts = { - current_line_blame = true, - on_attach = function(bufnr) - local gs = package.loaded.gitsigns - local map = function(mode, lhs, rhs, desc) - vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, desc = desc }) - end - map("n", "]g", gs.next_hunk, "[g]it next hunk") - map("n", "[g", gs.prev_hunk, "[g]it prev hunk") - map("n", "hs", gs.stage_hunk, "[h]unk [s]tage") - map("n", "hr", gs.reset_hunk, "[h]unk [r]eset") - map("n", "hp", gs.preview_hunk, "[h]unk [p]review") - end, - }, - }, - - -- Telescope - { - "nvim-telescope/telescope.nvim", - branch = "0.1.x", - dependencies = { "nvim-lua/plenary.nvim" }, - keys = { - { "ff", function() require("telescope.builtin").find_files() end, desc = "Find files" }, - { "fg", function() require("telescope.builtin").live_grep() end, desc = "Live grep" }, - { "fb", function() require("telescope.builtin").buffers() end, desc = "Buffers" }, - { "fh", function() require("telescope.builtin").help_tags() end, desc = "Help" }, - { "fo", function() require("telescope.builtin").oldfiles() end, desc = "Recent files" }, - }, - config = function() - require("telescope").setup({ defaults = { mappings = { i = { [""] = false, [""] = false } } } }) - end, - }, - - -- Treesitter - { - "nvim-treesitter/nvim-treesitter", - build = ":TSUpdate", - event = { "BufReadPost", "BufNewFile" }, - dependencies = { "nvim-treesitter/nvim-treesitter-textobjects" }, - opts = { - ensure_installed = { "c", "cpp", "lua", "vim", "vimdoc", "query", "python", "bash" }, - auto_install = true, - highlight = { enable = true, additional_vim_regex_highlighting = false }, - indent = { enable = true }, - incremental_selection = { - enable = true, - keymaps = { - init_selection = "", - node_incremental = "", - scope_incremental = false, - node_decremental = "", - }, - }, - }, - config = function(_, opts) - require("nvim-treesitter.configs").setup(opts) - end, - }, - - -- ⚠️ 注意:不再需要 nvim-lspconfig 插件 - -- Neovim 0.11+ 使用内置 vim.lsp.config - - -- Mason(LSP 服务器管理) - { - "williamboman/mason.nvim", - build = ":MasonUpdate", - config = function() - require("mason").setup({ - ui = { - icons = { - package_installed = "✓", - package_pending = "➜", - package_uninstalled = "✗" - } - } - }) - end, - }, - - -- nvim-cmp 补全栈 - { - "hrsh7th/nvim-cmp", - event = "InsertEnter", - dependencies = { - "hrsh7th/cmp-nvim-lsp", - "hrsh7th/cmp-buffer", - "hrsh7th/cmp-path", - "L3MON4D3/LuaSnip", - "saadparwaiz1/cmp_luasnip", - "rafamadriz/friendly-snippets", - }, - }, - - -- 格式化 - { - "stevearc/conform.nvim", - event = { "BufWritePre" }, - keys = { - { - "lf", - function() - require("conform").format({ async = true, lsp_fallback = true }) - end, - mode = { "n", "v" }, - desc = "Format buffer", - }, - }, - opts = { - formatters_by_ft = { - c = { "clang_format" }, - cpp = { "clang_format" }, - lua = { "stylua" }, - python = { "black" }, - }, - format_on_save = nil, - }, - }, - - -- AsyncRun(保留) - { "skywind3000/asyncrun.vim" }, - - -- 注释插件 - { - "numToStr/Comment.nvim", - event = { "BufReadPre", "BufNewFile" }, - config = function() - require("Comment").setup() - end, - }, -}, { - ui = { border = "rounded" }, - performance = { - rtp = { - disabled_plugins = { - "gzip", "tarPlugin", "tohtml", "tutor", "zipPlugin", - }, - }, - }, -}) - ------------------------------------------------------------- --- 3) 使用 vim.lsp.config (Neovim 0.11+ 新方式) ------------------------------------------------------------- - --- nvim-cmp 补全配置 -local cmp = require("cmp") -local luasnip = require("luasnip") -require("luasnip.loaders.from_vscode").lazy_load() - -cmp.setup({ - snippet = { - expand = function(args) - luasnip.lsp_expand(args.body) - end, - }, - window = { - completion = cmp.config.window.bordered(), - documentation = cmp.config.window.bordered(), - }, - mapping = cmp.mapping.preset.insert({ - [""] = cmp.mapping.complete(), - [""] = cmp.mapping.abort(), - [""] = cmp.mapping.confirm({ select = true }), - [""] = cmp.mapping(function(fallback) - if cmp.visible() then cmp.select_next_item() - elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() - else fallback() end - end, { "i", "s" }), - [""] = cmp.mapping(function(fallback) - if cmp.visible() then cmp.select_prev_item() - elseif luasnip.jumpable(-1) then luasnip.jump(-1) - else fallback() end - end, { "i", "s" }), - [""] = cmp.mapping.select_next_item(), - [""] = cmp.mapping.select_prev_item(), - }), - sources = cmp.config.sources({ - { name = "nvim_lsp", priority = 1000 }, - { name = "luasnip", priority = 750 }, - { name = "path", priority = 500 }, - { name = "buffer", priority = 250 }, - }), - formatting = { - format = function(entry, vim_item) - vim_item.menu = ({ - nvim_lsp = "[LSP]", - luasnip = "[Snip]", - buffer = "[Buf]", - path = "[Path]", - })[entry.source.name] - return vim_item - end, - }, -}) - --- 获取补全能力 -local capabilities = require("cmp_nvim_lsp").default_capabilities() - --- 统一 on_attach 函数 -local on_attach = function(client, bufnr) - local map = function(mode, lhs, rhs, desc) - vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, desc = desc }) - end - - -- LSP 功能键位 - map("n", "gd", vim.lsp.buf.definition, "Go to definition") - map("n", "gD", vim.lsp.buf.declaration, "Go to declaration") - map("n", "gr", vim.lsp.buf.references, "References") - map("n", "gi", vim.lsp.buf.implementation, "Implementation") - map("n", "gt", vim.lsp.buf.type_definition, "Type definition") - map("n", "K", vim.lsp.buf.hover, "Hover documentation") - map("n", "", vim.lsp.buf.signature_help, "Signature help") - map("n", "rn", vim.lsp.buf.rename, "Rename symbol") - map({"n","v"}, "ca", vim.lsp.buf.code_action, "Code action") - map({"n","v"}, "lf", function() vim.lsp.buf.format({ async = false }) end, "Format") - - -- 诊断导航 - map("n", "[e", vim.diagnostic.goto_prev, "Prev diagnostic") - map("n", "]e", vim.diagnostic.goto_next, "Next diagnostic") - map("n", "[d", vim.diagnostic.goto_prev, "Prev diagnostic") - map("n", "]d", vim.diagnostic.goto_next, "Next diagnostic") - map("n", "e", vim.diagnostic.open_float, "Line diagnostics") - map("n", "q", vim.diagnostic.setloclist, "Quickfix diagnostics") -end - --- ⚠️ Neovim 0.11+ 新 API(实验性) --- 注意:此 API 可能在未来版本中变化 --- --- 当前状态(2025-10):vim.lsp.config 仍在开发中 --- 推荐继续使用 nvim-lspconfig 直到此 API 稳定 - --- 检查是否支持新 API -if vim.lsp.config then - vim.notify("Using Neovim 0.11+ native LSP config", vim.log.levels.INFO) - - -- 使用新的配置方式 - vim.lsp.config({ - on_attach = on_attach, - capabilities = capabilities, - - servers = { - clangd = { - cmd = { - "clangd", - "--background-index", - "--clang-tidy", - "--header-insertion=iwyu", - "--completion-style=detailed", - "--function-arg-placeholders", - }, - filetypes = { "c", "cpp", "objc", "objcpp", "cuda" }, - }, - - lua_ls = { - settings = { - Lua = { - diagnostics = { globals = { "vim" } }, - workspace = { - library = vim.api.nvim_get_runtime_file("", true), - checkThirdParty = false, - }, - telemetry = { enable = false }, - }, - }, - }, - }, - }) -else - -- 降级到传统方式(需要 nvim-lspconfig 插件) - vim.notify("vim.lsp.config not available, falling back to nvim-lspconfig", vim.log.levels.WARN) - vim.notify("Please use init.lua instead of this file", vim.log.levels.ERROR) - return -end - --- 诊断配置 -vim.diagnostic.config({ - virtual_text = true, - signs = true, - update_in_insert = false, - underline = true, - severity_sort = true, - float = { - border = "rounded", - source = "always", - header = "", - prefix = "", - }, -}) - -local signs = { Error = "✘", Warn = "▲", Hint = "⚑", Info = "»" } -for type, icon in pairs(signs) do - local hl = "DiagnosticSign" .. type - vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = hl }) -end - ------------------------------------------------------------- --- 4) 其他配置(与 init.lua 相同) ------------------------------------------------------------- - --- AsyncRun 快捷键 -vim.g.asyncrun_open = 6 -vim.keymap.set("n", "", ":AsyncRun -save=2 make", { desc = "Make" }) -vim.keymap.set("n", "", ":AsyncRun -save=2 make run", { desc = "Make run" }) -vim.keymap.set("n", "", ":AsyncRun -save=2 make test", { desc = "Make test" }) -vim.keymap.set("n", "", ":cwindow", { desc = "Toggle quickfix" }) - --- F9: 单文件编译 -vim.keymap.set("n", "", function() - local ft = vim.bo.filetype - if ft == "c" then - vim.cmd("AsyncRun -save=2 gcc -O2 -std=c11 % -o %<") - elseif ft == "cpp" then - vim.cmd("AsyncRun -save=2 g++ -O2 -std=c++17 % -o %<") - else - print("No single-file build rule for " .. ft) - end -end, { desc = "Build current file" }) - --- F4: 运行二进制 -vim.keymap.set("n", "", function() - local binary = vim.fn.expand("%:r") - if vim.fn.filereadable(binary) == 1 then - vim.cmd("AsyncRun " .. binary) - else - print("Binary not found. Build first (F9).") - end -end, { desc = "Run current binary" }) - --- 兼容命令 -vim.api.nvim_create_user_command("ALEFix", function() - require("conform").format({ async = false, lsp_fallback = true }) -end, { desc = "Format current buffer (ALEFix compatibility)" }) - --- Tab/Window 管理 -vim.keymap.set("n", "tn", ":tabnew", { desc = "New tab" }) -vim.keymap.set("n", "tc", ":tabclose", { desc = "Close tab" }) -vim.keymap.set("n", "q", ":q", { desc = "Quit" }) - --- 快速编辑 -vim.keymap.set("i", "fj", "", { desc = "Exit insert mode" }) -vim.keymap.set("i", "vv", "", { desc = "Exit insert mode" }) -vim.keymap.set("n", "", "ggVG", { desc = "Select all" }) -vim.keymap.set("n", "k", ":g/^$/d", { desc = "Delete blank lines" }) - --- 注释键位 -vim.keymap.set("n", "cc", function() - return vim.v.count == 0 and "(comment_toggle_linewise_current)" or "(comment_toggle_linewise_count)" -end, { expr = true, desc = "Toggle comment" }) -vim.keymap.set("v", "cc", "(comment_toggle_linewise_visual)", { desc = "Toggle comment" }) - --- 高亮复制文本 -vim.api.nvim_create_autocmd("TextYankPost", { - desc = "Highlight when yanking text", - group = vim.api.nvim_create_augroup("highlight-yank", { clear = true }), - callback = function() - vim.highlight.on_yank() - end, -}) - --- 完成提示 -vim.notify("Neovim modern config loaded (vim.lsp.config)! Press for keybindings.", vim.log.levels.INFO) diff --git a/init.lua b/init.lua index 17433ec..f1ac613 100644 --- a/init.lua +++ b/init.lua @@ -1,15 +1,16 @@ --- init.lua — 最小替换:从 Vim 插件过渡到 Neovim/Lua 生态 --- 目标:保持常用按键/用法不变或提供兼容封装,减少软冲突 --- 替换:YCM/ALE/NERDTree/airline → LSP+nvim-cmp+conform、nvim-tree、lualine --- 保留:AsyncRun、Telescope、gitsigns;新增:nvim-treesitter、which-key (Lua) +-- init.lua — Neovim 0.11+ 原生 LSP 配置(默认启用) +-- +-- 要求:Neovim nightly/0.11+(提供 vim.lsp.config 原生接口) +-- 提示:如果仍在使用 0.10.x 及更早版本,请切换到 `config.vim` +-- 或使用仓库历史版本中的 `init.lua`(基于 nvim-lspconfig)。 ------------------------------------------------------------ --- 0) 基础选项(保持你现有习惯,可按需合并) +-- 0) 基础选项 ------------------------------------------------------------ vim.g.mapleader = " " vim.g.maplocalleader = " " --- 基本设置(从 config.vim 迁移) +-- 基本设置 vim.opt.number = true vim.opt.relativenumber = true vim.opt.cursorline = true @@ -38,7 +39,7 @@ vim.opt.path:append("**") vim.opt.wildmenu = true ------------------------------------------------------------ --- 1) 引导 lazy.nvim(推荐 Neovim 0.9+) +-- 1) lazy.nvim 插件管理 ------------------------------------------------------------ local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not vim.loop.fs_stat(lazypath) then @@ -62,7 +63,7 @@ end vim.opt.rtp:prepend(lazypath) ------------------------------------------------------------ --- 2) 插件声明(最小替换集合) +-- 2) 插件声明(Neovim 0.11+ 原生 LSP 所需组件) ------------------------------------------------------------ local lazy_ok, lazy = pcall(require, "lazy") if not lazy_ok then @@ -72,7 +73,7 @@ if not lazy_ok then end lazy.setup({ - -- 配色方案(保持 molokai 风格) + -- 配色方案 { "tomasr/molokai", lazy = false, @@ -82,82 +83,50 @@ lazy.setup({ end, }, - -- 文件树(替换 NERDTree) + -- 文件树 { "nvim-tree/nvim-tree.lua", dependencies = { "nvim-tree/nvim-web-devicons" }, keys = { - { "", "NvimTreeToggle", desc = "Toggle file tree (NERDTree 习惯)" }, + { "", "NvimTreeToggle", desc = "Toggle file tree" }, { "e", "NvimTreeToggle", desc = "Toggle file tree" }, - { "f", "NvimTreeFindFile", desc = "Find current file in tree" }, + { "f", "NvimTreeFindFile", desc = "Find current file" }, }, config = function() - -- 禁用 netrw(避免冲突) vim.g.loaded_netrw = 1 vim.g.loaded_netrwPlugin = 1 - require("nvim-tree").setup({ view = { width = 32 }, - renderer = { - group_empty = true, - icons = { - show = { - file = true, - folder = true, - folder_arrow = true, - git = true, - }, - }, - }, + renderer = { group_empty = true }, filters = { dotfiles = false }, git = { enable = true, ignore = false }, }) - -- 兼容:提供 :NERDTreeToggle 命令别名 - vim.api.nvim_create_user_command("NERDTreeToggle", function() - vim.cmd("NvimTreeToggle") - end, {}) - vim.api.nvim_create_user_command("NERDTreeFind", function() - vim.cmd("NvimTreeFindFile") - end, {}) + -- 兼容命令 + vim.api.nvim_create_user_command("NERDTreeToggle", "NvimTreeToggle", {}) + vim.api.nvim_create_user_command("NERDTreeFind", "NvimTreeFindFile", {}) end, }, - -- 状态栏(替换 vim-airline) + -- 状态栏 { "nvim-lualine/lualine.nvim", dependencies = { "nvim-tree/nvim-web-devicons" }, config = function() - require("lualine").setup({ - options = { - theme = "auto", - component_separators = { left = '|', right = '|'}, - section_separators = { left = '', right = ''}, - }, - sections = { - lualine_a = {'mode'}, - lualine_b = {'branch', 'diff', 'diagnostics'}, - lualine_c = {'filename'}, - lualine_x = {'encoding', 'fileformat', 'filetype'}, - lualine_y = {'progress'}, - lualine_z = {'location'} - }, - }) + require("lualine").setup({ options = { theme = "auto" } }) end, }, - -- which-key(Lua 版) + -- which-key { "folke/which-key.nvim", event = "VeryLazy", config = function() - require("which-key").setup({ - plugins = { spelling = true }, - }) + require("which-key").setup({ plugins = { spelling = true } }) end, }, - -- Git 增强(保留) + -- Git 增强 { "lewis6991/gitsigns.nvim", event = { "BufReadPre", "BufNewFile" }, @@ -177,7 +146,7 @@ lazy.setup({ }, }, - -- Telescope(保留) + -- Telescope { "nvim-telescope/telescope.nvim", branch = "0.1.x", @@ -190,34 +159,20 @@ lazy.setup({ { "fo", function() require("telescope.builtin").oldfiles() end, desc = "Recent files" }, }, config = function() - require("telescope").setup({ - defaults = { - mappings = { - i = { - [""] = false, - [""] = false, - }, - }, - }, - }) + require("telescope").setup({ defaults = { mappings = { i = { [""] = false, [""] = false } } } }) end, }, - -- Treesitter(替代 vim-cpp-modern 的主力高亮) + -- Treesitter { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate", event = { "BufReadPost", "BufNewFile" }, - dependencies = { - "nvim-treesitter/nvim-treesitter-textobjects", - }, + dependencies = { "nvim-treesitter/nvim-treesitter-textobjects" }, opts = { ensure_installed = { "c", "cpp", "lua", "vim", "vimdoc", "query", "python", "bash" }, auto_install = true, - highlight = { - enable = true, - additional_vim_regex_highlighting = false, - }, + highlight = { enable = true, additional_vim_regex_highlighting = false }, indent = { enable = true }, incremental_selection = { enable = true, @@ -234,8 +189,10 @@ lazy.setup({ end, }, - -- LSP 基座(替换 YCM/ALE 的补全/诊断职责) - { "neovim/nvim-lspconfig" }, + -- ⚠️ 注意:不再需要 nvim-lspconfig 插件 + -- Neovim 0.11+ 使用内置 vim.lsp.config + + -- Mason(LSP 服务器管理) { "williamboman/mason.nvim", build = ":MasonUpdate", @@ -251,15 +208,6 @@ lazy.setup({ }) end, }, - { - "williamboman/mason-lspconfig.nvim", - config = function() - require("mason-lspconfig").setup({ - ensure_installed = { "clangd", "lua_ls" }, - automatic_installation = true, - }) - end, - }, -- nvim-cmp 补全栈 { @@ -275,7 +223,7 @@ lazy.setup({ }, }, - -- 格式化(替代 ALE 的大部分 fixers) + -- 格式化 { "stevearc/conform.nvim", event = { "BufWritePre" }, @@ -296,14 +244,14 @@ lazy.setup({ lua = { "stylua" }, python = { "black" }, }, - format_on_save = nil, -- 禁用自动保存格式化,手动触发 + format_on_save = nil, }, }, - -- AsyncRun(保留原有工作流) + -- AsyncRun(保留) { "skywind3000/asyncrun.vim" }, - -- 注释插件(替代 vim-commentary) + -- 注释插件 { "numToStr/Comment.nvim", event = { "BufReadPre", "BufNewFile" }, @@ -316,21 +264,17 @@ lazy.setup({ performance = { rtp = { disabled_plugins = { - "gzip", - "tarPlugin", - "tohtml", - "tutor", - "zipPlugin", + "gzip", "tarPlugin", "tohtml", "tutor", "zipPlugin", }, }, }, }) ------------------------------------------------------------ --- 3) LSP / 补全 / 诊断:尽量贴近原有快捷键 +-- 3) 使用 vim.lsp.config (Neovim 0.11+ 新方式) ------------------------------------------------------------ --- nvim-cmp 基本配置( 手动补全,回车确认) +-- nvim-cmp 补全配置 local cmp = require("cmp") local luasnip = require("luasnip") require("luasnip.loaders.from_vscode").lazy_load() @@ -350,22 +294,14 @@ cmp.setup({ [""] = cmp.mapping.abort(), [""] = cmp.mapping.confirm({ select = true }), [""] = cmp.mapping(function(fallback) - if cmp.visible() then - cmp.select_next_item() - elseif luasnip.expand_or_jumpable() then - luasnip.expand_or_jump() - else - fallback() - end + if cmp.visible() then cmp.select_next_item() + elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() + else fallback() end end, { "i", "s" }), [""] = cmp.mapping(function(fallback) - if cmp.visible() then - cmp.select_prev_item() - elseif luasnip.jumpable(-1) then - luasnip.jump(-1) - else - fallback() - end + if cmp.visible() then cmp.select_prev_item() + elseif luasnip.jumpable(-1) then luasnip.jump(-1) + else fallback() end end, { "i", "s" }), [""] = cmp.mapping.select_next_item(), [""] = cmp.mapping.select_prev_item(), @@ -389,25 +325,10 @@ cmp.setup({ }, }) ------------------------------------------------------------- --- 3) LSP 配置:使用 nvim-lspconfig (兼容 Neovim 0.11+) ------------------------------------------------------------- - --- 抑制 Neovim 0.11+ 的 lspconfig 过渡警告 --- nvim-lspconfig 团队正在适配新 API,当前版本仍使用旧接口但完全可用 -local notify = vim.notify -vim.notify = function(msg, ...) - if msg:match("lspconfig") then - return - end - notify(msg, ...) -end - --- LSP 服务器配置 -local lspconfig = require("lspconfig") +-- 获取补全能力 local capabilities = require("cmp_nvim_lsp").default_capabilities() --- 统一 on_attach:绑定常用按键(接近 ALE/YCM 习惯) +-- 统一 on_attach 函数 local on_attach = function(client, bufnr) local map = function(mode, lhs, rhs, desc) vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, desc = desc }) @@ -423,11 +344,9 @@ local on_attach = function(client, bufnr) map("n", "", vim.lsp.buf.signature_help, "Signature help") map("n", "rn", vim.lsp.buf.rename, "Rename symbol") map({"n","v"}, "ca", vim.lsp.buf.code_action, "Code action") - map({"n","v"}, "lf", function() - vim.lsp.buf.format({ async = false }) - end, "Format (like ALEFix)") + map({"n","v"}, "lf", function() vim.lsp.buf.format({ async = false }) end, "Format") - -- 诊断导航:模拟 ALE 的 [e / ]e + -- 诊断导航 map("n", "[e", vim.diagnostic.goto_prev, "Prev diagnostic") map("n", "]e", vim.diagnostic.goto_next, "Next diagnostic") map("n", "[d", vim.diagnostic.goto_prev, "Prev diagnostic") @@ -436,40 +355,56 @@ local on_attach = function(client, bufnr) map("n", "q", vim.diagnostic.setloclist, "Quickfix diagnostics") end --- 配置 clangd(C/C++) -lspconfig.clangd.setup({ - capabilities = capabilities, - on_attach = on_attach, - cmd = { - "clangd", - "--background-index", - "--clang-tidy", - "--header-insertion=iwyu", - "--completion-style=detailed", - "--function-arg-placeholders", - }, - filetypes = { "c", "cpp", "objc", "objcpp", "cuda" }, -}) +-- ⚠️ Neovim 0.11+ 新 API(实验性) +-- 注意:此 API 可能在未来版本中变化 +-- +-- 当前状态(2025-10):vim.lsp.config 仍在开发中 +-- 推荐继续使用 nvim-lspconfig 直到此 API 稳定 --- 配置 lua_ls(Lua) -lspconfig.lua_ls.setup({ - capabilities = capabilities, - on_attach = on_attach, - settings = { - Lua = { - diagnostics = { - globals = { "vim" } +-- 检查是否支持新 API +if vim.lsp.config then + vim.notify("Using Neovim 0.11+ native LSP config", vim.log.levels.INFO) + + -- 使用新的配置方式 + vim.lsp.config({ + on_attach = on_attach, + capabilities = capabilities, + + servers = { + clangd = { + cmd = { + "clangd", + "--background-index", + "--clang-tidy", + "--header-insertion=iwyu", + "--completion-style=detailed", + "--function-arg-placeholders", + }, + filetypes = { "c", "cpp", "objc", "objcpp", "cuda" }, }, - workspace = { - library = vim.api.nvim_get_runtime_file("", true), - checkThirdParty = false, + + lua_ls = { + settings = { + Lua = { + diagnostics = { globals = { "vim" } }, + workspace = { + library = vim.api.nvim_get_runtime_file("", true), + checkThirdParty = false, + }, + telemetry = { enable = false }, + }, + }, }, - telemetry = { enable = false }, - } - }, -}) + }, + }) +else + -- 降级到传统方式(需要 nvim-lspconfig 插件) + vim.notify("vim.lsp.config not available, falling back to nvim-lspconfig", vim.log.levels.WARN) + vim.notify("请使用仓库中的 config.vim 或旧版 init.lua(nvim-lspconfig)", vim.log.levels.ERROR) + return +end --- 诊断符号配置(类似 ALE 的错误标记) +-- 诊断配置 vim.diagnostic.config({ virtual_text = true, signs = true, @@ -491,12 +426,11 @@ for type, icon in pairs(signs) do end ------------------------------------------------------------ --- 4) 其他兼容与小功能 +-- 4) 其他配置(沿用经典工作流) ------------------------------------------------------------ --- AsyncRun 快捷键配置(保持原有习惯) +-- AsyncRun 快捷键 vim.g.asyncrun_open = 6 - vim.keymap.set("n", "", ":AsyncRun -save=2 make", { desc = "Make" }) vim.keymap.set("n", "", ":AsyncRun -save=2 make run", { desc = "Make run" }) vim.keymap.set("n", "", ":AsyncRun -save=2 make test", { desc = "Make test" }) @@ -514,7 +448,7 @@ vim.keymap.set("n", "", function() end end, { desc = "Build current file" }) --- F4: 运行当前二进制 +-- F4: 运行二进制 vim.keymap.set("n", "", function() local binary = vim.fn.expand("%:r") if vim.fn.filereadable(binary) == 1 then @@ -524,57 +458,29 @@ vim.keymap.set("n", "", function() end end, { desc = "Run current binary" }) --- 兼容命令:用 conform.nvim 模拟 :ALEFix +-- 兼容命令 vim.api.nvim_create_user_command("ALEFix", function() require("conform").format({ async = false, lsp_fallback = true }) end, { desc = "Format current buffer (ALEFix compatibility)" }) --- Tab/Window 管理(保持原有键位) +-- Tab/Window 管理 vim.keymap.set("n", "tn", ":tabnew", { desc = "New tab" }) vim.keymap.set("n", "tc", ":tabclose", { desc = "Close tab" }) vim.keymap.set("n", "q", ":q", { desc = "Quit" }) --- 快速编辑助手(保持原有习惯) +-- 快速编辑 vim.keymap.set("i", "fj", "", { desc = "Exit insert mode" }) vim.keymap.set("i", "vv", "", { desc = "Exit insert mode" }) vim.keymap.set("n", "", "ggVG", { desc = "Select all" }) vim.keymap.set("n", "k", ":g/^$/d", { desc = "Delete blank lines" }) --- 注释键位(兼容 vim-commentary 习惯) +-- 注释键位 vim.keymap.set("n", "cc", function() return vim.v.count == 0 and "(comment_toggle_linewise_current)" or "(comment_toggle_linewise_count)" end, { expr = true, desc = "Toggle comment" }) vim.keymap.set("v", "cc", "(comment_toggle_linewise_visual)", { desc = "Toggle comment" }) --- MagicInstall 命令(Lua 版本) -vim.api.nvim_create_user_command("MagicInstall", function() - local src = vim.fn.expand("%:p") - if vim.fn.filereadable(src) == 0 then - vim.api.nvim_err_writeln("Open this file from repo root: init.lua") - return - end - - local targets = { - vim.fn.expand("~/.config/nvim/init.lua"), - vim.fn.expand("~/.vim/init.lua"), - } - - for _, target in ipairs(targets) do - local dir = vim.fn.fnamemodify(target, ":h") - vim.fn.mkdir(dir, "p") - - local content = vim.fn.readfile(src) - if vim.fn.writefile(content, target) == 0 then - print("Wrote: " .. target) - else - vim.api.nvim_err_writeln("Failed to write: " .. target) - end - end - - print("MagicInstall complete. Restart Neovim.") -end, { desc = "Install config to common locations" }) - --- 高亮复制的文本 +-- 高亮复制文本 vim.api.nvim_create_autocmd("TextYankPost", { desc = "Highlight when yanking text", group = vim.api.nvim_create_augroup("highlight-yank", { clear = true }), @@ -583,5 +489,5 @@ vim.api.nvim_create_autocmd("TextYankPost", { end, }) --- 最后提示 -vim.notify("Neovim C/C++ IDE config loaded! Press to see leader key bindings.", vim.log.levels.INFO) +-- 完成提示 +vim.notify("Neovim modern config loaded (vim.lsp.config)! Press for keybindings.", vim.log.levels.INFO) diff --git a/install-local-lua.ps1 b/install-local-lua.ps1 deleted file mode 100644 index 5fc14ce..0000000 --- a/install-local-lua.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -# install-local-lua.ps1 - Local test installer (Lua version) -$ErrorActionPreference = "Stop" - -$destNvim = "$HOME\AppData\Local\nvim" -$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path - -Write-Host "╔════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan -Write-Host "║ Neovim C/C++ IDE Local Installer (Lua Edition) ║" -ForegroundColor Cyan -Write-Host "╚════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan -Write-Host "" - -Write-Host "[1/3] Backup old configs..." -ForegroundColor Cyan -if (Test-Path $destNvim) { - $backupName = "$destNvim.bak.$([DateTime]::Now.ToString('yyyyMMdd-HHmmss'))" - Write-Host " Backing up to: $backupName" -ForegroundColor Yellow - Rename-Item $destNvim $backupName - Write-Host " ✓ Backup created" -ForegroundColor Green -} - -Write-Host "[2/3] Install init.lua..." -ForegroundColor Cyan -$luaSource = Join-Path $scriptPath "init.lua" -if (-not (Test-Path $luaSource)) { - Write-Error "init.lua not found in: $scriptPath" - exit 1 -} - -New-Item -ItemType Directory -Force -Path $destNvim | Out-Null -Copy-Item -Force $luaSource "$destNvim\init.lua" -Write-Host " ✓ Installed: $destNvim\init.lua" -ForegroundColor Green - -Write-Host "[3/3] Done!" -ForegroundColor Green -Write-Host "" -Write-Host "╔════════════════════════════════════════════════════════════════╗" -ForegroundColor Yellow -Write-Host "║ ⚠️ 重要: 首次启动需要额外设置! ║" -ForegroundColor Yellow -Write-Host "╠════════════════════════════════════════════════════════════════╣" -ForegroundColor Yellow -Write-Host "║ 请运行首次启动助手来完成插件安装: ║" -ForegroundColor White -Write-Host "║ ║" -ForegroundColor White -Write-Host "║ .\first-launch.ps1 ║" -ForegroundColor Cyan -Write-Host "║ ║" -ForegroundColor White -Write-Host "║ 这将自动安装 lazy.nvim 和所有插件 (~2-5 分钟) ║" -ForegroundColor DarkGray -Write-Host "╚════════════════════════════════════════════════════════════════╝" -ForegroundColor Yellow -Write-Host "" -Write-Host "或者手动启动 Neovim (需要等待插件自动安装):" -ForegroundColor DarkGray -Write-Host " nvim" -ForegroundColor DarkGray -Write-Host "" -Write-Host "📖 详细指南: FIRST_LAUNCH_GUIDE.md" -ForegroundColor Magenta diff --git a/install-lua.ps1 b/install-lua.ps1 index 0f58d33..a21bcf3 100644 --- a/install-lua.ps1 +++ b/install-lua.ps1 @@ -1,119 +1,234 @@ -# install-lua.ps1 - Neovim C/C++ IDE Installer (Lua version) for Windows Param( - [string]$Repo = "magic-alt/nvim-cpp-ide" + [switch]$Local, + [switch]$FirstLaunchOnly, + [switch]$SkipFirstLaunch, + [switch]$NoBackup, + [string]$Repo = "magic-alt/nvim-cpp-ide", + [string]$SourcePath ) $ErrorActionPreference = "Stop" -$ProgressPreference = 'SilentlyContinue' # Speed up web requests +$ProgressPreference = 'SilentlyContinue' $destNvim = "$HOME\AppData\Local\nvim" +$initLuaPath = "$destNvim\init.lua" +$scriptRoot = $PSScriptRoot +if (-not $scriptRoot -and $MyInvocation.MyCommand.Path) { + $scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path +} -Write-Host "╔════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan -Write-Host "║ Neovim C/C++ IDE Installer (Lua + LSP Edition) ║" -ForegroundColor Cyan -Write-Host "║ Modern configuration with lazy.nvim, LSP, and nvim-cmp ║" -ForegroundColor Cyan -Write-Host "╚════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan -Write-Host "" - -Write-Host "[1/4] Backup old configs..." -ForegroundColor Cyan -if (Test-Path $destNvim) { - $backupName = "$destNvim.bak.$([DateTime]::Now.ToString('yyyyMMdd-HHmmss'))" - Write-Host " Backing up existing config to:" -ForegroundColor Yellow - Write-Host " $backupName" -ForegroundColor DarkYellow - Rename-Item $destNvim $backupName - Write-Host " ✓ Backup created" -ForegroundColor Green +function Write-Header { + Write-Host "╔════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan + Write-Host "║ Neovim C/C++ IDE Installer (Lua Edition, Neovim 0.11+) ║" -ForegroundColor Cyan + Write-Host "╚════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan + Write-Host "" } -Write-Host "[2/4] Clone repo..." -ForegroundColor Cyan -$tmp = Join-Path $env:TEMP ([System.Guid]::NewGuid().ToString()) +function Ensure-Git { + if ($script:GitExe) { return $script:GitExe } -# Find working Git installation -$gitExe = $null -$gitPaths = @( - "C:\Program Files\Git\cmd\git.exe", - "C:\Program Files (x86)\Git\cmd\git.exe", - "$env:LOCALAPPDATA\Programs\Git\cmd\git.exe", - "git" # Try PATH -) + $gitPaths = @( + "C:\\Program Files\\Git\\cmd\\git.exe", + "C:\\Program Files (x86)\\Git\\cmd\\git.exe", + "$env:LOCALAPPDATA\\Programs\\Git\\cmd\\git.exe", + "git" + ) -foreach ($gitPath in $gitPaths) { + foreach ($gitCandidate in $gitPaths) { try { - $testGit = if ($gitPath -eq "git") { "git" } else { $gitPath } - $null = & $testGit --version 2>&1 - if ($LASTEXITCODE -eq 0) { - $gitExe = $testGit - if ($gitPath -ne "git") { - Write-Host " Using: $gitPath" -ForegroundColor DarkGray - } - break + $testGit = if ($gitCandidate -eq "git") { "git" } else { $gitCandidate } + $null = & $testGit --version 2>&1 + if ($LASTEXITCODE -eq 0) { + $script:GitExe = $testGit + if ($gitCandidate -ne "git") { + Write-Host " Using Git at: $gitCandidate" -ForegroundColor DarkGray } + return $script:GitExe + } } catch { - continue + continue } + } + + throw "Git not found. Install it first: winget install Git.Git" +} + +function Backup-NvimConfig { + param([string]$Path) + if (-not (Test-Path $Path)) { return } + + $backupName = "$Path.bak.$([DateTime]::Now.ToString('yyyyMMdd-HHmmss'))" + Write-Host " Backing up existing config to:" -ForegroundColor Yellow + Write-Host " $backupName" -ForegroundColor DarkYellow + Rename-Item $Path $backupName + Write-Host " ✓ Backup created" -ForegroundColor Green } -if (-not $gitExe) { - Write-Error "Git not found. Please install Git: winget install Git.Git" - exit 1 +function Install-FromLocal { + param([string]$SourceRoot, [string]$Destination) + + if (-not $SourceRoot) { + throw "Local mode requires -SourcePath or running from a saved script file." + } + + $initSource = Join-Path $SourceRoot "init.lua" + if (-not (Test-Path $initSource)) { + throw "init.lua not found at: $SourceRoot" + } + + New-Item -ItemType Directory -Force -Path $Destination | Out-Null + Copy-Item -Force $initSource (Join-Path $Destination "init.lua") + Write-Host " ✓ Copied init.lua from $SourceRoot" -ForegroundColor Green } -try { - Write-Host " Cloning repository..." -ForegroundColor DarkGray - $cloneArgs = @("clone", "--depth", "1", "https://github.com/$Repo.git", $tmp) - - if ($gitExe -eq "git") { - & git $cloneArgs 2>&1 | Out-Null +function Install-FromRemote { + param([string]$RepoName, [string]$Destination, [string]$GitExe) + + $tmp = Join-Path $env:TEMP ([System.Guid]::NewGuid().ToString()) + Write-Host "[2/3] Clone repo..." -ForegroundColor Cyan + + try { + Write-Host " Cloning https://github.com/$RepoName.git" -ForegroundColor DarkGray + $cloneArgs = @("clone", "--depth", "1", "https://github.com/$RepoName.git", $tmp) + + if ($GitExe -eq "git") { + & git $cloneArgs 2>&1 | Out-Null } else { - & $gitExe $cloneArgs 2>&1 | Out-Null + & $GitExe $cloneArgs 2>&1 | Out-Null } - + if ($LASTEXITCODE -ne 0) { - throw "Git clone failed (exit code: $LASTEXITCODE)" + throw "Git clone failed (exit code: $LASTEXITCODE)" + } + + $initSource = Join-Path $tmp "init.lua" + if (-not (Test-Path $initSource)) { + throw "init.lua not found in repository!" } - - Write-Host " ✓ Clone successful" -ForegroundColor Green -} catch { - Write-Error "Failed to clone repository: $_" - Write-Host "`nTroubleshooting:" -ForegroundColor Yellow - Write-Host " • Ensure Git is installed: winget install Git.Git" -ForegroundColor White - Write-Host " • Check internet connection" -ForegroundColor White - Write-Host " • Try: git config --global http.sslVerify true" -ForegroundColor White - exit 1 + + New-Item -ItemType Directory -Force -Path $Destination | Out-Null + Copy-Item -Force $initSource (Join-Path $Destination "init.lua") + Write-Host " ✓ Installed to: $Destination\init.lua" -ForegroundColor Green + } finally { + Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue + } } -Write-Host "[3/4] Install init.lua..." -ForegroundColor Cyan -$luaSource = Join-Path $tmp "init.lua" -if (-not (Test-Path $luaSource)) { - Write-Error "init.lua not found in repository!" - exit 1 +function Invoke-FirstLaunch { + param([string]$InitPath, [string]$GitExe) + + Write-Host "[First Launch] Preparing environment..." -ForegroundColor Cyan + + if (-not (Test-Path $InitPath)) { + throw "init.lua not found at: $InitPath" + } + Write-Host " ✓ Found init.lua" -ForegroundColor Green + + $nvimCmd = Get-Command nvim -ErrorAction SilentlyContinue + if (-not $nvimCmd) { + throw "Neovim (nvim) not found in PATH. Install Neovim 0.11+ and rerun with -FirstLaunchOnly." + } + + $nvimData = "$env:LOCALAPPDATA\nvim-data" + $lazyPath = "$nvimData\lazy\lazy.nvim" + + if (-not (Test-Path $lazyPath)) { + Write-Host " Installing lazy.nvim plugin manager..." -ForegroundColor Cyan + New-Item -ItemType Directory -Force -Path (Split-Path $lazyPath) | Out-Null + + $cloneArgs = @("clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", $lazyPath) + try { + if ($GitExe -eq "git") { + & git $cloneArgs 2>&1 | Out-Null + } else { + & $GitExe $cloneArgs 2>&1 | Out-Null + } + if ($LASTEXITCODE -ne 0) { + throw "lazy.nvim clone failed (exit code: $LASTEXITCODE)" + } + Write-Host " ✓ lazy.nvim installed" -ForegroundColor Green + } catch { + throw "无法安装 lazy.nvim:$_" + } + } else { + Write-Host " ✓ lazy.nvim already present" -ForegroundColor Green + } + + Write-Host " Synchronizing plugins (Lazy! sync)..." -ForegroundColor Cyan + try { + $syncOutput = & $nvimCmd.Source --headless "+Lazy! sync" +qa 2>&1 + if ($LASTEXITCODE -eq 0 -or $LASTEXITCODE -eq $null) { + Write-Host " ✓ Plugin sync completed" -ForegroundColor Green + } else { + Write-Host " ⚠️ Sync completed with warnings (exit code: $LASTEXITCODE)" -ForegroundColor Yellow + if ($syncOutput) { + Write-Host $syncOutput -ForegroundColor DarkYellow + } + } + } catch { + Write-Host " ⚠️ Failed to run Lazy sync" -ForegroundColor Yellow + Write-Host $_.Exception.Message -ForegroundColor DarkYellow + } + + $pluginRoot = "$nvimData\lazy" + $pluginDirs = Get-ChildItem -Path $pluginRoot -Directory -ErrorAction SilentlyContinue + if ($pluginDirs) { + Write-Host " ✓ Detected $($pluginDirs.Count) plugins" -ForegroundColor Green + $pluginDirs | Select-Object -First 10 | ForEach-Object { + Write-Host " - $($_.Name)" -ForegroundColor DarkGray + } + if ($pluginDirs.Count -gt 10) { + Write-Host " ... and $($pluginDirs.Count - 10) more" -ForegroundColor DarkGray + } + } else { + Write-Host " ⚠️ No plugins detected under $pluginRoot" -ForegroundColor Yellow + } + + Write-Host "" + Write-Host "Next steps:" -ForegroundColor Cyan + Write-Host " 1. Launch Neovim: nvim" -ForegroundColor White + Write-Host " 2. Install recommended LSP servers (in Neovim):" -ForegroundColor White + Write-Host " :MasonInstall clangd lua-language-server clang-format stylua" -ForegroundColor DarkGray + Write-Host " 3. Run health checks: :checkhealth" -ForegroundColor White + Write-Host " 4. Explore keybindings: press (which-key)" -ForegroundColor White +} + +if ($FirstLaunchOnly -and $SkipFirstLaunch) { + throw "-FirstLaunchOnly cannot be combined with -SkipFirstLaunch" } -# Install for Neovim -New-Item -ItemType Directory -Force -Path $destNvim | Out-Null -Copy-Item -Force $luaSource "$destNvim\init.lua" -Write-Host " ✓ Installed to: $destNvim\init.lua" -ForegroundColor Green +Write-Header -# Cleanup -Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue +if (-not $FirstLaunchOnly) { + Write-Host "[1/3] Backup old configs..." -ForegroundColor Cyan + if (-not $NoBackup) { + Backup-NvimConfig -Path $destNvim + } elseif (-not (Test-Path $destNvim)) { + Write-Host " No existing config found" -ForegroundColor DarkGray + } else { + Write-Host " Skipping backup as requested" -ForegroundColor Yellow + Remove-Item -Recurse -Force $destNvim + } + + if ($Local) { + Write-Host "[2/3] Install init.lua from local path..." -ForegroundColor Cyan + $resolvedSource = if ($SourcePath) { $SourcePath } else { $scriptRoot } + Install-FromLocal -SourceRoot $resolvedSource -Destination $destNvim + } else { + $gitExe = Ensure-Git + Install-FromRemote -RepoName $Repo -Destination $destNvim -GitExe $gitExe + } + + Write-Host "[3/3] Installation complete" -ForegroundColor Green + Write-Host "" +} + +if ($SkipFirstLaunch) { + Write-Host "Skipping first-launch bootstrap as requested (-SkipFirstLaunch)." -ForegroundColor Yellow +} else { + $gitExeForBootstrap = Ensure-Git + Invoke-FirstLaunch -InitPath $initLuaPath -GitExe $gitExeForBootstrap +} -Write-Host "[4/4] Installation complete!" -ForegroundColor Green -Write-Host "" -Write-Host "╔════════════════════════════════════════════════════════════════╗" -ForegroundColor Yellow -Write-Host "║ Next Steps: ║" -ForegroundColor Yellow -Write-Host "╠════════════════════════════════════════════════════════════════╣" -ForegroundColor Yellow -Write-Host "║ 1. Run: nvim ║" -ForegroundColor White -Write-Host "║ First launch will auto-install plugins (wait ~2 minutes) ║" -ForegroundColor DarkGray -Write-Host "║ ║" -ForegroundColor White -Write-Host "║ 2. Install LSP servers (in Neovim): ║" -ForegroundColor White -Write-Host "║ :Mason ║" -ForegroundColor Cyan -Write-Host "║ Then press 'i' on: ║" -ForegroundColor DarkGray -Write-Host "║ - clangd (C/C++) ║" -ForegroundColor DarkGray -Write-Host "║ - lua-language-server (Lua) ║" -ForegroundColor DarkGray -Write-Host "║ - clang-format (formatting) ║" -ForegroundColor DarkGray -Write-Host "║ ║" -ForegroundColor White -Write-Host "║ 3. Check health: :checkhealth ║" -ForegroundColor White -Write-Host "║ ║" -ForegroundColor White -Write-Host "║ 4. Learn keybindings: Press in normal mode ║" -ForegroundColor White -Write-Host "╚════════════════════════════════════════════════════════════════╝" -ForegroundColor Yellow -Write-Host "" -Write-Host "📖 Read LUA_MIGRATION_GUIDE.md for detailed migration guide!" -ForegroundColor Magenta Write-Host "" +Write-Host "All done!" -ForegroundColor Green