From f059534f62594152eee8d74c5c2dae1a7284fbfe Mon Sep 17 00:00:00 2001 From: "RingOfStorms (Joshua Bell)" Date: Sun, 16 Jul 2023 19:38:55 -0500 Subject: [PATCH] rust better --- lua/plugins/lsp.lua | 449 +++++++++++++++------------- lua/plugins/null-ls.lua | 130 ++++---- lua/plugins/rust-tools.lua | 5 - lua/plugins_disabled/rust-tools.lua | 9 + 4 files changed, 323 insertions(+), 270 deletions(-) delete mode 100644 lua/plugins/rust-tools.lua create mode 100644 lua/plugins_disabled/rust-tools.lua diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index e7d4eed..d6e4117 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -1,228 +1,249 @@ +function prereqs() + local output = vim.fn.system({ + "which", + "rust-analyzer", + "&&", + "rust-analyzer", + "--version", + }) + if output == nil or output == "" or string.find(output, "not installed for the toolchain") then + print("Installing rust-analyzer globally with rustup") + vim.fn.system({ + "rustup", "component", "add", "rust-analyzer" + }) + end +end + local servers = { - rust_analyzer = { - -- rust - -- to enable rust-analyzer settings visit: - -- https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/generated_config.adoc - ["rust-analyzer"] = { - cargo = { - allFeatures = true, - }, - checkOnSave = { - allFeatures = true, - command = "clippy", - }, - }, - }, - tsserver = { - -- typescript/javascript - }, - pyright = { - -- python - }, - lua_ls = { - -- lua - Lua = { - workspace = { checkThirdParty = false }, - telemetry = { enable = false }, - }, - }, - bashls = { - -- bash - }, - cssls = { - -- css - }, - cssmodules_ls = { - -- css modules - }, - dockerls = { - -- docker - }, - docker_compose_language_service = { - -- docker compose - }, - jsonls = { - -- json - }, - marksman = { - -- markdown - }, - taplo = { - -- toml - }, - yamlls = { - -- yaml - }, - lemminx = { - -- xml - }, - rnix = { - -- Nix - }, - ansiblels = { - -- ansible - }, + -- rust_analyzer = USES RUST_TOOLS INSTEAD, SEE BOTTOM OF THIS FILE + tsserver = { + -- typescript/javascript + }, + pyright = { + -- python + }, + lua_ls = { + -- lua + Lua = { + workspace = { checkThirdParty = false }, + telemetry = { enable = false }, + }, + }, + bashls = { + -- bash + }, + cssls = { + -- css + }, + cssmodules_ls = { + -- css modules + }, + dockerls = { + -- docker + }, + docker_compose_language_service = { + -- docker compose + }, + jsonls = { + -- json + }, + marksman = { + -- markdown + }, + taplo = { + -- toml + }, + yamlls = { + -- yaml + }, + lemminx = { + -- xml + }, + rnix = { + -- Nix + }, + ansiblels = { + -- ansible + }, } -- LSP config -- Took lots of inspiration from this kickstart lua file: https://github.com/hjr3/dotfiles/blob/main/.config/nvim/init.lua +-- This function gets run when an LSP connects to a particular buffer. +local on_attach = function(client, bufnr) + local nmap = function(keys, func, desc) + if desc then + desc = "LSP: " .. desc + end + + vim.keymap.set("n", keys, func, { buffer = bufnr, desc = desc }) + end + + nmap("lr", vim.lsp.buf.rename, "[R]ename") + nmap("la", vim.lsp.buf.code_action, "Code [A]ction") + + nmap("gd", vim.lsp.buf.definition, "[G]oto [D]efinition") + nmap("gr", require("telescope.builtin").lsp_references, "[G]oto [R]eferences") + nmap("gI", vim.lsp.buf.implementation, "[G]oto [I]mplementation") + nmap("D", vim.lsp.buf.type_definition, "Type [D]efinition") + + -- See `:help K` for why this keymap + nmap("K", vim.lsp.buf.hover, "Hover Documentation") + nmap("", vim.lsp.buf.signature_help, "Signature Documentation") + + -- Lesser used LSP functionality + nmap("gD", vim.lsp.buf.declaration, "[G]oto [D]eclaration") + + -- disable tsserver so it does not conflict with prettier + if client.name == "tsserver" then + client.server_capabilities.document_formatting = false + end +end + return { - { - -- Autocompletion - "hrsh7th/nvim-cmp", - dependencies = { - "hrsh7th/cmp-nvim-lsp", - "L3MON4D3/LuaSnip", - "saadparwaiz1/cmp_luasnip", - "hrsh7th/cmp-buffer", - "hrsh7th/cmp-path", - }, - }, - { - "williamboman/mason.nvim", - cmd = { - "Mason", - "MasonUpdate", - "MasonInstall", - "MasonInstallAll", - "MasonUninstall", - "MasonUninstallAll", - "MasonLog", - }, - build = ":MasonUpdate", - opts = {}, - }, - { - "williamboman/mason-lspconfig.nvim", - }, - { "folke/neodev.nvim", opts = {} }, - { - "neovim/nvim-lspconfig", - dependencies = { "nvim-telescope/telescope.nvim" }, - config = function() - local config = require("lspconfig") - local util = require("lspconfig/util") - local mason_lspconfig = require("mason-lspconfig") - local cmp = require("cmp") - local luasnip = require("luasnip") + { + "lvimuser/lsp-inlayhints.nvim", + }, + { + -- Autocompletion + "hrsh7th/nvim-cmp", + dependencies = { + "hrsh7th/cmp-nvim-lsp", + "L3MON4D3/LuaSnip", + "saadparwaiz1/cmp_luasnip", + "hrsh7th/cmp-buffer", + "hrsh7th/cmp-path", + --"Saecki/crates.nvim", -- SEE plugins/rust-tools.lua + }, + }, + { + "williamboman/mason.nvim", + cmd = { + "Mason", + "MasonUpdate", + "MasonInstall", + "MasonInstallAll", + "MasonUninstall", + "MasonUninstallAll", + "MasonLog", + }, + build = ":MasonUpdate", + opts = {}, + }, + { + "williamboman/mason-lspconfig.nvim", + }, + { + "neovim/nvim-lspconfig", + dependencies = { "nvim-telescope/telescope.nvim" }, + config = function() + local config = require("lspconfig") + local util = require("lspconfig/util") + local mason_lspconfig = require("mason-lspconfig") + local cmp = require("cmp") + local luasnip = require("luasnip") - -- LSP - -- This function gets run when an LSP connects to a particular buffer. - local on_attach = function(client, bufnr) - local nmap = function(keys, func, desc) - if desc then - desc = "LSP: " .. desc - end + -- LSP + -- nvim-cmp supports additional completion capabilities, so broadcast that to servers + local capabilities = vim.lsp.protocol.make_client_capabilities() + capabilities = require("cmp_nvim_lsp").default_capabilities(capabilities) - vim.keymap.set("n", keys, func, { buffer = bufnr, desc = desc }) - end + -- Install servers used + mason_lspconfig.setup({ + ensure_installed = vim.tbl_keys(servers), + }) - nmap("lr", vim.lsp.buf.rename, "[R]ename") - nmap("la", vim.lsp.buf.code_action, "Code [A]ction") + local flags = { + allow_incremental_sync = true, + debounce_text_changes = 200, + } - nmap("gd", vim.lsp.buf.definition, "[G]oto [D]efinition") - nmap("gr", require("telescope.builtin").lsp_references, "[G]oto [R]eferences") - nmap("gI", vim.lsp.buf.implementation, "[G]oto [I]mplementation") - nmap("D", vim.lsp.buf.type_definition, "Type [D]efinition") + mason_lspconfig.setup_handlers({ + function(server_name) + config[server_name].setup({ + flags = flags, + capabilities = capabilities, + on_attach = on_attach, + settings = servers[server_name], + }) + end, + }) - -- See `:help K` for why this keymap - nmap("K", vim.lsp.buf.hover, "Hover Documentation") - nmap("", vim.lsp.buf.signature_help, "Signature Documentation") + -- Completion + luasnip.config.setup({}) - -- Lesser used LSP functionality - nmap("gD", vim.lsp.buf.declaration, "[G]oto [D]eclaration") - - -- disable tsserver so it does not conflict with prettier - if client.name == "tsserver" then - client.server_capabilities.document_formatting = false - end - end - - -- nvim-cmp supports additional completion capabilities, so broadcast that to servers - local capabilities = vim.lsp.protocol.make_client_capabilities() - capabilities = require("cmp_nvim_lsp").default_capabilities(capabilities) - - -- Install servers used - mason_lspconfig.setup({ - ensure_installed = vim.tbl_keys(servers), - }) - - local flags = { - allow_incremental_sync = true, - debounce_text_changes = 200, - } - - mason_lspconfig.setup_handlers({ - function(server_name) - require("lspconfig")[server_name].setup({ - flags = flags, - capabilities = capabilities, - on_attach = on_attach, - settings = servers[server_name], - }) - end, - }) - - -- Completion - luasnip.config.setup({}) - - cmp.setup({ - snippet = { - expand = function(args) - luasnip.lsp_expand(args.body) - end, - }, - mapping = cmp.mapping.preset.insert({ - [""] = cmp.mapping.select_next_item(), - [""] = cmp.mapping.select_prev_item(), - [""] = cmp.mapping.scroll_docs(-4), - [""] = cmp.mapping.scroll_docs(4), - [""] = cmp.mapping.complete({}), - [""] = cmp.mapping.confirm({ - behavior = cmp.ConfirmBehavior.Replace, - 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" }), - }), - sources = { - { name = "nvim_lsp", priority = 8 }, - { nane = "buffer", priority = 7 }, - { name = "luasnip", priority = 6 }, - { name = "path" }, - }, - sorting = { - priority_weight = 1, - comparators = { - cmp.config.compare.locality, - cmp.config.compare.recently_used, - cmp.config.compare.score, - cmp.config.compare.offset, - cmp.config.compare.order, - }, - }, - window = { - completion = cmp.config.window.bordered(), - documentation = cmp.config.window.bordered(), - }, - }) - end, - }, + cmp.setup({ + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) + end, + }, + mapping = cmp.mapping.preset.insert({ + [""] = cmp.mapping.select_next_item(), + [""] = cmp.mapping.select_prev_item(), + [""] = cmp.mapping.scroll_docs(-4), + [""] = cmp.mapping.scroll_docs(4), + [""] = cmp.mapping.complete({}), + [""] = cmp.mapping.confirm({ + behavior = cmp.ConfirmBehavior.Replace, + 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" }), + }), + sources = { + { name = "nvim_lsp", priority = 8 }, + { nane = "buffer", priority = 7 }, + { name = "luasnip", priority = 6 }, + { name = "path" }, + { name = "crates" }, + }, + sorting = { + priority_weight = 1, + comparators = { + cmp.config.compare.locality, + cmp.config.compare.recently_used, + cmp.config.compare.score, + cmp.config.compare.offset, + cmp.config.compare.order, + }, + }, + window = { + completion = cmp.config.window.bordered(), + documentation = cmp.config.window.bordered(), + }, + }) + end, + }, + { "folke/neodev.nvim", opts = {} }, -- lua stuff + { -- Rust tools + "simrat39/rust-tools.nvim", + build = prereqs, + opts = { + server = { + on_attach = on_attach + }, + }, + --config = function(_, opts) + --require('rust-tools').setup(opts) + --end + }, + { "Saecki/crates.nvim", tag = "v0.3.0", dependencies = { "nvim-lua/plenary.nvim" }, opts = {} }, } diff --git a/lua/plugins/null-ls.lua b/lua/plugins/null-ls.lua index 8dc6e5e..0d05ac0 100644 --- a/lua/plugins/null-ls.lua +++ b/lua/plugins/null-ls.lua @@ -1,60 +1,88 @@ function prereqs() - local output = vim.fn.system({ - "which", - "cspell", - }) - if output == nil or output == "" then - print("Installing cspell globally with npm") - vim.fn.system({ - "npm", - "install", - "-g", - "cspell@latest", - }) - end + local output = vim.fn.system({ + "which", + "cspell", + }) + if output == nil or output == "" then + print("Installing cspell globally with npm") + vim.fn.system({ + "npm", + "install", + "-g", + "cspell@latest", + }) + end end return { - { - "jose-elias-alvarez/null-ls.nvim", - dependencies = { "williamboman/mason.nvim" }, + { + "jose-elias-alvarez/null-ls.nvim", + dependencies = { "williamboman/mason.nvim" }, build = prereqs, - opts = function(_, config) - -- config variable is the default definitions table for the setup function call - local null_ls = require("null-ls") + opts = function(_, config) + -- config variable is the default definitions table for the setup function call + local null_ls = require("null-ls") - -- Check supported formatters and linters - -- https://github.com/jose-elias-alvarez/null-ls.nvim/tree/main/lua/null-ls/builtins/formatting - -- https://github.com/jose-elias-alvarez/null-ls.nvim/tree/main/lua/null-ls/builtins/diagnostics - config.sources = { - -- Set a formatter - null_ls.builtins.formatting.prettier, -- typescript/javascript - null_ls.builtins.formatting.stylua, - null_ls.builtins.formatting.rustfmt, - null_ls.builtins.formatting.black, -- python - -- null_ls.builtins.code_actions.proselint, -- TODO looks interesting - null_ls.builtins.code_actions.cspell.with({ - config = { - find_json = function() - return vim.fn.findfile("cspell.json", vim.fn.environ().HOME .. "/.config/nvim/lua/user/;") - end, - }, - }), - null_ls.builtins.diagnostics.cspell.with({ - extra_args = { "--config", "~/.config/nvim/lua/user/cspell.json" }, - }), - } + -- Custom rust formatter: genemichaels first, then rustfmt, nightly if experimental + local rust_formatter_genemichaels = { + name = "rust_formatter_genemichaels", + method = null_ls.methods.FORMATTING, + filetypes = { "rust" }, + generator = null_ls.formatter({ + command = "genemichaels", + args = { '-q' }, + to_stdin = true, + }), + } + -- ╰─ cat src/main.rs| rustfmt --emit=stdout --edition=2021 --color=never + local rust_formatter_rustfmt = { + name = "rust_formatter_rustfmt", + method = null_ls.methods.FORMATTING, + filetypes = { "rust" }, + generator = null_ls.formatter({ + command = "rustfmt", + args = { '--emit=stdout', "--edition=$(grep edition Cargo.toml | awk '{print substr($3,2,length($3)-2)}')", + '--color=never' }, + to_stdin = true, + }), + } - config.update_in_insert = true - config.debug = true + null_ls.register(rust_formatter_genemichaels) + null_ls.register(rust_formatter_rustfmt) - return config - end, - }, - { - "jay-babu/mason-null-ls.nvim", - opts = { - ensure_installed = { "rustfmt", "stylelua", "prettier", "black" }, - }, - }, + -- Check supported formatters and linters + -- https://github.com/jose-elias-alvarez/null-ls.nvim/tree/main/lua/null-ls/builtins/formatting + -- https://github.com/jose-elias-alvarez/null-ls.nvim/tree/main/lua/null-ls/builtins/diagnostics + config.sources = { + null_ls.builtins.formatting.prettier, -- typescript/javascript + null_ls.builtins.formatting.stylua, -- lua + --null_ls.builtins.formatting.rustfmt, -- rust + rust_formatter_genemichaels, -- order matters, we run genemichaels first then rustfmt + rust_formatter_rustfmt, + null_ls.builtins.formatting.black, -- python + -- null_ls.builtins.code_actions.proselint, -- TODO looks interesting + null_ls.builtins.code_actions.cspell.with({ + config = { + find_json = function() + return vim.fn.findfile("cspell.json", vim.fn.environ().HOME .. "/.config/nvim/lua/user/;") + end, + }, + }), + null_ls.builtins.diagnostics.cspell.with({ + extra_args = { "--config", "~/.config/nvim/lua/user/cspell.json" }, + }), + } + + config.update_in_insert = true + config.debug = true + + return config + end, + }, + { + "jay-babu/mason-null-ls.nvim", + opts = { + ensure_installed = { "rustfmt", "stylelua", "prettier", "black" }, + }, + }, } diff --git a/lua/plugins/rust-tools.lua b/lua/plugins/rust-tools.lua deleted file mode 100644 index 0e80b5a..0000000 --- a/lua/plugins/rust-tools.lua +++ /dev/null @@ -1,5 +0,0 @@ -return { - "simrat39/rust-tools.nvim", - event = "BufEnter *.rs", - dependencies = { "mason-lspconfig.nvim", "lvimuser/lsp-inlayhints.nvim" }, -} diff --git a/lua/plugins_disabled/rust-tools.lua b/lua/plugins_disabled/rust-tools.lua new file mode 100644 index 0000000..bdd55f4 --- /dev/null +++ b/lua/plugins_disabled/rust-tools.lua @@ -0,0 +1,9 @@ +return { + { + "simrat39/rust-tools.nvim", + event = "BufEnter *.rs", + dependencies = { "mason-lspconfig.nvim", "lvimuser/lsp-inlayhints.nvim" }, + opts = {}, + }, + { "Saecki/crates.nvim", tag = "v0.3.0", dependencies = { "nvim-lua/plenary.nvim" }, opts = {} }, +}