0
0

init.lua 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. -- === === === === === === === === Neovim Config === === === === === === === ===
  2. --
  3. -- A configuration for Neovim that aims to be beautiful, intuitive, and
  4. -- pragmatic about plugin usage, while providing a developer experience on par
  5. -- with professional IDEs. It is tuned for usage with a custom keyboard
  6. -- layout and terminal configuration, and may not be as useful in other setups.
  7. --
  8. -- This configuration leverages a combination of keymaps and omnibars to give
  9. -- quick access to a large amount of functionality in an intuitive way. Most
  10. -- keymaps are unchanged from stock Neovim, with the notable exception of
  11. -- remapping most `s<a-Z>` keymaps.
  12. --
  13. -- === === === === === === === === === === === === === === === === === === ===
  14. --
  15. -- Core Options
  16. --
  17. -- === === === === === === === === === === === === === === === === === === ===
  18. -- Incantation to render correctly in Alacritty/tmux/macOS
  19. vim.cmd([[
  20. let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
  21. let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
  22. set termguicolors
  23. ]])
  24. -- File options
  25. vim.opt.wrap = false
  26. vim.opt.encoding = "UTF-8"
  27. vim.opt.hlsearch = true
  28. vim.opt.spell = true
  29. vim.opt.spelllang = "en_us"
  30. -- Display options
  31. vim.opt.pumheight = 15
  32. vim.opt.laststatus = 2
  33. vim.opt.showtabline = 2
  34. vim.opt.showcmd = true
  35. vim.opt.cmdheight = 0
  36. vim.opt.number = true
  37. vim.opt.relativenumber = true
  38. vim.opt.splitbelow = true
  39. vim.opt.splitright = true
  40. vim.opt.expandtab = true
  41. vim.opt.tabstop = 4
  42. vim.opt.shiftwidth = 4
  43. -- === === === === === === === === === === === === === === === === === === ===
  44. --
  45. -- Leader
  46. --
  47. -- === === === === === === === === === === === === === === === === === === ===
  48. vim.keymap.set({ 'n', 'v' }, 's', '<Nop>', { noremap = true, silent = true })
  49. vim.keymap.set({ 'n', 'v' }, 'S', '<Nop>', { noremap = true, silent = true })
  50. vim.g.mapleader = 's'
  51. vim.g.maplocalleader = vim.g.mapleader
  52. -- === === === === === === === === === === === === === === === === === === ===
  53. --
  54. -- Keymaps
  55. --
  56. -- === === === === === === === === === === === === === === === === === === ===
  57. -- Use `Alt-Arrow` to navigate between panes
  58. vim.keymap.set("i", "<A-left>", "<C-\\><C-N><C-w>W")
  59. vim.keymap.set("i", "<A-right>", "<C-\\><C-N><C-w>w")
  60. vim.keymap.set("i", "<S-A-left>", "<C-\\><C-N>:tabnext<CR>")
  61. vim.keymap.set("i", "<S-A-right>", "<C-\\><C-N>:tabprevious<CR>")
  62. vim.keymap.set("n", "<A-left>", "<C-w>W")
  63. vim.keymap.set("n", "<A-right>", "<C-w>w")
  64. vim.keymap.set("n", "<S-A-left>", ":tabnext<CR>")
  65. vim.keymap.set("n", "<S-A-right>", ":tabprevious<CR>")
  66. -- Folds toggled by homerow roll
  67. vim.keymap.set("n", "sr", ": normal za<CR>")
  68. -- Buffer actions
  69. vim.keymap.set("n", "SV", ":vsp<CR>")
  70. vim.keymap.set("n", "SQ", ":q<CR>")
  71. vim.keymap.set("n", "SH", ":noh<CR>")
  72. -- Yank to system clipboard
  73. vim.keymap.set({ "n", 'v' }, "Y", "\"+y")
  74. -- Yank file properties to system clipboard
  75. local yank_filename = function(full, line)
  76. local filename = vim.fn.expand("%")
  77. if full then filename = vim.fn.expand("%:p") end
  78. if line then filename = filename .. ":" .. vim.api.nvim_win_get_cursor(0)[1] end
  79. vim.fn.setreg("+", filename)
  80. end
  81. vim.keymap.set("n", "Syan", function() yank_filename(true, false) end)
  82. vim.keymap.set("n", "Syal", function() yank_filename(true, true) end)
  83. vim.keymap.set("n", "Syrn", function() yank_filename(false, false) end)
  84. vim.keymap.set("n", "Syrl", function() yank_filename(false, true) end)
  85. vim.keymap.set("n", "Syf", function() yank_filename(false, false) end)
  86. -- === === === === === === === === === === === === === === === === === === ===
  87. --
  88. -- Language Servers
  89. --
  90. -- === === === === === === === === === === === === === === === === === === ===
  91. -- See configurations in `lsp/*.lua`
  92. vim.lsp.config("*", {
  93. cmd_cwd = vim.fn.expand("~"),
  94. root_markers = { ".git" },
  95. })
  96. -- Enable all language servers with extant configurations
  97. for _, filename in pairs(vim.split(io.popen("ls -a " .. vim.fn.stdpath("config")
  98. .. "/lsp"):read("*a"), "\n")) do
  99. if filename:match(".lua$") ~= nil then
  100. vim.lsp.enable(filename:sub(1, -5))
  101. end
  102. end
  103. -- LSP Keymaps
  104. vim.api.nvim_create_autocmd("LspAttach", {
  105. callback = function(_)
  106. vim.keymap.set("n", "SR", vim.lsp.buf.rename)
  107. vim.keymap.set("n", "Sx", vim.lsp.buf.code_action)
  108. vim.keymap.set("n", "<Space>", vim.lsp.buf.hover)
  109. vim.keymap.set("n", "SI", function()
  110. local diagnostic_config = vim.diagnostic.config()
  111. if (vim.lsp.inlay_hint.is_enabled()) then
  112. vim.lsp.inlay_hint.enable(false)
  113. vim.diagnostic.config({
  114. virtual_lines = {
  115. current_line = true,
  116. ---@diagnostic disable-next-line: need-check-nil, undefined-field
  117. format = diagnostic_config.format
  118. }
  119. })
  120. else
  121. vim.lsp.inlay_hint.enable(true)
  122. vim.diagnostic.config({
  123. virtual_lines = true,
  124. ---@diagnostic disable-next-line: need-check-nil, undefined-field
  125. format = diagnostic_config.format
  126. })
  127. end
  128. end)
  129. end
  130. })
  131. -- === === === === === === === === === === === === === === === === === === ===
  132. --
  133. -- Plugins Declarations
  134. --
  135. -- === === === === === === === === === === === === === === === === === === ===
  136. vim.pack.add({
  137. "https://github.com/hrsh7th/cmp-buffer",
  138. "https://github.com/hrsh7th/cmp-calc",
  139. "https://github.com/hrsh7th/cmp-cmdline",
  140. "https://github.com/hrsh7th/cmp-nvim-lsp",
  141. "https://github.com/hrsh7th/cmp-nvim-lsp-signature-help",
  142. "https://github.com/hrsh7th/cmp-nvim-lua",
  143. "https://github.com/hrsh7th/cmp-path",
  144. "https://github.com/hrsh7th/nvim-cmp",
  145. "https://github.com/kylechui/nvim-surround",
  146. "https://github.com/lewis6991/gitsigns.nvim",
  147. "https://github.com/lukas-reineke/virt-column.nvim",
  148. "https://github.com/nvim-lua/plenary.nvim",
  149. "https://github.com/nvim-telescope/telescope-file-browser.nvim",
  150. "https://github.com/nvim-telescope/telescope-ui-select.nvim",
  151. "https://github.com/nvim-telescope/telescope.nvim",
  152. "https://github.com/nvim-treesitter/nvim-treesitter",
  153. "https://github.com/nvim-treesitter/nvim-treesitter-context",
  154. "https://github.com/nvim-treesitter/nvim-treesitter-textobjects",
  155. "https://github.com/psliwka/vim-dirtytalk",
  156. "https://github.com/stevearc/aerial.nvim",
  157. "https://github.com/tpope/vim-commentary"
  158. })
  159. for _, plugin in ipairs({
  160. "like-a-butterfly",
  161. "bit-browser",
  162. "command-palette",
  163. "jonathandarker",
  164. "jxdash",
  165. "like-a-butterfly",
  166. "maj-peg",
  167. "pandoctrinated",
  168. "proj-conf",
  169. "save-formatter",
  170. "status-beast",
  171. "telescope-shroud",
  172. }) do
  173. vim.opt.runtimepath:prepend(vim.fn.stdpath("config") ..
  174. "/custom/" .. plugin)
  175. end
  176. -- === === === === === === === === === === === === === === === === === === ===
  177. --
  178. -- Plugins Configurations
  179. --
  180. -- === === === === === === === === === === === === === === === === === === ===
  181. local function config_command_palette()
  182. local palette = require("command-palette")
  183. palette.add({
  184. {
  185. "Manage project", "", {
  186. {
  187. "Close project",
  188. "Safely close the project and then close the associated tmux pane",
  189. function()
  190. vim.api.nvim_create_autocmd({ "VimLeave" }, {
  191. pattern = { "*" },
  192. group = vim.api.nvim_create_augroup(
  193. "tmux_close_group", { clear = true }),
  194. callback = function()
  195. vim.api.nvim_exec("!tmux kill-pane",
  196. false)
  197. end
  198. })
  199. vim.api.nvim_exec("qa", true)
  200. end
  201. }
  202. }
  203. }, {
  204. "Manage Neovim", "", {
  205. {
  206. "Update plugins",
  207. "",
  208. function() vim.pack.update() end
  209. }
  210. }
  211. }
  212. })
  213. vim.keymap.set("n", "<Leader>P", palette.open)
  214. vim.keymap.set("n", "<Leader>p", palette.open_full)
  215. vim.keymap.set("n", "<Leader>L", function()
  216. palette.open({}, "LSP Finders", {
  217. { "Treesitter", "", ":Telescope treesitter" },
  218. { "LSP References", "", ":Telescope lsp_references" },
  219. { "LSP Incoming Calls", "", ":Telescope lsp_incoming_calls" },
  220. { "LSP Outgoing Calls", "", ":Telescope lsp_outgoing_calls" },
  221. {
  222. "LSP Document Symbols", "",
  223. ":Telescope lsp_document_symbols"
  224. },
  225. {
  226. "LSP Workspace Symbols", "",
  227. ":Telescope lsp_workspace_symbols"
  228. }, {
  229. "LSP Dynamic Workspace Symbols", "",
  230. ":Telescope lsp_workspace_symbols"
  231. }, { "Diagnostics", "", ":Telescope diagnostics" },
  232. {
  233. "LSP Implementations", "",
  234. ":Telescope lsp_implementations"
  235. }, { "LSP Definitions", "", ":Telescope lsp_definitions" },
  236. {
  237. "LSP Type Definitions", "",
  238. ":Telescope lsp_type_definitions"
  239. }
  240. })
  241. end)
  242. end
  243. local function config_bit_browser()
  244. local bitbrowser = require("bit-browser")
  245. vim.keymap.set("n", "n", bitbrowser.next)
  246. vim.keymap.set("n", "N", bitbrowser.prev)
  247. for i, v in pairs({ 'e', 'w', 'i', 'd', 's', 'g' }) do
  248. vim.keymap.set("n", "<Leader>n" .. v, function()
  249. bitbrowser.set_target(i);
  250. bitbrowser.next()
  251. end)
  252. vim.keymap.set("n", "<Leader>N" .. v, function()
  253. bitbrowser.set_target(i);
  254. bitbrowser.prev()
  255. end)
  256. end
  257. end
  258. local function config_save_formatter()
  259. local formatter = require("save-formatter")
  260. formatter.setup()
  261. vim.keymap.set("n", "Sw",
  262. function() vim.api.nvim_exec2("write", {}) end)
  263. require("command-palette").add({ {
  264. "Save Formatter", "Configure automatic formatters", formatter.picker }
  265. })
  266. end
  267. local function config_pandoctrinated()
  268. local pandoctrinated = require("pandoctrinated")
  269. vim.keymap.set("n", "Sfd", pandoctrinated.pandoc_format_docstring)
  270. require("command-palette").add({ {
  271. "Pandoctrinated", "Format \"\"\"docstring\"\"\" with `pandoc`",
  272. pandoctrinated.pandoc_format_docstring }
  273. })
  274. end
  275. local function config_nvim_cmp()
  276. local cmp = require("cmp")
  277. local mapping = {
  278. ["<Tab>"] = function(fallback)
  279. if cmp.visible() then
  280. cmp.select_next_item(
  281. { behavior = cmp.SelectBehavior.Select })
  282. else
  283. fallback()
  284. end
  285. end,
  286. ["<S-Tab>"] = function(fallback)
  287. if cmp.visible() then
  288. cmp.select_prev_item(
  289. { behavior = cmp.SelectBehavior.Select })
  290. else
  291. fallback()
  292. end
  293. end,
  294. ["<CR>"] = function(fallback)
  295. if cmp.visible() and cmp.get_active_entry() then
  296. cmp.confirm({ behavior = cmp.ConfirmBehavior.Replace })
  297. else
  298. fallback()
  299. end
  300. end
  301. }
  302. cmp.setup({
  303. snippet = {},
  304. mapping = mapping,
  305. sources = cmp.config.sources({ { name = "nvim_lsp" } }, {
  306. { name = "buffer" }, { name = "nvim_lua" }, { name = "calc" },
  307. { name = "nvim_lsp_signature_help" }, { name = "path" }
  308. })
  309. })
  310. cmp.setup.cmdline("/", {
  311. mapping = cmp.mapping.preset.cmdline(),
  312. sources = { { name = "buffer" } }
  313. })
  314. cmp.setup.cmdline(":", {
  315. mapping = cmp.mapping.preset.cmdline(),
  316. sources = cmp.config.sources({ { name = "path" } }, {
  317. { name = "cmdline", option = { ignore_cmds = { "Man", "!" } } }
  318. })
  319. })
  320. vim.api.nvim_create_autocmd("LspAttach", {
  321. callback = function(args)
  322. local client = vim.lsp.get_client_by_id(args.data.client_id)
  323. if client == nil then return end
  324. if client:supports_method('textDocument/completion') then
  325. vim.lsp.completion.enable(true, client.id, args.buf,
  326. { autotrigger = false })
  327. end
  328. end
  329. })
  330. end
  331. local function config_maj_peg()
  332. local mp = require("maj-peg")
  333. mp.setup()
  334. require("command-palette").add({
  335. {
  336. "maj-peg", "Diagnostic integration for `mypy`", {
  337. {
  338. "Toggle maj-peg",
  339. function()
  340. if mp.status().enabled then
  341. return "Disable `mypy` integration"
  342. else
  343. return "Enable `mypy` integration"
  344. end
  345. end,
  346. mp.toggle } }
  347. }
  348. })
  349. end
  350. local function config_like_a_butterfly()
  351. local lab = require('like-a-butterfly')
  352. local augroup = vim.api.nvim_create_augroup(
  353. 'like-a-butterfly', { clear = true })
  354. function MakeTerm(shortcut, name, command, flaky)
  355. lab.create_term(name, command)
  356. vim.keymap.set("n", "<Leader>" .. shortcut, function()
  357. if flaky then
  358. local flaky_redraw_time = 10
  359. vim.api.nvim_create_autocmd({ "BufEnter" },
  360. {
  361. pattern = { "*" },
  362. group = augroup,
  363. once = true,
  364. callback = function()
  365. if (vim.bo.filetype ~= "butterfly") then
  366. return
  367. end
  368. local window = vim.api
  369. .nvim_get_current_win()
  370. vim.cmd(
  371. "setlocal sidescrolloff=" ..
  372. vim.o
  373. .columns)
  374. vim.defer_fn(function()
  375. vim.api.nvim_win_set_height(
  376. window,
  377. vim.api
  378. .nvim_win_get_height(
  379. window) -
  380. 1)
  381. vim.defer_fn(function()
  382. vim.api
  383. .nvim_win_set_height(
  384. window,
  385. vim.api
  386. .nvim_win_get_height(
  387. window) + 1)
  388. vim.api.nvim_feedkeys(
  389. vim.api
  390. .nvim_replace_termcodes(
  391. '<C-\\><C-n>^zei',
  392. true, true, true),
  393. 'i', true)
  394. vim.schedule(function()
  395. vim.cmd("redraw!")
  396. end)
  397. end, flaky_redraw_time)
  398. end, flaky_redraw_time)
  399. vim.cmd("redraw!")
  400. end
  401. })
  402. end
  403. lab.open_term(name)
  404. end)
  405. end
  406. vim.api.nvim_create_autocmd({ "BufEnter" },
  407. {
  408. pattern = { "*" },
  409. group = augroup,
  410. callback = function()
  411. vim
  412. .schedule(function()
  413. if (vim.bo.filetype ~= "butterfly") then
  414. lab.close_all()
  415. end
  416. end)
  417. end
  418. })
  419. MakeTerm("tt", "Alpha", "zsh")
  420. MakeTerm("ts", "Beta", "zsh")
  421. MakeTerm("tr", "Gamma", "zsh")
  422. MakeTerm("ta", "Delta", "zsh")
  423. MakeTerm("tn", "Epsilon", "gemini --model gemini-2.5-pro")
  424. MakeTerm("te", "Zeta", "/bin/zsh $DOTFILES_DIR/.scripts/omniscratch.zsh")
  425. MakeTerm("ti", "Eta", "lazydocker", true)
  426. MakeTerm("to", "Theta", "lazygit", true)
  427. vim.keymap.set("t", "<C-S-t>", "<C-\\><C-n>")
  428. vim.keymap.set("t", "<S-Space>", "<Esc>")
  429. local timer_var = "lab_doubletap_timer"
  430. vim.keymap.set("t", "<Esc>", function()
  431. if vim.b[timer_var] then
  432. vim.fn.timer_stop(vim.b[timer_var])
  433. vim.b[timer_var] = nil
  434. lab.close_all()
  435. else
  436. vim.b[timer_var] = vim.fn.timer_start(150, function()
  437. vim.b[timer_var] = nil
  438. vim.api.nvim_chan_send(
  439. vim.b.terminal_job_id,
  440. vim.api.nvim_replace_termcodes("<Esc>", true, false, true))
  441. end)
  442. end
  443. end, { noremap = true, silent = true })
  444. end
  445. local function config_gitsigns()
  446. local gitsigns = require("gitsigns")
  447. gitsigns.setup {
  448. diff_opts = {
  449. internal = true,
  450. linematch = 1,
  451. algorithm = "minimal"
  452. },
  453. signcolumn = true,
  454. numhl = false,
  455. linehl = false,
  456. max_file_length = 50000,
  457. word_diff = false,
  458. auto_attach = true,
  459. attach_to_untracked = true
  460. }
  461. local pickers = require("telescope.pickers")
  462. local actions = require("telescope.actions")
  463. local action_state = require("telescope.actions.state")
  464. local finders = require("telescope.finders")
  465. local conf = require("telescope.config").values
  466. local entry_display = require("telescope.pickers.entry_display")
  467. local palette = require("command-palette")
  468. local open_picker = function(title, command)
  469. local displayer = entry_display.create({
  470. separator = " ▏",
  471. items = {
  472. { width = 16 }, { width = 64 }, { width = 24 },
  473. { remaining = true }
  474. }
  475. })
  476. local results = vim.split(vim.fn.system(
  477. "git log --branches=\\* --pretty='format:%H ||!|| %cr ||!|| %(decorate:prefix=,suffix=,separator= ) ||!|| %an ||!|| %s' --since='last month'"),
  478. "\n")
  479. pickers.new({}, {
  480. prompt_title = title,
  481. finder = finders.new_table({
  482. results = results,
  483. entry_maker = function(entry)
  484. local s = vim.split(entry, "||!||")
  485. return {
  486. value = s[1],
  487. display = function()
  488. return displayer({
  489. { s[2] }, { s[3] }, { s[4] }, { s[5] }
  490. })
  491. end,
  492. ordinal = string.format("%s %s", s[3], s[5])
  493. }
  494. end
  495. }),
  496. sorter = conf.generic_sorter(),
  497. attach_mappings = function(prompt_bufnr, _)
  498. actions.select_default:replace(function()
  499. actions.close(prompt_bufnr)
  500. local hash = action_state.get_selected_entry().value
  501. if command == "base" then
  502. vim.api.nvim_exec(
  503. ":Gitsigns change_base " .. hash .. " true",
  504. true)
  505. elseif command == "diff" then
  506. vim.api.nvim_exec(":Gitsigns diffthis " .. hash,
  507. true)
  508. end
  509. end)
  510. return true
  511. end
  512. }):find()
  513. end
  514. local open_diff_picker =
  515. function()
  516. open_picker("Gitsigns Diff", "diff")
  517. end
  518. local open_base_picker = function()
  519. open_picker("Gitsigns Change Base", "base")
  520. end
  521. vim.keymap.set("n", "Sgd", open_diff_picker)
  522. vim.keymap.set("n", "Sgb", open_base_picker)
  523. palette.add({
  524. {
  525. "Gitsigns", "", {
  526. {
  527. "Diff file",
  528. "Open the Gitsigns differ for this file",
  529. open_diff_picker
  530. },
  531. {
  532. "Change diff base",
  533. "Change base branch for Gitsigns to diff again",
  534. open_base_picker
  535. }
  536. }
  537. }
  538. })
  539. end
  540. local function config_proj_conf()
  541. require("proj-conf").setup()
  542. end
  543. local function config_vim_dirtytalk()
  544. vim.opt.spelllang = { "en_us", "programming" }
  545. end
  546. local function config_jonathandarker()
  547. vim.cmd.colorscheme("jonathandarker")
  548. vim.opt.list = true
  549. vim.opt.fillchars = "horiz:-," .. "horizup:-," .. "horizdown:-," ..
  550. "vert:¦," .. "verthoriz:¦," ..
  551. "vertleft:¦," .. "vertright:¦," ..
  552. "eob:⠀"
  553. vim.opt.listchars = "extends:›," .. "precedes:‹," ..
  554. "tab:\\ ," .. "nbsp:·," .. "trail:·," ..
  555. "space:·"
  556. end
  557. local function config_status_beast()
  558. require("status-beast.highlights").setup()
  559. require("status-beast").setup()
  560. vim.api.nvim_create_autocmd({ "BufEnter" },
  561. {
  562. group = vim.api.nvim_create_augroup('StatusBeast',
  563. { clear = true }),
  564. callback = function (args)
  565. if vim.bo[args.buf].filetype == "aerial" then
  566. return
  567. end
  568. require("status-beast").setup()
  569. end
  570. })
  571. vim.diagnostic.config({
  572. virtual_lines = {
  573. current_line = true,
  574. format = function(d)
  575. return "[" .. d.source .. "] " .. d.message
  576. end
  577. },
  578. float = false,
  579. virtual_text = false,
  580. update_in_insert = true
  581. })
  582. local palette = require("command-palette")
  583. palette.add({
  584. {
  585. "Status Beast", "Options for status bars and columns", { {
  586. "Toggle Relnum", "Toggle relative line numbers on/off",
  587. ":setl rnu!" } } }
  588. })
  589. end
  590. local function config_jxdash()
  591. require("jxdash").setup()
  592. end
  593. local function config_virt_column()
  594. vim.opt.colorcolumn = tostring(80 + 1)
  595. local cc_group = vim.api.nvim_create_augroup("colorcolumn",
  596. { clear = true })
  597. local filetype_colorcolumn_map = {
  598. python = 88,
  599. kotlin = 100,
  600. julia = 92
  601. }
  602. vim.api.nvim_create_autocmd({ "FileType" }, {
  603. pattern = { "*" },
  604. group = cc_group,
  605. callback = function(event)
  606. local filetype = vim.bo[event.buf].filetype
  607. local colorcolumn = filetype_colorcolumn_map[filetype]
  608. if colorcolumn == nil then
  609. colorcolumn = 80
  610. end
  611. for _, w in pairs(vim.api.nvim_list_wins()) do
  612. if vim.api.nvim_win_get_buf(w) == event.buf then
  613. vim.wo[w].colorcolumn = tostring(colorcolumn + 1)
  614. end
  615. end
  616. end
  617. })
  618. require("virt-column").setup({ char = "⁚" })
  619. end
  620. local function config_telescope()
  621. local builtin = require("telescope.builtin")
  622. require("telescope").setup({
  623. extensions = {
  624. ["ui-select"] = { require("telescope.themes").get_dropdown() }
  625. },
  626. defaults = {
  627. ["borderchars"] = {
  628. "-", "¦", "-", "¦", "⌌", "⌍", "⌏", "⌎"
  629. },
  630. layout_strategy = "horizontal",
  631. layout_config = {
  632. horizontal = { width = { padding = 0 }, height = 0.99 }
  633. },
  634. cache_picker = {
  635. num_pickers = 100,
  636. limit_entries = 100,
  637. ignore_empty_prompt = true
  638. }
  639. },
  640. pickers = {
  641. live_grep = {
  642. additional_args = function(_)
  643. return { "--hidden", "--glob=!**/.git/*" }
  644. end
  645. }
  646. }
  647. })
  648. vim.keymap.set("n", "<Leader>f", function()
  649. require("telescope").extensions.file_browser.file_browser({
  650. select_buffer = true,
  651. grouped = true,
  652. no_ignore = true,
  653. hidden = true,
  654. respect_gitignore = false,
  655. path = vim.fn.expand("%:p:h")
  656. })
  657. end, {})
  658. vim.keymap.set("n", "<Leader>s", builtin.resume)
  659. vim.keymap.set("n", "<Leader>S", builtin.pickers)
  660. vim.keymap.set("n", "<Leader>T", builtin.treesitter)
  661. vim.keymap.set("n", "<Leader>a", builtin.find_files)
  662. vim.keymap.set("n", "<Leader>g", builtin.git_files)
  663. vim.keymap.set("n", "<Leader>G", builtin.git_status)
  664. vim.keymap.set("n", "<Leader>b", builtin.buffers)
  665. vim.keymap.set("n", "<Leader>j", builtin.jumplist)
  666. vim.keymap.set("n", "<Leader>w", builtin.grep_string)
  667. vim.keymap.set("n", "<Leader>ld", builtin.lsp_definitions)
  668. vim.keymap.set("n", "<Leader>lt", builtin.lsp_type_definitions)
  669. vim.keymap.set("n", "<Leader>lr", builtin.lsp_references)
  670. vim.keymap.set("n", "<Leader>li", builtin.lsp_implementations)
  671. vim.keymap.set("n", "<Leader>ls", builtin.lsp_document_symbols)
  672. vim.keymap.set("n", "<Leader>lS", builtin.lsp_workspace_symbols)
  673. require("telescope").load_extension("ui-select")
  674. require("telescope").load_extension("file_browser")
  675. end
  676. local function config_telescope_file_browser()
  677. require("telescope").setup({
  678. extensions = {
  679. file_browser = {
  680. respect_gitignore = false,
  681. hidden = { file_browser = true, folder_browser = true },
  682. hijack_netrw = true,
  683. display_stat = { date = false, size = true, mode = false },
  684. mappings = {}
  685. }
  686. }
  687. })
  688. require("telescope").load_extension("file_browser")
  689. end
  690. local function config_telescope_shroud()
  691. local shroud = require("telescope-shroud")
  692. local palette = require("command-palette")
  693. palette.add({
  694. {
  695. "Telescope Shroud", "Telescope `grep` filter management", { {
  696. "Populate", "Reload the list of filter options", shroud.populate
  697. }, {
  698. "Clear default", "Reset the default filters", function()
  699. shroud.set_default({})
  700. end
  701. }, {
  702. "Set default", "Set the default filters", shroud.set_default }, {
  703. "Open default", "Set the default filters", shroud.open_default }, {
  704. "Open narrow", "Set the default filters", shroud.open_narrow } } }
  705. })
  706. vim.keymap.set("n", "<Leader>i", shroud.open_default)
  707. vim.keymap.set("n", "<Leader>I", shroud.open_narrow)
  708. end
  709. local function config_nvim_surround()
  710. require("nvim-surround").setup({})
  711. end
  712. local function config_nvim_treesitter_textobjects()
  713. require("nvim-treesitter.configs").setup({
  714. textobjects = {
  715. select = {
  716. enable = true,
  717. lookahead = true,
  718. keymaps = {
  719. ["af"] = "@function.outer",
  720. ["if"] = "@function.inner",
  721. ["ac"] = "@class.outer",
  722. ["ic"] = "@class.inner",
  723. ["ap"] = "@parameter.outer",
  724. ["ip"] = "@parameter.inner",
  725. ["aa"] = "@parameter.outer",
  726. ["ia"] = "@parameter.inner",
  727. ["al"] = "@loop.outer",
  728. ["il"] = "@loop.inner",
  729. ["at"] = "@attribute.outer",
  730. ["it"] = "@attribute.inner",
  731. ["a="] = "@assignment.outer",
  732. ["i="] = "@assignment.inner",
  733. ["ab"] = "@block.outer",
  734. ["ib"] = "@block.inner"
  735. },
  736. include_surrounding_whitespace = true
  737. },
  738. swap = {
  739. enable = true,
  740. swap_next = {
  741. ["csf"] = "@function.inner",
  742. ["csc"] = "@class.inner",
  743. ["csp"] = "@parameter.inner",
  744. ["csa"] = "@parameter.inner",
  745. ["csl"] = "@loop.inner",
  746. ["cst"] = "@attribute.inner",
  747. ["cs="] = "@assignment.inner",
  748. ["csb"] = "@block.inner"
  749. },
  750. swap_previous = {
  751. ["cSf"] = "@function.inner",
  752. ["cSc"] = "@class.inner",
  753. ["cSp"] = "@parameter.inner",
  754. ["cSa"] = "@parameter.inner",
  755. ["cSl"] = "@loop.inner",
  756. ["cSt"] = "@attribute.inner",
  757. ["cS="] = "@assignment.inner",
  758. ["cSb"] = "@block.inner"
  759. }
  760. }
  761. }
  762. })
  763. end
  764. local function config_nvim_treesitter()
  765. local api = require("nvim-treesitter.configs")
  766. api.setup({
  767. ensure_installed = "all",
  768. sync_install = false,
  769. auto_install = true,
  770. ignore_install = { "ipkg" },
  771. highlight = {
  772. enable = true,
  773. additional_vim_regex_highlighting = false
  774. }
  775. })
  776. vim.opt.foldmethod = "expr"
  777. vim.opt.foldexpr = "nvim_treesitter#foldexpr()"
  778. vim.api.nvim_create_autocmd("LspAttach", {
  779. callback = function(args)
  780. local client = vim.lsp.get_client_by_id(args.data.client_id)
  781. if vim.treesitter ~= nil and client ~= nil and
  782. type(vim.treesitter.highlighter.active[args.buf]) ~= "nil" then
  783. client.server_capabilities.semanticTokensProvider = nil
  784. end
  785. end
  786. })
  787. end
  788. local function config_nvim_treesitter_context()
  789. require("treesitter-context").setup({
  790. enable = true,
  791. max_lines = 5,
  792. min_window_height = 0,
  793. line_numbers = true,
  794. multiline_threshold = 20,
  795. trim_scope = "outer",
  796. mode = "cursor",
  797. zindex = 20,
  798. on_attach = nil
  799. })
  800. vim.api.nvim_set_hl(0, "TreesitterContextSeparator",
  801. { link = "WinSeparator" })
  802. vim.keymap.set("n", "<Leader>c", function()
  803. require("treesitter-context").go_to_context(vim.v.count1)
  804. end, { silent = true })
  805. end
  806. local function config_aerial()
  807. require("aerial").setup({
  808. backends = { "treesitter", "lsp" },
  809. attach_mode = "global",
  810. highlight_closest = true,
  811. autojump = true,
  812. layout = {
  813. default_direction = "left",
  814. width = 40,
  815. placement = "window",
  816. winopts = {
  817. statuscolumn = ""
  818. }
  819. },
  820. nerd_font = "auto",
  821. icons = {
  822. Array = "[a]",
  823. Boolean = "[b]",
  824. Class = "[C]",
  825. Constant = "[const]",
  826. Constructor = "[Co]",
  827. Enum = "[E]",
  828. EnumMember = "[em]",
  829. Event = "[Ev]",
  830. Field = "[Fld]",
  831. File = "[File]",
  832. Function = "[F]",
  833. Interface = "[I]",
  834. Key = "[K]",
  835. Method = "[M]",
  836. Module = "[Mod]",
  837. Namespace = "[NS]",
  838. Null = "[-]",
  839. Number = "[n]",
  840. Object = "[o]",
  841. Operator = "[+]",
  842. Package = "[Pkg]",
  843. Property = "[P]",
  844. String = "[str]",
  845. Struct = "[S]",
  846. TypeParameter = "[T]",
  847. Variable = "[V]",
  848. Collapsed = "▶",
  849. },
  850. on_attach = function(bufnr)
  851. vim.keymap.set("n", "[[", "<cmd>AerialPrev<CR>", { buffer = bufnr })
  852. vim.keymap.set("n", "]]", "<cmd>AerialNext<CR>", { buffer = bufnr })
  853. end,
  854. })
  855. vim.keymap.set("n", "Sa", ":AerialOpen<CR>")
  856. vim.keymap.set("n", "SA", ":AerialToggle!<CR>")
  857. vim.api.nvim_create_autocmd({ "FileType", "BufEnter" }, {
  858. group = vim.api.nvim_create_augroup("AerialConfig", { clear = true }),
  859. callback = function(args)
  860. for _, win in ipairs(vim.fn.getwininfo()) do
  861. if (win.bufnr == args.buf) then
  862. vim.wo[win.winid].statuscolumn = ""
  863. end
  864. end
  865. end,
  866. })
  867. end
  868. local setup_plugins = function()
  869. config_jonathandarker()
  870. config_nvim_treesitter()
  871. config_vim_dirtytalk()
  872. config_virt_column()
  873. config_nvim_surround()
  874. config_like_a_butterfly()
  875. config_nvim_cmp()
  876. config_telescope()
  877. config_jxdash()
  878. config_nvim_treesitter_textobjects()
  879. config_nvim_treesitter_context()
  880. config_aerial()
  881. config_telescope_file_browser()
  882. config_command_palette()
  883. config_maj_peg()
  884. config_bit_browser()
  885. config_save_formatter()
  886. config_pandoctrinated()
  887. config_gitsigns()
  888. config_telescope_shroud()
  889. config_proj_conf()
  890. config_status_beast()
  891. end
  892. setup_plugins()