diff --git a/dot_config/nvim/Readme.md b/dot_config/nvim/Readme.md index 8e7f0d0..ea736ad 100644 --- a/dot_config/nvim/Readme.md +++ b/dot_config/nvim/Readme.md @@ -63,6 +63,28 @@ dot_config/nvim └── Readme.md ``` +## LSP -Language Server Protocol +因為設定方式與結構太過複雜,故獨立開 + +### 和LSP有關的目錄結構 +``` +~/.config/nvim/ +├── lua/ +│ ├── plugins/ +│ │ ├── lsp.lua <-- 所有 LSP / cmp 相關 plugin 定義 +│ ├── lsp/ +│ │ ├── init.lua <-- 初始化 Mason / LSP 等 +│ │ ├── config/ +│ │ │ ├── mason.lua <-- 1. Mason 設定,需要的程式語言安裝都在這定義 +│ │ │ ├── lspconfig.lua <-- 2. 載入各語言的設定 +│ │ │ └── cmp.lua <-- nvim-cmp 設定 +│ │ └── servers/ +│ │ ├── php.lua +│ │ ├── pyright.lua +│ │ └── ... +│ └──(可另外有 config/、keymaps/ 等其他模組) +``` + ## 代找外掛 * Align * diff --git a/dot_config/nvim/exact_lua/exact_plugins/lsp.lua b/dot_config/nvim/exact_lua/exact_plugins/lsp.lua new file mode 100644 index 0000000..a5f8726 --- /dev/null +++ b/dot_config/nvim/exact_lua/exact_plugins/lsp.lua @@ -0,0 +1,50 @@ +-- 專責 LSP / 補全相關 plugin 定義 +return { + -- 依照mason官方教學抄過來 https://github.com/williamboman/mason-lspconfig.nvim + "williamboman/mason.nvim", + "williamboman/mason-lspconfig.nvim", + "neovim/nvim-lspconfig", + + -- 補全相關 + -- 以下為 hrsh7th/nvim-cmp 的官方範例 + -- call plug#begin(s:plug_dir) + -- Plug 'neovim/nvim-lspconfig' + -- Plug 'hrsh7th/cmp-nvim-lsp' + -- Plug 'hrsh7th/cmp-buffer' + -- Plug 'hrsh7th/cmp-path' + -- Plug 'hrsh7th/cmp-cmdline' + -- Plug 'hrsh7th/nvim-cmp' + + -- " For vsnip users. + -- Plug 'hrsh7th/cmp-vsnip' + -- Plug 'hrsh7th/vim-vsnip' + + -- " For luasnip users. + -- " Plug 'L3MON4D3/LuaSnip' + -- " Plug 'saadparwaiz1/cmp_luasnip' + + -- " For mini.snippets users. + -- " Plug 'echasnovski/mini.snippets' + -- " Plug 'abeldekat/cmp-mini-snippets' + + -- " For ultisnips users. + -- " Plug 'SirVer/ultisnips' + -- " Plug 'quangnguyen30192/cmp-nvim-ultisnips' + + -- " For snippy users. + -- " Plug 'dcampos/nvim-snippy' + -- " Plug 'dcampos/cmp-snippy' + + -- call plug#end() + { "hrsh7th/cmp-nvim-lsp" }, + { "hrsh7th/cmp-buffer" }, + { "hrsh7th/cmp-path" }, + { "hrsh7th/cmp-cmdline" }, + { "hrsh7th/nvim-cmp" }, + + -- " For luasnip users. + { "L3MON4D3/LuaSnip" }, + { "saadparwaiz1/cmp_luasnip" }, + + { "rafamadriz/friendly-snippets" }, +} diff --git a/dot_config/nvim/exact_lua/init.lua b/dot_config/nvim/exact_lua/init.lua index e4f0fbb..d56ae60 100644 --- a/dot_config/nvim/exact_lua/init.lua +++ b/dot_config/nvim/exact_lua/init.lua @@ -3,5 +3,6 @@ require("config.options") require("config.keymaps_nvim") require("config.keymaps") require("config.gui") -require("config.lazy") +require("config.lazy") -- 初始化 Lazy.nvim +require("lsp") -- LSP 與 cmp 設定 require("config.terminal") -- 因為會被lazy.nvim override,所以要放在最後 diff --git a/dot_config/nvim/exact_lua/lsp/exact_config/cmp.lua b/dot_config/nvim/exact_lua/lsp/exact_config/cmp.lua new file mode 100644 index 0000000..41be11f --- /dev/null +++ b/dot_config/nvim/exact_lua/lsp/exact_config/cmp.lua @@ -0,0 +1,84 @@ +-- Set up nvim-cmp. +local cmp = require'cmp' + +cmp.setup({ + snippet = { + -- REQUIRED - you must specify a snippet engine + expand = function(args) + vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users. + require('luasnip').lsp_expand(args.body) -- For `luasnip` users. + -- require('snippy').expand_snippet(args.body) -- For `snippy` users. + -- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users. + -- vim.snippet.expand(args.body) -- For native neovim snippets (Neovim v0.10+) + + -- For `mini.snippets` users: + -- local insert = MiniSnippets.config.expand.insert or MiniSnippets.default_insert + -- insert({ body = args.body }) -- Insert at cursor + -- cmp.resubscribe({ "TextChangedI", "TextChangedP" }) + -- require("cmp.config").set_onetime({ sources = {} }) + end, + }, + window = { + -- completion = cmp.config.window.bordered(), + -- documentation = cmp.config.window.bordered(), + }, + mapping = cmp.mapping.preset.insert({ + [''] = cmp.mapping.scroll_docs(-4), + [''] = cmp.mapping.scroll_docs(4), + [''] = cmp.mapping.complete(), + [''] = cmp.mapping.abort(), + [''] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items. + + -- AI範例: + -- [""] = cmp.mapping.select_next_item(), + -- [""] = cmp.mapping.select_prev_item(), + -- [""] = cmp.mapping.confirm({ select = true }), + }), + sources = cmp.config.sources({ + { name = 'nvim_lsp' }, + -- { name = 'vsnip' }, -- For vsnip users. + { name = 'luasnip' }, -- For luasnip users. + -- { name = 'ultisnips' }, -- For ultisnips users. + -- { name = 'snippy' }, -- For snippy users. + }, { + { name = 'buffer' }, + }) +}) + +-- To use git you need to install the plugin petertriho/cmp-git and uncomment lines below +-- Set configuration for specific filetype. +--[[ cmp.setup.filetype('gitcommit', { + sources = cmp.config.sources({ + { name = 'git' }, + }, { + { name = 'buffer' }, + }) +}) +require("cmp_git").setup() ]]-- + +-- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore). +cmp.setup.cmdline({ '/', '?' }, { + mapping = cmp.mapping.preset.cmdline(), + sources = { + { name = 'buffer' } + } +}) + +-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore). +cmp.setup.cmdline(':', { + mapping = cmp.mapping.preset.cmdline(), + sources = cmp.config.sources({ + { name = 'path' } + }, { + { name = 'cmdline' } + }), + matching = { disallow_symbol_nonprefix_matching = false } +}) + +-- 已經由lspconfig.lua來處理,故註解掉 +-- -- Set up lspconfig. +-- local capabilities = require('cmp_nvim_lsp').default_capabilities() +-- -- Replace with each lsp server you've enabled. +-- require('lspconfig')[''].setup { +-- capabilities = capabilities +-- } diff --git a/dot_config/nvim/exact_lua/lsp/exact_config/lspconfig.lua b/dot_config/nvim/exact_lua/lsp/exact_config/lspconfig.lua new file mode 100644 index 0000000..88dcaff --- /dev/null +++ b/dot_config/nvim/exact_lua/lsp/exact_config/lspconfig.lua @@ -0,0 +1,31 @@ +local lspconfig = require("lspconfig") +local capabilities = require("cmp_nvim_lsp").default_capabilities() + +local on_attach = function(_, bufnr) + local map = function(mode, lhs, rhs) + vim.keymap.set(mode, lhs, rhs, { buffer = bufnr }) + end + map("n", "gd", vim.lsp.buf.definition) + map("n", "K", vim.lsp.buf.hover) +end + +local servers = { + "phpactor", + "pyright", + "gopls", + "html", + "cssls", + -- "tsserver", -- TODO: tsserver is deprecated, use ts_ls instead. +} + +-- 載入所有的對應的 LSP server 設定 +-- +-- 相關設定請看 +-- +for _, name in ipairs(servers) do + local ok, config = pcall(require, "lsp.servers." .. name) + if not ok then config = {} end + config.capabilities = capabilities + config.on_attach = on_attach + lspconfig[name].setup(config) +end diff --git a/dot_config/nvim/exact_lua/lsp/exact_config/mason.lua b/dot_config/nvim/exact_lua/lsp/exact_config/mason.lua new file mode 100644 index 0000000..11e77db --- /dev/null +++ b/dot_config/nvim/exact_lua/lsp/exact_config/mason.lua @@ -0,0 +1,35 @@ +require("mason").setup() +require("mason-lspconfig").setup { + -- A list of servers to automatically install if they're not already installed. Example: { "rust_analyzer@nightly", "lua_ls" } + -- This setting has no relation with the `automatic_installation` setting. + ---@type string[] + ensure_installed = { + -- "lua_ls", "rust_analyzer" -- 官方範例 + "phpactor", + "pyright", + "gopls", + "html", + "cssls", + "tsserver", + }, + + -- Whether servers that are set up (via lspconfig) should be automatically installed if they're not already installed. + -- This setting has no relation with the `ensure_installed` setting. + -- Can either be: + -- - false: Servers are not automatically installed. + -- - true: All servers set up via lspconfig are automatically installed. + -- - { exclude: string[] }: All servers set up via lspconfig, except the ones provided in the list, are automatically installed. + -- Example: automatic_installation = { exclude = { "rust_analyzer", "solargraph" } } + ---@type boolean + automatic_installation = false, + + -- See `:h mason-lspconfig.setup_handlers()` + ---@type table? + handlers = nil, +} + +-- 下面這段先註解掉,由lspconfig.lua來處理 +-- -- After setting up mason-lspconfig you may set up servers via lspconfig +-- require("lspconfig").lua_ls.setup {} +-- require("lspconfig").rust_analyzer.setup {} +-- -- ... diff --git a/dot_config/nvim/exact_lua/lsp/exact_servers/phpactor.lua b/dot_config/nvim/exact_lua/lsp/exact_servers/phpactor.lua new file mode 100644 index 0000000..c015f5f --- /dev/null +++ b/dot_config/nvim/exact_lua/lsp/exact_servers/phpactor.lua @@ -0,0 +1,17 @@ +return { + init_options = { + ["language_server_phpstan.enabled"] = true, + ["language_server_psalm.enabled"] = false, + } + -- settings = { + -- -- 自訂 PHPactor 設定(如果有的話) + -- }, +} + +-- 僅對照用 +-- require("lspconfig").phpactor.setup({ +-- init_options = { +-- ["language_server_phpstan.enabled"] = true, +-- ["language_server_psalm.enabled"] = false, +-- } +-- }) diff --git a/dot_config/nvim/exact_lua/lsp/init.lua b/dot_config/nvim/exact_lua/lsp/init.lua new file mode 100644 index 0000000..2a74f2c --- /dev/null +++ b/dot_config/nvim/exact_lua/lsp/init.lua @@ -0,0 +1,3 @@ +require("lsp.config.mason") +require("lsp.config.lspconfig") +require("lsp.config.cmp")