all the languages!

This commit is contained in:
RingOfStorms (Joshua Bell) 2024-05-03 18:56:57 -05:00
parent 1eb427a6dc
commit eb7f522795
14 changed files with 630 additions and 548 deletions

View file

@ -61,9 +61,7 @@ rm -rf ~/.local/state/nvim
## NOTES/TODOS
- h/l movement broken in insert mode, probably due to cmp hotkeys
- h/l in telescope
- arrows still work in insert mode and telescope, need to remove trying to break arrow key habit
- See what linters/formaters to add or are the LSP's enough?
FUTURE

View file

@ -87,7 +87,14 @@
"nvim_plugin-saadparwaiz1/cmp_luasnip" = cmp_luasnip;
"nvim_plugin-hrsh7th/cmp-nvim-lsp" = cmp-nvim-lsp;
"nvim_plugin-hrsh7th/cmp-path" = cmp-path;
"nvim_plugin-hrsh7th/cmp-buffer" = cmp-buffer;
"nvim_plugin-zbirenbaum/copilot-cmp" = copilot-cmp;
"nvim_plugin-zbirenbaum/copilot.lua" = copilot-lua;
"nvim_plugin-folke/neodev.nvim" = neodev-nvim;
"nvim_plugin-mrcjkb/rustaceanvim" = rustaceanvim;
"nvim_plugin-Saecki/crates.nvim" = crates-nvim;
"nvim_plugin-lvimuser/lsp-inlayhints.nvim" = lsp-inlayhints-nvim;
"nvim_plugin-rafamadriz/friendly-snippets" = friendly-snippets;
};
# This will be how we put any nix related stuff into our lua config
luaNixGlobal =
@ -113,6 +120,11 @@
fzf # search fuzzy
tree-sitter
glow # markdown renderer
# curl # http requests TODO
# nodePackages.cspell TODO
];
defaultRuntimeDependencies = with pkgs; [
# linters
markdownlint-cli
luajitPackages.luacheck
@ -121,14 +133,23 @@
stylua
nixfmt-rfc-style
nodePackages.prettier
rustywind
markdownlint-cli2
# LSPs
nil # nix
lua-language-server
vscode-langservers-extracted # HTML/CSS/JSON/ESLint
nodePackages.typescript-language-server
tailwindcss-language-server
nodePackages.pyright
# curl # http requests TODO
# nodePackages.cspell TODO
rust-analyzer
marksman # markdown
taplo #toml
yaml-language-server
lemminx # xml
# Other
# typescript
nodejs_20
];
in
{
@ -152,6 +173,11 @@
"PATH"
":"
"${lib.makeBinPath runtimeDependencies}"
# Some we will suffix so we pick up the local dev shell intead and default to these otherwise
"--suffix"
"PATH"
":"
"${lib.makeBinPath defaultRuntimeDependencies}"
# Set the LAZY env path to the nix store, see init.lua for how it is used
"--set"
"LAZY"

View file

@ -45,6 +45,13 @@ local function getSpec()
-- Convert plugins to use nix store, this auto sets the `dir` property for us on all plugins.
local function convertPluginToNixStore(plugin)
local p = ensure_table(plugin)
if U.isArray(p) and #p > 1 then
local plugins = {}
table.foreachi(p, function(i, inner)
table.insert(plugins, convertPluginToNixStore(inner))
end)
return plugins
end
if p.enabled == false then
return plugin
end
@ -69,14 +76,11 @@ local function getSpec()
local plugins_path = debug.getinfo(2, "S").source:sub(2):match("(.*/)") .. "lua/plugins"
for _, file in ipairs(vim.fn.readdir(plugins_path, [[v:val =~ '\.lua$']])) do
local plugin = string.sub(file, 0, -5)
table.insert(plugins, convertPluginToNixStore(require("plugins." .. plugin)))
local converted = convertPluginToNixStore(require("plugins." .. plugin))
table.insert(plugins, converted)
end
return plugins
else
-- TODO I want this to work in the nixos versionhttps://github.com/RingOfStorms/nvim/blob/nix-flake/init.lua#L39-L55
-- but it is not resolving properly to the nix store.
-- Will revisit at some point, instead we manually pull them
-- in above with a directory scan.
return { { import = "plugins" } }
end
end

View file

@ -1,58 +1,60 @@
local group = vim.api.nvim_create_augroup("myconfig-autocommands-group", { clear = true });
local group = vim.api.nvim_create_augroup("myconfig-autocommands-group", { clear = true })
-- Highlight when yanking (copying) text
-- Try it with `yap` in normal mode
-- See `:help vim.highlight.on_yank()`
vim.api.nvim_create_autocmd("TextYankPost", {
group = group,
desc = "Highlight when yanking (copying) text",
callback = function()
vim.highlight.on_yank({ timeout = 300 })
end,
group = group,
desc = "Highlight when yanking (copying) text",
callback = function()
vim.highlight.on_yank({ timeout = 300 })
end,
})
-- TODO is there a better way for these?
-- https://www.youtube.com/watch?v=NecszftvMFI vim.filetype.add
vim.api.nvim_create_autocmd("BufRead", {
group = group,
pattern = ".env*",
command = "set filetype=sh",
group = group,
pattern = ".env*",
command = "set filetype=sh",
})
vim.api.nvim_create_autocmd("BufRead", {
group = group,
pattern = ".*rc",
command = "set filetype=sh",
group = group,
pattern = ".*rc",
command = "set filetype=sh",
})
vim.api.nvim_create_autocmd("BufRead", {
group = group,
pattern = "Dockerfile.*",
command = "set filetype=dockerfile",
group = group,
pattern = "Dockerfile.*",
command = "set filetype=dockerfile",
})
vim.api.nvim_create_autocmd("BufRead", {
group = group,
pattern = "*.http",
command = "set filetype=http",
group = group,
pattern = "*.http",
command = "set filetype=http",
})
-- Auto exit insert mode whenever we switch screens
vim.api.nvim_create_autocmd({ "BufEnter", "BufWinEnter" }, {
group = group,
callback = function()
if vim.bo.filetype ~= "TelescopePrompt" and vim.bo.filetype ~= nil and vim.bo.filetype ~= "" then
vim.api.nvim_command("stopinsert")
end
end,
group = group,
callback = function()
if vim.bo.filetype ~= "TelescopePrompt" and vim.bo.filetype ~= nil and vim.bo.filetype ~= "" then
vim.api.nvim_command("stopinsert")
end
end,
})
vim.api.nvim_create_autocmd("VimLeavePre", {
group = group,
callback = function()
vim.cmd("NvimTreeClose")
-- Close all buffers with the 'httpResult' type
local close_types = { "httpResult", "noice", "help" }
local buffers = vim.api.nvim_list_bufs()
for _, bufnr in ipairs(buffers) do
if U.table_contains(close_types, vim.bo[bufnr].filetype) then
vim.api.nvim_buf_delete(bufnr, { force = true })
end
end
end,
group = group,
callback = function()
vim.cmd("NvimTreeClose")
-- Close all buffers with the 'httpResult' type
local close_types = { "httpResult", "noice", "help" }
local buffers = vim.api.nvim_list_bufs()
for _, bufnr in ipairs(buffers) do
if U.table_contains(close_types, vim.bo[bufnr].filetype) then
vim.api.nvim_buf_delete(bufnr, { force = true })
end
end
end,
})

View file

@ -84,7 +84,7 @@ U.keymaps({
-- Editor
{ "J", "mzJ`z", desc = "Move line below onto this line" },
{ -- TODO stay here, are these already mapped?
{
"]d",
vim.diagnostic.goto_next,
desc = "Go to next diagnostic message",
@ -107,13 +107,12 @@ U.keymaps({
{ "<C-6>", "<Home>", mode = { "i", "c" }, desc = "Movements in insert/command mode" },
-- Tabs
-- TODO revisit, do I even need these tab things?
{ "<leader>tn", "<cmd>tabnew<cr>", desc = "Create new tab", mode = nvx },
{ "<leader>tq", "<cmd>tabclose<cr>", desc = "Close current tab", mode = nvx },
{ "H", "<cmd>tabprevious<cr>", desc = "Move to previous tab" },
{ "L", "<cmd>tabnext<cr>", desc = "Move to next tab" },
-- LSP/IDE/etc TODO move to lsp config file
-- LSP/IDE/
{
"<leader>ld",
vim.diagnostic.open_float,

View file

@ -53,14 +53,12 @@ vim.opt.undofile = true
-- and `:help 'listchars'`
vim.opt.list = true
vim.opt.listchars = { tab = "", trail = "·", nbsp = "", eol = "" }
-- TODO REVISIT IF I WANT THESE
-- Search settings
vim.opt.hlsearch = true
vim.opt.incsearch = true
-- Preview substitutions live, as you type
-- TODO revisit, what does this actually do
vim.opt.inccommand = "split"
-- Show which line your cursor is on

View file

@ -1,103 +1,127 @@
return {
"hrsh7th/nvim-cmp",
event = "InsertEnter",
dependencies = {
-- Snippet Engine & its associated nvim-cmp source
{
"L3MON4D3/LuaSnip",
dependencies = {
-- TODO use or remove this?
-- `friendly-snippets` contains a variety of premade snippets.
-- See the README about individual language/framework/plugin snippets:
-- https://github.com/rafamadriz/friendly-snippets
-- {
-- 'rafamadriz/friendly-snippets',
-- config = function()
-- require('luasnip.loaders.from_vscode').lazy_load()
-- end,
-- },
},
},
"saadparwaiz1/cmp_luasnip",
"hrsh7th/nvim-cmp",
event = "InsertEnter",
dependencies = {
-- Snippet Engine & its associated nvim-cmp source
{
"L3MON4D3/LuaSnip",
dependencies = {
{
"rafamadriz/friendly-snippets",
config = function()
require("luasnip.loaders.from_vscode").lazy_load()
end,
},
},
},
"saadparwaiz1/cmp_luasnip",
-- Adds other completion capabilities.
-- nvim-cmp does not ship with all sources by default. They are split
-- into multiple repos for maintenance purposes.
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-path",
},
config = function()
-- See `:help cmp`
local cmp = require("cmp")
local luasnip = require("luasnip")
luasnip.config.setup({})
-- Adds other completion capabilities.
-- nvim-cmp does not ship with all sources by default. They are split
-- into multiple repos for maintenance purposes.
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
{
"zbirenbaum/copilot.lua",
cmd = "Copilot",
event = "InsertEnter",
opts = {
-- suggestion = { enabled = false, auto_trigger = false },
-- panel = { enabled = false, auto_trigger = false },
},
main = "copilot",
},
{ "zbirenbaum/copilot-cmp", opts = {}, main = "copilot_cmp" },
},
config = function()
-- See `:help cmp`
local cmp = require("cmp")
local luasnip = require("luasnip")
luasnip.config.setup({})
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
completion = { completeopt = "menu,menuone,noinsert" },
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
completion = { completeopt = "menu,menuone,noinsert" },
-- For an understanding of why these mappings were
-- chosen, you will need to read `:help ins-completion`
--
-- No, but seriously. Please read `:help ins-completion`, it is really good!
mapping = cmp.mapping.preset.insert({
-- Select the [n]ext item
["<C-j>"] = cmp.mapping.select_next_item(),
-- Select the [p]revious item
["<C-k>"] = cmp.mapping.select_prev_item(),
mapping = cmp.mapping.preset.insert({
-- Scroll the documentation window [b]ack / [f]orward
["<C-u>"] = cmp.mapping.scroll_docs(-4),
["<C-d>"] = cmp.mapping.scroll_docs(4),
["<esc>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.abort()
fallback()
else
fallback()
end
end),
-- Scroll the documentation window [b]ack / [f]orward
["<C-u>"] = cmp.mapping.scroll_docs(-4),
["<C-d>"] = cmp.mapping.scroll_docs(4),
-- Accept ([y]es) the completion.
-- This will auto-import if your LSP supports it.
-- This will expand snippets if the LSP sent a snippet.
["<C-y>"] = cmp.mapping.confirm({ select = true }),
-- If you prefer more traditional completion keymaps,
-- you can uncomment the following lines
--['<CR>'] = cmp.mapping.confirm { select = true },
--['<Tab>'] = cmp.mapping.select_next_item(),
--['<S-Tab>'] = cmp.mapping.select_prev_item(),
-- Manually trigger a completion from nvim-cmp.
-- Generally you don't need this, because nvim-cmp will display
-- completions whenever it has completion options available.
["<C-c>"] = cmp.mapping.complete({}),
-- TODO remove these or make them soemthing else, this collided with my normal movements in insert mode
-- Think of <c-l> as moving to the right of your snippet expansion.
-- So if you have a snippet that's like:
-- function $name($args)
-- $body
-- end
--
-- <c-l> will move you to the right of each of the expansion locations.
-- <c-h> is similar, except moving you backwards.
-- ["<C-l>"] = cmp.mapping(function()
-- if luasnip.expand_or_locally_jumpable() then
-- luasnip.expand_or_jump()
-- end
-- end, { "i", "s" }),
-- ["<C-h>"] = cmp.mapping(function()
-- if luasnip.locally_jumpable(-1) then
-- luasnip.jump(-1)
-- end
-- end, { "i", "s" }),
-- For more advanced Luasnip keymaps (e.g. selecting choice nodes, expansion) see:
-- https://github.com/L3MON4D3/LuaSnip?tab=readme-ov-file#keymaps
}),
sources = {
{ name = "nvim_lsp" },
{ name = "luasnip" },
{ name = "path" },
},
})
end,
-- Select the [n]ext item
["<C-j>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
-- elseif luasnip.expand_or_jumpable() then
elseif luasnip.expand_or_locally_jumpable() then
luasnip.expand_or_jump()
else
fallback()
end
end, { "i", "s" }),
-- Select the [p]revious item
["<C-k>"] = 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" }),
["<C-y>"] = cmp.mapping.confirm({ select = true }),
["<C-space>"] = cmp.mapping.complete({}),
}),
sources = {
{
name = "copilot",
priority = 9,
keyword_length = 1,
filter = function(keyword)
-- Check if keyword length is some number and not just whitespace
if #keyword < 2 or keyword:match("^%s*$") then
return false
end
return true
end,
},
{ name = "nvim_lsp", priority = 8, max_item_count = 100 },
{ name = "luasnip", priority = 7 },
-- This source provides file path completions, helping you to complete file paths in your code
{ name = "path", priority = 7 },
-- This source provides completion items from the current buffer, meaning it suggests words that have already been typed in the same file.
{ name = "buffer", priority = 6 },
-- Rust crates.io integration
{ name = "crates" },
},
-- TODO revisit if I want these or not
-- 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 = { -- also? https://github.com/RingOfStorms/nvim/blob/master/lua/plugins/lsp.lua#L330-L347
-- completion = cmp.config.window.bordered(),
-- documentation = cmp.config.window.bordered(),
-- },
})
end,
}

View file

@ -1,137 +1,133 @@
-- TODO checkout https://github.com/nvim-lua/lsp-status.nvim
-- https://www.reddit.com/r/neovim/comments/o4bguk/comment/h2kcjxa/
local function lsp_clients()
local clients = {}
for _, client in pairs(vim.lsp.buf_get_clients(0)) do
local name = client.name
-- TODO revisit this doesn't work
if not client.initialized then
name = name .. " (loading)"
end
clients[#clients + 1] = name
end
table.sort(clients)
return table.concat(clients, ""), ""
local clients = {}
for _, client in pairs(vim.lsp.buf_get_clients(0)) do
clients[#clients + 1] = client.name
end
table.sort(clients)
return table.concat(clients, ""), ""
end
local function langs()
local l = {}
for _, client in pairs(vim.lsp.buf_get_clients(0)) do
local out = nil
if client.name == "pyright" then
out = vim.fn.system({ "python", "-V" })
elseif client.name == "tsserver" then
out = "node " .. vim.fn.system({ "node", "--version" })
end
if out ~= nil and out ~= "" then
l[#l + 1] = vim.trim(out)
end
end
local l = {}
for _, client in pairs(vim.lsp.buf_get_clients(0)) do
local out = nil
if client.name == "pyright" then
out = vim.fn.system({ "python", "-V" })
elseif client.name == "tsserver" then
out = "node " .. vim.fn.system({ "node", "--version" })
end
if out ~= nil and out ~= "" then
l[#l + 1] = vim.trim(out)
end
end
table.sort(l)
return table.concat(l, ""), ""
table.sort(l)
return table.concat(l, ""), ""
end
local last_blame = nil
local last_blame_time = vim.loop.now()
local function gitblame()
local d = vim.b.gitsigns_blame_line_dict
local d = vim.b.gitsigns_blame_line_dict
if d then
last_blame = d
last_blame_time = vim.loop.now()
elseif vim.loop.now() - last_blame_time <= 2000 then
d = last_blame
end
if d then
last_blame = d
last_blame_time = vim.loop.now()
elseif vim.loop.now() - last_blame_time <= 2000 then
d = last_blame
end
if d then
local ok, res = pcall(os.date, "%d %b %y", d.committer_time)
return d.committer:sub(1, 12) .. " - " .. (ok and res or d.committer_time)
end
return ""
if d then
local ok, res = pcall(os.date, "%d %b %y", d.committer_time)
return d.committer:sub(1, 12) .. " - " .. (ok and res or d.committer_time)
end
return ""
end
return {
"nvim-lualine/lualine.nvim",
dependencies = { { "folke/noice.nvim", optional = true } },
lazy = false,
opts = function()
return {
options = {
theme = "codedark",
section_separators = { left = "", right = "" },
component_separators = "|",
},
sections = {
lualine_a = { "mode" },
lualine_b = { "branch", "diff", "diagnostics" },
lualine_c = {
{ "filename", separator = { right = "" } },
{ "reg_recording", icon = { "󰻃" }, color = { fg = "#D37676" } },
{ gitblame, color = { fg = "#696969" } },
},
lualine_x = {
lsp_clients,
langs,
"encoding",
"filetype",
"filesize",
},
lualine_y = { "searchcount", "selectioncount" },
lualine_z = { "location" },
},
winbar = {
lualine_a = {
{
"filename",
symbols = {
modified = "", -- Text to show when the file is modified.
readonly = "[-]", -- Text to show when the file is non-modifiable or readonly.
unnamed = "[No Name]", -- Text to show for unnamed buffers.
newfile = "[New]", -- Text to show for newly created file before first write
},
},
},
lualine_b = {
"mode",
},
},
inactive_winbar = {
lualine_a = {
{
"filename",
symbols = {
modified = "", -- Text to show when the file is modified.
readonly = "[-]", -- Text to show when the file is non-modifiable or readonly.
unnamed = "[No Name]", -- Text to show for unnamed buffers.
newfile = "[New]", -- Text to show for newly created file before first write
},
},
},
},
}
end,
config = function(_, opts)
require("lualine").setup(opts)
"nvim-lualine/lualine.nvim",
dependencies = { { "folke/noice.nvim", optional = true } },
lazy = false,
opts = function()
return {
options = {
theme = "codedark",
section_separators = { left = "", right = "" },
component_separators = "|",
},
sections = {
lualine_a = { "mode" },
lualine_b = {
"branch",
"filename",
},
lualine_c = {
"diff",
"diagnostics",
{ "reg_recording", icon = { "󰻃" }, color = { fg = "#D37676" } },
{ gitblame, color = { fg = "#696969" } },
},
lualine_x = {
lsp_clients,
langs,
"encoding",
"filetype",
"filesize",
},
lualine_y = { "searchcount", "selectioncount" },
lualine_z = { "location" },
},
winbar = {
lualine_a = {
{
"filename",
symbols = {
modified = "", -- Text to show when the file is modified.
readonly = "[-]", -- Text to show when the file is non-modifiable or readonly.
unnamed = "[No Name]", -- Text to show for unnamed buffers.
newfile = "[New]", -- Text to show for newly created file before first write
},
},
},
lualine_b = {
"mode",
},
},
inactive_winbar = {
lualine_a = {
{
"filename",
symbols = {
modified = "", -- Text to show when the file is modified.
readonly = "[-]", -- Text to show when the file is non-modifiable or readonly.
unnamed = "[No Name]", -- Text to show for unnamed buffers.
newfile = "[New]", -- Text to show for newly created file before first write
},
},
},
},
}
end,
config = function(_, opts)
require("lualine").setup(opts)
local ref = function()
require("lualine").refresh({
place = { "statusline" },
})
end
local ref = function()
require("lualine").refresh({
place = { "statusline" },
})
end
local group = vim.api.nvim_create_augroup("myconfig-lua-line-group", { clear = true })
vim.api.nvim_create_autocmd("RecordingEnter", {
group = group,
callback = ref,
})
vim.api.nvim_create_autocmd("RecordingLeave", {
group = group,
callback = function()
local timer = vim.loop.new_timer()
timer:start(50, 0, vim.schedule_wrap(ref))
end,
})
end,
local group = vim.api.nvim_create_augroup("myconfig-lua-line-group", { clear = true })
vim.api.nvim_create_autocmd("RecordingEnter", {
group = group,
callback = ref,
})
vim.api.nvim_create_autocmd("RecordingLeave", {
group = group,
callback = function()
local timer = vim.loop.new_timer()
timer:start(50, 0, vim.schedule_wrap(ref))
end,
})
end,
}

View file

@ -7,11 +7,6 @@ return {
},
event = "VeryLazy",
opts = {
routes = {
-- I want telescope-ui-select to trigger here not noice
{ filter = { event = "lsp", kind = "search_count" }, opts = { skip = true } },
{ filter = { event = "lsp" }, opts = { skip = true } }, -- TODO come back to this, im having weird issues with insert mode getting broken.
},
messages = {
view = "mini", -- default view for messages
view_error = "notify", -- view for errors
@ -26,6 +21,8 @@ return {
["vim.lsp.util.stylize_markdown"] = true,
["cmp.entry.get_documentation"] = true, -- requires hrsh7th/nvim-cmp
},
-- I had an issue with auto_open kicking me out of insert mode when entering insert mode
signature = { auto_open = { trigger = false } },
},
},
config = function(_, opts)

View file

@ -1,36 +1,45 @@
local function formatCurrent(retry)
require("conform").format({ async = true, lsp_fallback = true }, function(err, edited)
if edited then
print("Formatted!")
elseif err then
-- Sometimes I am too fast and vim is saving from my InsertExit and this fails so
-- I give it one retry
if not retry and string.find(err, "concurrent modification") then
return formatCurrent(true)
end
print(err)
else
print("Nothing to format!")
end
end)
end
return {
"stevearc/conform.nvim",
opts = {
-- https://github.com/stevearc/conform.nvim?tab=readme-ov-file#setup
notify_on_error = true,
-- Note that all these need to be available at runtime, add them to flake.nix#runtimeDependencies
-- Note that all these need to be available at runtime, add them to flake.nix#runtimeDependencies
formatters_by_ft = {
lua = { "stylua" },
nix = { "nixfmt" },
typescript = { { "prettierd", "prettier" } },
typescriptreact = { { "prettierd", "prettier" } },
javascript = { { "prettierd", "prettier" } },
javascriptreact = { { "prettierd", "prettier" } },
-- TODO revisit these I'd like to use them but they are not in nixpkgs yet
-- https://nixos.org/guides/nix-pills/
-- markdown = { "mdslw", "mdsf"},
markdown = { "markdownlint-cli2" },
nix = { "nixfmt" },
typescript = { { "prettierd", "prettier" }, "rustywind" },
typescriptreact = { { "prettierd", "prettier" }, "rustywind" },
javascript = { { "prettierd", "prettier" }, "rustywind" },
javascriptreact = { { "prettierd", "prettier" }, "rustywind" },
-- TODO revisit these I'd like to use them but they are not in nixpkgs yet
-- https://nixos.org/guides/nix-pills/
-- markdown = { "mdslw", "mdsf"},
markdown = { "markdownlint-cli2" },
-- rust = { "rustfmt" },
},
},
keys = {
{
"<leader>l<leader>",
function()
require("conform").format({ async = true, lsp_fallback = true }, function(err, edited)
if edited then
print("Formatted!")
elseif err then
print(err)
else
print("Nothing to format!")
end
end)
end,
formatCurrent,
mode = { "n", "v", "x" },
desc = "Format buffer",
},

View file

@ -1,145 +1,176 @@
return {
"neovim/nvim-lspconfig",
event = "BufEnter",
dependencies = {
-- Automatically install LSPs and related tools to stdpath for Neovim
{ "williamboman/mason.nvim", enabled = not NIX, config = true }, -- NOTE: Must be loaded before dependants
{ "williamboman/mason-lspconfig.nvim", enabled = not NIX },
{ "WhoIsSethDaniel/mason-tool-installer.nvim", enabled = not NIX },
-- LSP helper plugins for various languages
{ "folke/neodev.nvim", event = { "BufRead *.lua", "BufRead *.vim" }, opts = {}, main = "neodev" },
{ "mrcjkb/rustaceanvim", lazy = false }, -- uses ftplugins to enable itself lazily already
-- TODO add some hotkeys for opening the popup menus on crates
{ "Saecki/crates.nvim", event = "BufRead Cargo.toml", tag = "stable", opts = {}, main = "crates" },
{
"neovim/nvim-lspconfig",
event = "BufEnter",
dependencies = {
{
"lvimuser/lsp-inlayhints.nvim",
init = function()
vim.api.nvim_create_augroup("LspAttach_inlayhints", { clear = true })
vim.api.nvim_create_autocmd("LspAttach", {
group = "LspAttach_inlayhints",
callback = function(args)
if not (args.data and args.data.client_id) then
return
end
-- TODO revisit if I want this or not, is this already solved?
-- Useful status updates for LSP.
-- NOTE: `opts = {}` is the same as calling `require('fidget').setup({})`
-- { "j-hui/fidget.nvim", opts = {} },
local bufnr = args.buf
local client = vim.lsp.get_client_by_id(args.data.client_id)
require("lsp-inlayhints").on_attach(client, bufnr)
end,
})
end,
opts = {
type_hints = { prefix = " ::" },
},
main = "lsp-inlayhints",
},
-- Automatically install LSPs and related tools to stdpath for Neovim
{ "williamboman/mason.nvim", enabled = not NIX, config = true }, -- NOTE: Must be loaded before dependants
{ "williamboman/mason-lspconfig.nvim", enabled = not NIX },
{ "WhoIsSethDaniel/mason-tool-installer.nvim", enabled = not NIX },
},
config = function()
vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("myconfig-lsp-attach", { clear = true }),
callback = function(event)
local map = function(keys, func, desc)
vim.keymap.set("n", keys, func, { buffer = event.buf, desc = "LSP: " .. desc })
end
map("gd", require("telescope.builtin").lsp_definitions, "Goto Definition")
map("gr", require("telescope.builtin").lsp_references, "Goto References")
map("gI", require("telescope.builtin").lsp_implementations, "Goto Implementation")
map("<leader>lr", vim.lsp.buf.rename, "Rename")
map("<leader>la", vim.lsp.buf.code_action, "Code Action")
map("K", vim.lsp.buf.hover, "Hover Documentation")
map("gD", vim.lsp.buf.declaration, "Goto Declaration")
end,
})
-- `neodev` configures Lua LSP for your Neovim config, runtime and plugins
-- used for completion, annotations and signatures of Neovim apis
{ "folke/neodev.nvim", opts = {}, main = "neodev" },
},
config = function()
vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("myconfig-lsp-attach", { clear = true }),
callback = function(event)
local map = function(keys, func, desc)
vim.keymap.set("n", keys, func, { buffer = event.buf, desc = "LSP: " .. desc })
end
map("gd", require("telescope.builtin").lsp_definitions, "Goto Definition")
map("gr", require("telescope.builtin").lsp_references, "Goto References")
map("gI", require("telescope.builtin").lsp_implementations, "Goto Implementation")
-- TODO do I want these?
-- map("<leader>D", require("telescope.builtin").lsp_type_definitions, "Type Definition")
-- map("<leader>ds", require("telescope.builtin").lsp_document_symbols, "Document Symbols")
-- map("<leader>ws", require("telescope.builtin").lsp_dynamic_workspace_symbols, "Workspace Symbols")
map("<leader>lr", vim.lsp.buf.rename, "Rename")
map("<leader>la", vim.lsp.buf.code_action, "Code Action")
map("K", vim.lsp.buf.hover, "Hover Documentation")
map("gD", vim.lsp.buf.declaration, "Goto Declaration")
vim.api.nvim_create_autocmd("LspDetach", {
group = vim.api.nvim_create_augroup("myconfig-lsp-detach", { clear = true }),
callback = function(event)
vim.lsp.buf.clear_references()
vim.api.nvim_clear_autocmds({ group = "myconfig-lsp-highlight", buffer = event.buf })
end,
})
local client = vim.lsp.get_client_by_id(event.data.client_id)
if client and client.server_capabilities.inlayHintProvider and vim.lsp.inlay_hint then
map("<leader>lth", function()
vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled())
end, "Toggle Inlay Hints")
end
end,
})
local capabilities = vim.lsp.protocol.make_client_capabilities()
U.safeRequire("cmp_nvim_lsp", function(c)
capabilities = vim.tbl_deep_extend("force", capabilities, c.default_capabilities())
end)
vim.api.nvim_create_autocmd("LspDetach", {
group = vim.api.nvim_create_augroup("myconfig-lsp-detach", { clear = true }),
callback = function(event)
vim.lsp.buf.clear_references()
vim.api.nvim_clear_autocmds({ group = "myconfig-lsp-highlight", buffer = event.buf })
end,
})
local capabilities = vim.lsp.protocol.make_client_capabilities()
U.safeRequire("cmp_nvim_lsp", function(c)
capabilities = vim.tbl_deep_extend("force", capabilities, c.default_capabilities())
end)
-- TODO finish porting over lsp configs: https://github.com/RingOfStorms/nvim/blob/master/lua/plugins/lsp.lua
local servers = {
-- clangd = {},
-- gopls = {},
-- pyright = {},
-- rust_analyzer = {},
-- ... etc. See `:help lspconfig-all` for a list of all the pre-configured LSPs
--
-- Some languages (like typescript) have entire language plugins that can be useful:
-- https://github.com/pmizio/typescript-tools.nvim
--
-- But for many setups, the LSP (`tsserver`) will work just fine
tsserver = {
-- typescript/javascript
implicitProjectConfiguration = {
checkJs = true,
},
},
pyright = {
-- python
},
lua_ls = {
-- cmd = { ... },
-- filetypes = { ...},
-- capabilities = {},
settings = {
Lua = {
runtime = {
-- Tell the language server which version of Lua you're using
-- (most likely LuaJIT in the case of Neovim)
version = "LuaJIT",
},
completion = {
callSnippet = "Replace",
},
workspace = {
checkThirdParty = false,
library = {
vim.env.VIMRUNTIME,
vim.api.nvim_get_runtime_file("", true),
vim.fn.expand("$VIMRUNTIME/lua"),
vim.fn.expand("$VIMRUNTIME/lua/vim/lsp"),
},
telemetry = { enable = false },
diagnostics = {
globals = {
"vim",
"require",
"NIX",
"U",
-- Hammerspoon
"hs",
},
},
},
-- You can toggle below to ignore Lua_LS's noisy `missing-fields` warnings
-- diagnostics = { disable = { 'missing-fields' } },
},
},
},
}
if NIX then
local servers = vim.tbl_keys(servers or {})
for _, server_name in ipairs(servers) do
local server_opts = servers[server_name] or {}
require("lspconfig")[server_name].setup(server_opts)
end
else
require("mason").setup()
local ensure_installed = vim.tbl_keys(servers or {})
vim.list_extend(ensure_installed, {
"stylua", -- Used to format Lua code TODO come back to this, more about linter/formatter configs
})
require("mason-tool-installer").setup({ ensure_installed = ensure_installed })
require("mason-lspconfig").setup({
handlers = {
function(server_name)
local server = servers[server_name] or {}
server.capabilities = vim.tbl_deep_extend("force", {}, capabilities, server.capabilities or {})
require("lspconfig")[server_name].setup(server)
end,
},
})
end
end,
-- TODO finish porting over lsp configs: https://github.com/RingOfStorms/nvim/blob/master/lua/plugins/lsp.lua
local servers = {
-- Some languages (like typescript) have entire language plugins that can be useful:
-- https://github.com/pmizio/typescript-tools.nvim
--
-- But for many setups, the LSP (`tsserver`) will work just fine
-- Note that `rust-analyzer` is done via mrcjkb/rustaceanvim plugin above, do not register it here.
lua_ls = {
settings = {
Lua = {
runtime = {
-- Tell the language server which version of Lua you're using
-- (most likely LuaJIT in the case of Neovim)
version = "LuaJIT",
},
completion = {
callSnippet = "Replace",
},
workspace = {
checkThirdParty = false,
library = {
vim.env.VIMRUNTIME,
vim.api.nvim_get_runtime_file("", true),
vim.fn.expand("$VIMRUNTIME/lua"),
vim.fn.expand("$VIMRUNTIME/lua/vim/lsp"),
},
telemetry = { enable = false },
diagnostics = {
globals = {
"vim",
"require",
"NIX",
"U",
-- Hammerspoon for macos
"hs",
},
},
},
},
},
},
nil_ls = {},
tsserver = {
-- typescript/javascript
implicitProjectConfiguration = {
checkJs = true,
},
},
tailwindcss = {
-- tailwind css
-- https://www.tailwind-variants.org/docs/getting-started#intellisense-setup-optional
tailwindCSS = {
experimental = {
classRegex = {
{ "tv\\((([^()]*|\\([^()]*\\))*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]" },
},
},
},
},
cssls = {
-- css
},
jsonls = {
-- json
},
pyright = {
-- python
},
marksman = {
-- markdown
},
taplo = {
-- toml
},
yamlls = {
-- yaml
},
lemminx = {
-- xml
},
}
if NIX then
local lsp_servers = vim.tbl_keys(servers or {})
for _, server_name in ipairs(lsp_servers) do
local server_opts = servers[server_name] or {}
require("lspconfig")[server_name].setup(server_opts)
end
else
-- TODO test this out on a non nix setup...
require("mason").setup()
local ensure_installed = vim.tbl_keys(servers or {})
vim.list_extend(ensure_installed, {
"stylua", -- Used to format Lua code TODO come back to this, more about linter/formatter configs
})
require("mason-tool-installer").setup({ ensure_installed = ensure_installed })
require("mason-lspconfig").setup({
handlers = {
function(server_name)
local server = servers[server_name] or {}
server.capabilities =
vim.tbl_deep_extend("force", {}, capabilities, server.capabilities or {})
require("lspconfig")[server_name].setup(server)
end,
},
})
end
end,
},
}

View file

@ -11,7 +11,6 @@ return {
"<leader>,c",
function()
if next(vim.lsp.get_active_clients()) ~= nil then
-- TODO test that this works
vim.cmd("TextCaseOpenTelescopeLSPChange")
else
vim.cmd("TextCaseOpenTelescope")

View file

@ -15,15 +15,15 @@ return {
local wk = require("which-key")
wk.setup(opts)
wk.register({
["<leader>b"] = { name = "Buffers", mode = { "n", "x", "v", "c" } },
["<leader>t"] = { name = "Tabs", mode = { "n", "x", "v", "c" } },
["<leader>,"] = { name = "Miscellaneous Tools", mode = { "n", "x", "v", "c" } },
["<leader>b"] = { name = "Buffers", mode = { "n", "x", "v" } },
["<leader>t"] = { name = "Tabs", mode = { "n", "x", "v" } },
["<leader>,"] = { name = "Miscellaneous Tools", mode = { "n", "x", "v" } },
-- ["<leader>c"] = { name = "Copilot" },
["<leader>f"] = { name = "Find [Telescope]", mode = { "n", "x", "v", "c" } },
["<leader>f"] = { name = "Find [Telescope]", mode = { "n", "x", "v" } },
-- ["<leader>fs"] = { name = "Find in Scratches [Telescope]" },
["<leader>g"] = { name = "Git", mode = { "n", "x", "v", "c" } },
["<leader>l"] = { name = "LSP", mode = { "n", "x", "v", "c" } },
["<leader>lf"] = { name = "LSP Find", mode = { "n", "x", "v", "c" } },
["<leader>g"] = { name = "Git", mode = { "n", "x", "v" } },
["<leader>l"] = { name = "LSP", mode = { "n", "x", "v" } },
["<leader>lf"] = { name = "LSP Find", mode = { "n", "x", "v" } },
-- ["<leader>Q"] = { name = "+Q Quit and remove session" },
-- ["<leader>s"] = { name = "Scratch Files" },
-- ["<leader>x"] = { name = "Generative AI, Ollama" },

View file

@ -1,30 +1,41 @@
local M = {}
function M.isArray(table)
local i = 0
for _ in pairs(table) do
i = i + 1
if table[i] == nil then
return false
end
end
return true
end
function M.cmd_executable(cmd, callback)
local executable = vim.fn.executable(cmd) == 1
-- Check if a callback is provided and it is a function
if executable and callback and type(callback) == "function" then
callback()
end
local executable = vim.fn.executable(cmd) == 1
-- Check if a callback is provided and it is a function
if executable and callback and type(callback) == "function" then
callback()
end
-- Check if a callback is provided and it is a table
if type(callback) == "table" then
if executable and (callback[1] or callback[true]) then
-- Call the function associated with key 1 or true if the command is executable
local func = callback[1] or callback[true]
if type(func) == "function" then
func()
end
elseif not executable and (callback[2] or callback[false]) then
-- Call the function associated with key 2 or false if the command is not executable
local func = callback[2] or callback[false]
if type(func) == "function" then
func()
end
end
end
-- Check if a callback is provided and it is a table
if type(callback) == "table" then
if executable and (callback[1] or callback[true]) then
-- Call the function associated with key 1 or true if the command is executable
local func = callback[1] or callback[true]
if type(func) == "function" then
func()
end
elseif not executable and (callback[2] or callback[false]) then
-- Call the function associated with key 2 or false if the command is not executable
local func = callback[2] or callback[false]
if type(func) == "function" then
func()
end
end
end
return executable
return executable
end
-- [1]: (string) lhs (required)
@ -33,127 +44,115 @@ end
-- ft: (string|string[]) filetype for buffer-local keymaps (optional)
-- any other option valid for vim.keymap.set
function M.keymaps(keymaps)
-- is not an array, will pass directly to keymaps
if type(keymaps[1]) == "string" then
M.keymap(keymaps)
else
-- is array will iterate over
for _, keymap in pairs(keymaps) do
M.keymap(keymap)
end
end
-- is not an array, will pass directly to keymaps
if type(keymaps[1]) == "string" then
M.keymap(keymaps)
else
-- is array will iterate over
for _, keymap in pairs(keymaps) do
M.keymap(keymap)
end
end
end
function M.keymap(keymap)
local lhs = keymap[1]
local rhs = keymap[2]
local mode = keymap["mode"] or "n"
local opts = { silent = true }
for key, value in pairs(keymap) do
if type(key) ~= "number" and key ~= "mode" then
opts[key] = value
end
end
local lhs = keymap[1]
local rhs = keymap[2]
local mode = keymap["mode"] or "n"
local opts = { silent = true }
for key, value in pairs(keymap) do
if type(key) ~= "number" and key ~= "mode" then
opts[key] = value
end
end
local status, err = pcall(function()
vim.keymap.set(mode, lhs, rhs, opts)
end)
if not status then
vim.notify("Failed to create keymap: " .. err, 3)
end
local status, err = pcall(function()
vim.keymap.set(mode, lhs, rhs, opts)
end)
if not status then
vim.notify("Failed to create keymap: " .. err, 3)
end
end
-- spread({})({})
function M.spread(template)
local result = {}
for key, value in pairs(template) do
result[key] = value
end
local result = {}
for key, value in pairs(template) do
result[key] = value
end
return function(table)
for key, value in pairs(table) do
result[key] = value
end
return result
end
return function(table)
for key, value in pairs(table) do
result[key] = value
end
return result
end
end
-- assign({}, {})
function M.assign(obj, assign)
for key, value in pairs(assign) do
obj[key] = value
end
return obj
for key, value in pairs(assign) do
obj[key] = value
end
return obj
end
function M.table_contains(table, element)
for _, value in pairs(table) do
if value == element then
return true
end
end
return false
for _, value in pairs(table) do
if value == element then
return true
end
end
return false
end
-- From https://github.com/lukas-reineke/onedark.nvim/blob/master/lua/onedark.lua
function M.highlight(group, options)
local guifg = options.fg or "NONE"
local guibg = options.bg or "NONE"
local guisp = options.sp or "NONE"
local gui = options.gui or "NONE"
local blend = options.blend or 0
local ctermfg = options.ctermfg or "NONE"
local guifg = options.fg or "NONE"
local guibg = options.bg or "NONE"
local guisp = options.sp or "NONE"
local gui = options.gui or "NONE"
local blend = options.blend or 0
local ctermfg = options.ctermfg or "NONE"
vim.cmd(
string.format(
"highlight %s guifg=%s ctermfg=%s guibg=%s guisp=%s gui=%s blend=%d",
group,
guifg,
ctermfg,
guibg,
guisp,
gui,
blend
)
)
vim.cmd(
string.format(
"highlight %s guifg=%s ctermfg=%s guibg=%s guisp=%s gui=%s blend=%d",
group,
guifg,
ctermfg,
guibg,
guisp,
gui,
blend
)
)
end
function M.safeRequire(module, func, errorFunc)
local ok, result = pcall(require, module)
if ok then
return func(result)
elseif errorFunc then
return errorFunc(result)
end
return nil
local ok, result = pcall(require, module)
if ok then
return func(result)
elseif errorFunc then
return errorFunc(result)
end
return nil
end
-- TODO remove if not needed
-- local startup_time = vim.loop.now()
-- function M.delayFromStartup(delay, func)
-- local current_time = vim.loop.now()
-- local diff = current_time - startup_time
-- if diff >= delay then
-- func()
-- else
-- vim.defer_fn(func, (delay - diff))
-- end
-- end
function M.fnFalse()
return false
return false
end
function M.fnNil()
return nil
return nil
end
function M.fnEmptyStr()
return ""
return ""
end
function M.fnZero()
return 0
return 0
end
return M