├── init.lua ├── scripts ├── .gitignore └── benchmark.ts ├── .styluaignore ├── after ├── ftplugin │ ├── gp.lua │ ├── systemverilog.lua │ ├── http.lua │ ├── typescript.lua │ ├── typescriptreact.lua │ ├── help.lua │ ├── rust.lua │ ├── markdown.lua │ ├── json.lua │ └── toml.lua └── queries │ └── markdown │ └── injections.scm ├── lua ├── user │ ├── plugins │ │ ├── edit │ │ │ ├── venn.lua │ │ │ ├── gtd.lua │ │ │ ├── luasnip.lua │ │ │ ├── flash.lua │ │ │ ├── init.lua │ │ │ ├── molten.lua │ │ │ ├── insx.lua │ │ │ └── cmp.lua │ │ ├── tools │ │ │ ├── vim-startuptime.lua │ │ │ ├── muren.lua │ │ │ ├── suda.lua │ │ │ ├── grug-far.lua │ │ │ ├── ccc.lua │ │ │ ├── bufferlist.lua │ │ │ ├── aerial.lua │ │ │ ├── trouble.lua │ │ │ ├── mini.lua │ │ │ ├── oil.lua │ │ │ ├── overseer.lua │ │ │ ├── snacks.lua │ │ │ ├── hlslens.lua │ │ │ ├── skkleton.lua │ │ │ ├── toggleterm.lua │ │ │ ├── smart-splits.lua │ │ │ ├── telescope.lua │ │ │ └── nvim-tree.lua │ │ ├── external │ │ │ ├── dadbod.lua │ │ │ ├── chezmoi.lua │ │ │ └── fmo.lua │ │ ├── appearance │ │ │ ├── nougat │ │ │ │ ├── setup.lua │ │ │ │ ├── statusline │ │ │ │ │ ├── inactive.lua │ │ │ │ │ ├── init.lua │ │ │ │ │ ├── explorer.lua │ │ │ │ │ └── active.lua │ │ │ │ ├── winbar │ │ │ │ │ ├── init.lua │ │ │ │ │ ├── explorer.lua │ │ │ │ │ ├── inactive.lua │ │ │ │ │ └── active.lua │ │ │ │ ├── nut │ │ │ │ │ ├── buf │ │ │ │ │ │ ├── navic.lua │ │ │ │ │ │ ├── filetype.lua │ │ │ │ │ │ ├── filename.lua │ │ │ │ │ │ ├── encoding.lua │ │ │ │ │ │ ├── fileformat.lua │ │ │ │ │ │ ├── copilot.lua │ │ │ │ │ │ ├── fmo.lua │ │ │ │ │ │ ├── icon.lua │ │ │ │ │ │ └── lsp_servers.lua │ │ │ │ │ ├── git │ │ │ │ │ │ ├── branch.lua │ │ │ │ │ │ └── status.lua │ │ │ │ │ └── mode.lua │ │ │ │ ├── tabline.lua │ │ │ │ └── common.lua │ │ │ ├── nougat.lua │ │ │ ├── satellite.lua │ │ │ ├── highlight-colors.lua │ │ │ ├── init.lua │ │ │ ├── dressing.lua │ │ │ ├── fidget.lua │ │ │ ├── ufo.lua │ │ │ └── kanagawa.lua │ │ ├── lsp │ │ │ ├── glance.lua │ │ │ ├── lspconfig.lua │ │ │ └── init.lua │ │ ├── git │ │ │ ├── neogit.lua │ │ │ ├── fugitive.lua │ │ │ ├── gitsigns.lua │ │ │ └── diffview.lua │ │ ├── common │ │ │ ├── hydra.lua │ │ │ ├── init.lua │ │ │ ├── mason.lua │ │ │ ├── hydra │ │ │ │ ├── venn.lua │ │ │ │ └── windows.lua │ │ │ └── possession.lua │ │ ├── ai │ │ │ ├── codecompanion.lua │ │ │ ├── copilot.lua │ │ │ └── codecompanion │ │ │ │ └── fidget.lua │ │ ├── debug │ │ │ └── dap.lua │ │ ├── treesitter │ │ │ └── init.lua │ │ └── language │ │ │ ├── flutter.lua │ │ │ └── init.lua │ ├── shared │ │ ├── json │ │ │ ├── README.md │ │ │ ├── jsonc.lua │ │ │ └── init.lua │ │ ├── utils │ │ │ ├── lua.lua │ │ │ ├── system.lua │ │ │ ├── typst.lua │ │ │ └── vim.lua │ │ └── lsp-selector │ │ │ └── web.lua │ ├── lsp │ │ ├── server-configs │ │ │ ├── eslint.lua │ │ │ ├── fsautocomplete.lua │ │ │ ├── clangd.lua │ │ │ ├── biome.lua │ │ │ ├── pyright.lua │ │ │ ├── mdx-analyzer.lua │ │ │ ├── tsserver.lua │ │ │ ├── yamlls.lua │ │ │ ├── rust_analyzer.lua │ │ │ ├── omnisharp.lua │ │ │ ├── jsonls.lua │ │ │ ├── lua_ls.lua │ │ │ ├── basedpyright.lua │ │ │ ├── vtsls.lua │ │ │ ├── sqls.lua │ │ │ ├── texlab.lua │ │ │ ├── tailwindcss.lua │ │ │ ├── tinymist.lua │ │ │ └── denols.lua │ │ ├── init.lua │ │ ├── settings-json.lua │ │ ├── config-builder.lua │ │ └── attach.lua │ ├── ginit.lua │ ├── local-template │ │ ├── README.md │ │ ├── early-init.lua │ │ ├── init.lua │ │ └── plugins.lua │ ├── init.lua │ ├── profile.lua │ ├── args.lua │ ├── config │ │ ├── filetype.lua │ │ ├── keymaps.lua │ │ └── options.lua │ ├── lazy.lua │ └── early-init.lua ├── nougat │ └── color │ │ └── kanagawa.lua ├── overseer │ ├── template │ │ └── user │ │ │ ├── ngspice.lua │ │ │ ├── gnuplot_run.lua │ │ │ ├── typst_watch.lua │ │ │ ├── flutter_run.lua │ │ │ ├── gcc_run.lua │ │ │ ├── iverilog_run.lua │ │ │ ├── deno_file.lua │ │ │ └── typst_watch_root.lua │ └── component │ │ └── user │ │ └── remove_winbar.lua └── telescope │ └── _extensions │ └── fidget2.lua ├── .gitignore ├── stylua.toml ├── .neoconf.json ├── README.md └── .github └── workflows └── benchmark.yml /init.lua: -------------------------------------------------------------------------------- 1 | require "user" 2 | -------------------------------------------------------------------------------- /scripts/.gitignore: -------------------------------------------------------------------------------- 1 | data.json 2 | -------------------------------------------------------------------------------- /.styluaignore: -------------------------------------------------------------------------------- 1 | plugin/ 2 | profile.nvim/ 3 | -------------------------------------------------------------------------------- /after/ftplugin/gp.lua: -------------------------------------------------------------------------------- 1 | vim.bo.commentstring = "# %s" 2 | -------------------------------------------------------------------------------- /after/ftplugin/systemverilog.lua: -------------------------------------------------------------------------------- 1 | vim.o.commentstring = "// %s" 2 | -------------------------------------------------------------------------------- /after/ftplugin/http.lua: -------------------------------------------------------------------------------- 1 | map("n", "", "RestNvim", { remap = true, buffer = true }) 2 | -------------------------------------------------------------------------------- /lua/user/plugins/edit/venn.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "jbyuki/venn.nvim", 3 | cmd = "VBox", 4 | } 5 | -------------------------------------------------------------------------------- /after/ftplugin/typescript.lua: -------------------------------------------------------------------------------- 1 | vim.cmd.compiler "tsc" 2 | vim.opt_local.makeprg = "npx tsc --noEmit" 3 | -------------------------------------------------------------------------------- /after/ftplugin/typescriptreact.lua: -------------------------------------------------------------------------------- 1 | vim.cmd.compiler "tsc" 2 | vim.opt_local.makeprg = "npx tsc --noEmit" 3 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/vim-startuptime.lua: -------------------------------------------------------------------------------- 1 | return { "dstein64/vim-startuptime", cmd = { "StartupTime" } } 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | flame.svg 3 | lazy-lock.json 4 | lua/user/local/* 5 | .luarc.json 6 | profile.nvim 7 | profile.json 8 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/muren.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "AckslD/muren.nvim", 3 | config = true, 4 | cmd = { "MurenToggle", "MurenOpen" }, 5 | } 6 | -------------------------------------------------------------------------------- /lua/user/shared/json/README.md: -------------------------------------------------------------------------------- 1 | # json.lua 2 | 3 | Taken from [json.lua](https://github.com/actboy168/json.lua). 4 | 5 | This is used to parse JSONC. 6 | -------------------------------------------------------------------------------- /after/ftplugin/help.lua: -------------------------------------------------------------------------------- 1 | map("n", "K", function() 2 | local word = vim.fn.expand "" 3 | vim.cmd("help " .. word) 4 | end) 5 | vim.opt_local.number = true 6 | -------------------------------------------------------------------------------- /stylua.toml: -------------------------------------------------------------------------------- 1 | column_width = 120 2 | line_endings = "Unix" 3 | indent_type = "Spaces" 4 | indent_width = 2 5 | quote_style = "AutoPreferDouble" 6 | no_call_parentheses = true 7 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/eslint.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | workspace_required = true, 5 | } 6 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/suda.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "lambdalisue/suda.vim", 3 | event = { "BufReadPre" }, 4 | init = function() 5 | vim.g.suda_smart_edit = 1 6 | end, 7 | } 8 | -------------------------------------------------------------------------------- /lua/user/ginit.lua: -------------------------------------------------------------------------------- 1 | if vim.g.neovide then 2 | vim.opt.guifont = "PlemolJP Console NF:h12" 3 | elseif vim.g.fvim_loaded then 4 | vim.opt.guifont = "PlemolJP Console NF:h15" 5 | end 6 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/grug-far.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "MagicDuck/grug-far.nvim", 3 | keys = { { mode = { "n" }, "S", "GrugFar" } }, 4 | cmd = { "GrugFar" }, 5 | opts = {}, 6 | } 7 | -------------------------------------------------------------------------------- /lua/user/local-template/README.md: -------------------------------------------------------------------------------- 1 | # About this directory 2 | 3 | This directory contains some snippets of code that can be used locally. To use 4 | them, copy them to the file under `user/local` dir. 5 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/fsautocomplete.lua: -------------------------------------------------------------------------------- 1 | local create_config = require("user.lsp.config-builder").create_config 2 | 3 | return function(server) 4 | require("ionide").setup(create_config()) 5 | end 6 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/clangd.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | cmd = { 5 | "clangd", 6 | "--offset-encoding=utf-16", 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/biome.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | root_dir = function(bufnr, cb) 5 | cb(vim.fs.root(bufnr, "biome.json")) 6 | end, 7 | } 8 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/pyright.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | root_dir = function(bufnr, cb) 5 | cb(vim.fs.root(bufnr, "pyproject.toml")) 6 | end, 7 | } 8 | -------------------------------------------------------------------------------- /lua/user/plugins/external/dadbod.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "tpope/vim-dadbod", 3 | dependencies = { 4 | "kristijanhusak/vim-dadbod-completion", 5 | "kristijanhusak/vim-dadbod-ui", 6 | }, 7 | cmd = { "DB", "DBUI", "DBUIToggle" }, 8 | } 9 | -------------------------------------------------------------------------------- /after/ftplugin/rust.lua: -------------------------------------------------------------------------------- 1 | map("n", "rm", "RustLsp expandMacro", { buffer = true, desc = "[rust] Expand macro" }) 2 | map("n", "rd", "RustLsp externalDocs", { buffer = true, desc = "[rust] External docs (docs.rs)" }) 3 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/mdx-analyzer.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | init_options = { 5 | typescript = { 6 | enabled = true, 7 | }, 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/tsserver.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | root_dir = function(bufnr, cb) 5 | cb(vim.fs.root(bufnr, { "package.json", "tsconfig.json" })) 6 | end, 7 | } 8 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/yamlls.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | return create_setup { 3 | on_attach = function(client, bufnr) 4 | client.server_capabilities.documentFormattingProvider = true 5 | end, 6 | } 7 | -------------------------------------------------------------------------------- /lua/nougat/color/kanagawa.lua: -------------------------------------------------------------------------------- 1 | local mod = {} 2 | 3 | function mod.get() 4 | ---@class nougat.color 5 | ---@field palette PaletteColors 6 | local color = { palette = _G.color_palette } 7 | -- set the values here 8 | return color 9 | end 10 | 11 | return mod 12 | -------------------------------------------------------------------------------- /lua/user/plugins/edit/gtd.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "hrsh7th/nvim-gtd", 3 | init = function() 4 | map("n", "gf", function() 5 | require("gtd").exec { command = "edit" } 6 | end) 7 | end, 8 | config = function() 9 | require("gtd").setup {} 10 | end, 11 | } 12 | -------------------------------------------------------------------------------- /lua/user/local-template/early-init.lua: -------------------------------------------------------------------------------- 1 | -- `local/early-init.lua` is executed before all other config is loaded. 2 | 3 | -- For example, you can change `Args`. 4 | -- For more detail, see `args.lua`. 5 | Args.feature.copilot = false 6 | vim.list_extend(Args.lsp.local_servers, { "nil_ls" }) 7 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/ccc.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "uga-rosa/ccc.nvim", 3 | cmd = { "CccPick" }, 4 | event = { "BufRead" }, 5 | config = function() 6 | require("ccc").setup { 7 | highlighter = { 8 | auto_enable = false, 9 | }, 10 | } 11 | end, 12 | } 13 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/rust_analyzer.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | settings = { 5 | ["rust-analyzer"] = { 6 | check = { 7 | command = "clippy", 8 | }, 9 | }, 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/omnisharp.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | handlers = { 5 | ["textDocument/definition"] = function(...) 6 | require("omnisharp_extended").handler(...) 7 | end, 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/setup.lua: -------------------------------------------------------------------------------- 1 | local nougat = require "nougat" 2 | 3 | nougat.set_statusline(require "user.plugins.appearance.nougat.statusline") 4 | nougat.set_tabline(require "user.plugins.appearance.nougat.tabline") 5 | nougat.set_winbar(require "user.plugins.appearance.nougat.winbar") 6 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/bufferlist.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "EL-MASTOR/bufferlist.nvim", 4 | lazy = true, 5 | keys = { { "", ":BufferList", desc = "Open bufferlist" } }, 6 | dependencies = { "echasnovski/mini.icons" }, 7 | cmd = "BufferList", 8 | opts = {}, 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "MunifTanjim/nougat.nvim", 3 | lazy = false, 4 | enabled = not Args.feature.vscode, 5 | dependencies = { "rebelot/kanagawa.nvim", "echasnovski/mini.icons" }, 6 | config = function() 7 | require "user.plugins.appearance.nougat.setup" 8 | end, 9 | } 10 | -------------------------------------------------------------------------------- /lua/user/plugins/lsp/glance.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "dnlhc/glance.nvim", 4 | cmd = { "Glance" }, 5 | config = function() 6 | local glance = require "glance" 7 | 8 | glance.setup { 9 | winbar = { 10 | enable = false, 11 | }, 12 | } 13 | end, 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /lua/user/plugins/git/neogit.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "NeogitOrg/neogit", 3 | cmd = { "Neogit" }, 4 | dependencies = { 5 | "nvim-lua/plenary.nvim", 6 | "sindrets/diffview.nvim", 7 | "nvim-telescope/telescope.nvim", 8 | }, 9 | ---@type NeogitConfig 10 | opts = { 11 | graph_style = "unicode", 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /lua/user/shared/utils/lua.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.script_path = function() 4 | local str = debug.getinfo(2, "S").source:sub(2) 5 | if M.is_win then 6 | str = str:gsub("/", "\\") 7 | end 8 | local separator = M.is_win and "\\" or "/" 9 | return str:match("(.*" .. separator .. ")") 10 | end 11 | 12 | return M 13 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/jsonls.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | return create_setup { 3 | filetypes = { "json", "jsonc" }, 4 | settings = { 5 | json = { 6 | schemas = require("schemastore").json.schemas(), 7 | validate = { enable = true }, 8 | }, 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/aerial.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "stevearc/aerial.nvim", 3 | event = "BufRead", 4 | cmd = "Aerial", 5 | init = function() 6 | -- map("n", "o", "AerialToggle") 7 | end, 8 | config = function() 9 | require("aerial").setup { 10 | filter_kind = false, 11 | } 12 | end, 13 | } 14 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/satellite.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "lewis6991/satellite.nvim", 3 | event = { "BufRead", "InsertEnter", "BufNewFile" }, 4 | config = function() 5 | require("satellite").setup { 6 | handlers = { 7 | gitsigns = { 8 | enable = false, 9 | }, 10 | }, 11 | } 12 | end, 13 | } 14 | -------------------------------------------------------------------------------- /lua/overseer/template/user/ngspice.lua: -------------------------------------------------------------------------------- 1 | return { 2 | name = "ngspice load", 3 | builder = function() 4 | local file = vim.fn.expand "%:p" 5 | return { 6 | cmd = { "ngspice" }, 7 | args = { file }, 8 | cwd = vim.fn.expand "%:p:h", 9 | } 10 | end, 11 | condition = { 12 | filetype = { "ngspice" }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/lua_ls.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | settings = { 5 | Lua = { 6 | diagnostics = { 7 | globals = { "vim" }, 8 | }, 9 | workspace = { 10 | checkThirdParty = false, 11 | }, 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /lua/overseer/template/user/gnuplot_run.lua: -------------------------------------------------------------------------------- 1 | return { 2 | name = "gnuplot", 3 | builder = function() 4 | local filename = vim.fn.expand "%:t" 5 | 6 | return { 7 | cmd = { "gnuplot" }, 8 | args = { filename }, 9 | cwd = vim.fn.expand "%:p:h", 10 | } 11 | end, 12 | condition = { 13 | filetype = { "gp" }, 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/statusline/inactive.lua: -------------------------------------------------------------------------------- 1 | local Bar = require "nougat.bar" 2 | local sep = require "nougat.separator" 3 | 4 | local c = require "user.plugins.appearance.nougat.common" 5 | local nut = c.nut 6 | local color = c.color 7 | 8 | local stl_inactive = Bar "statusline" 9 | do 10 | stl_inactive:add_item(nut.spacer()) 11 | end 12 | 13 | return stl_inactive 14 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/trouble.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/trouble.nvim", 3 | keys = { 4 | { 5 | "", 6 | "Trouble diagnostics toggle", 7 | desc = "Diagnostics (Trouble)", 8 | }, 9 | { 10 | "", 11 | "Trouble diagnostics toggle", 12 | desc = "Diagnostics (Trouble)", 13 | }, 14 | }, 15 | opts = {}, 16 | } 17 | -------------------------------------------------------------------------------- /.neoconf.json: -------------------------------------------------------------------------------- 1 | { 2 | "neoconf": { 3 | "plugins": { 4 | "lua_ls": { 5 | "enabled": true 6 | } 7 | } 8 | }, 9 | "lspconfig": { 10 | "lua_ls": { 11 | "Lua.completion.callSnippet": "Replace", 12 | "Lua.workspace.checkThirdParty": false, 13 | "Lua.diagnostics.disable": [ 14 | "missing-fields" 15 | ] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lua/user/init.lua: -------------------------------------------------------------------------------- 1 | require "user.profile" 2 | 3 | require "user.early-init" 4 | require "user.args" 5 | pcall(require, "user.local.early-init") 6 | 7 | if vim.fn.has "gui_running" == 1 then 8 | require "user.ginit" 9 | end 10 | 11 | require "user.config.options" 12 | require "user.lazy" 13 | require "user.config.filetype" 14 | require "user.config.keymaps" 15 | 16 | pcall(require, "user.local") 17 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/basedpyright.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | root_dir = function(bufnr, cb) 5 | local venv = vim.fs.root(bufnr, { ".venv" }) 6 | if venv ~= nil then 7 | cb(venv) 8 | return 9 | end 10 | 11 | cb(vim.fs.root(bufnr, { "pyproject.toml", "requirements.txt" })) 12 | end, 13 | } 14 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/vtsls.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | local node_or_deno = require("user.shared.lsp-selector.web").judge 3 | 4 | return create_setup(function() 5 | return { 6 | root_dir = function(bufnr, cb) 7 | if node_or_deno(bufnr).type == "node" then 8 | cb(node_or_deno(bufnr).root) 9 | end 10 | end, 11 | } 12 | end) 13 | -------------------------------------------------------------------------------- /lua/overseer/template/user/typst_watch.lua: -------------------------------------------------------------------------------- 1 | return { 2 | name = "typst watch", 3 | builder = function() 4 | local filename = vim.fn.expand "%:t" 5 | local pdfname = vim.fn.expand "%:t:r" .. ".pdf" 6 | 7 | return { 8 | cmd = { "typst" }, 9 | args = { "watch", filename, pdfname }, 10 | cwd = vim.fn.expand "%:p:h", 11 | } 12 | end, 13 | condition = { 14 | filetype = { "typst" }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/sqls.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | on_attach = function(client, bufnr) 5 | require("sqls").on_attach(client, bufnr) 6 | end, 7 | settings = { 8 | sqls = { 9 | connections = { 10 | { 11 | driver = "sqlite3", 12 | dataSourceName = "../db", 13 | }, 14 | }, 15 | }, 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /lua/user/plugins/common/hydra.lua: -------------------------------------------------------------------------------- 1 | local hydras = { 2 | require "user.plugins.common.hydra.venn", 3 | -- require "user.plugins.common.hydra.windows", 4 | } 5 | 6 | local keys = {} 7 | for _, hydra in ipairs(hydras) do 8 | table.insert(keys, hydra.key) 9 | end 10 | 11 | return { 12 | "nvimtools/hydra.nvim", 13 | keys = keys, 14 | config = function() 15 | for _, hydra in ipairs(hydras) do 16 | hydra.setup() 17 | end 18 | end, 19 | } 20 | -------------------------------------------------------------------------------- /lua/overseer/template/user/flutter_run.lua: -------------------------------------------------------------------------------- 1 | return { 2 | name = "flutter run", 3 | builder = function() 4 | local root_dir = vim.fs.root(0, "pubspec.yaml") 5 | if root_dir == nil then 6 | return false, "Failed to find pubspec.yaml" 7 | end 8 | return { 9 | cmd = { "flutter" }, 10 | args = { "run" }, 11 | cwd = vim.fn.expand(root_dir), 12 | } 13 | end, 14 | condition = { 15 | filetype = { "dart" }, 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /after/ftplugin/markdown.lua: -------------------------------------------------------------------------------- 1 | local ext = vim.fn.fnamemodify(vim.fn.bufname(), ":e") 2 | 3 | if ext == "ipynb" then 4 | require("quarto").activate() 5 | local runner = require "quarto.runner" 6 | 7 | vim.keymap.set("n", "ip", function() 8 | vim.cmd "MoltenInit python3" 9 | end, { desc = "Initialize Molten for python3", buffer = true }) 10 | vim.keymap.set("n", "rc", runner.run_cell, { desc = "run cell", silent = true, buffer = true }) 11 | end 12 | -------------------------------------------------------------------------------- /lua/user/plugins/git/fugitive.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "tpope/vim-fugitive", 3 | cmd = { 4 | "G", 5 | "Git", 6 | "Gdiffsplit", 7 | "Gread", 8 | "Gwrite", 9 | "Ggrep", 10 | "GMove", 11 | "GDelete", 12 | "GBrowse", 13 | "GRemove", 14 | "GRename", 15 | "Glgrep", 16 | "Gedit", 17 | "Gvdiffsplit", 18 | "Gvsplit", 19 | "Gtabedit", 20 | "Gsplit", 21 | "Gvedit", 22 | "Gwrite", 23 | "Gw", 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /lua/user/plugins/common/init.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { "jghauser/mkdir.nvim", event = { "BufWritePre" } }, 3 | 4 | { "vim-jp/vimdoc-ja", event = { "CmdlineEnter" } }, 5 | 6 | { "MunifTanjim/nui.nvim" }, 7 | 8 | { 9 | "echasnovski/mini.icons", 10 | module = "nvim-web-devicons", 11 | version = false, 12 | lazy = false, 13 | config = function() 14 | require("mini.icons").setup() 15 | MiniIcons.mock_nvim_web_devicons() 16 | end, 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/highlight-colors.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "brenoprata10/nvim-highlight-colors", 3 | cmd = { "HighlightColors" }, 4 | event = { "BufRead" }, 5 | -- I found out that tinymist crashes with documentColor lsp request, so temporarily disabled 6 | enabled = false, 7 | config = function() 8 | require("nvim-highlight-colors").setup { 9 | render = "virtual", 10 | enable_tailwind = true, 11 | enable_short_hex = false, 12 | } 13 | end, 14 | } 15 | -------------------------------------------------------------------------------- /lua/user/plugins/git/gitsigns.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "lewis6991/gitsigns.nvim", 3 | dependencies = { 4 | { "nvim-lua/plenary.nvim" }, 5 | }, 6 | event = "BufRead", 7 | cmd = "GitSigns", 8 | init = function() 9 | map("n", "", "lua require('gitsigns').toggle_current_line_blame()", { desc = "Stage hunk" }) 10 | end, 11 | config = function() 12 | require("gitsigns").setup { 13 | signcolumn = false, 14 | numhl = true, 15 | } 16 | end, 17 | } 18 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/mini.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "echasnovski/mini.clue", 4 | keys = { "" }, 5 | config = function() 6 | local miniclue = require "mini.clue" 7 | miniclue.setup { 8 | triggers = { 9 | { mode = "n", keys = "" }, 10 | { mode = "x", keys = "" }, 11 | }, 12 | window = { 13 | delay = 200, 14 | config = { 15 | width = "auto", 16 | }, 17 | }, 18 | } 19 | end, 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /lua/overseer/template/user/gcc_run.lua: -------------------------------------------------------------------------------- 1 | return { 2 | name = "gcc build and run", 3 | builder = function() 4 | local file = vim.fn.expand "%:p" 5 | local file_basename = vim.fn.fnamemodify(file, ":t:r") 6 | local output = vim.fn.fnamemodify(vim.fn.expand "%:p:h", ":p") .. file_basename .. ".out" 7 | return { 8 | cmd = { "gcc" }, 9 | args = { file, "-o", output, "-lm", "&&", output }, 10 | cwd = vim.fn.expand "%:p:h", 11 | } 12 | end, 13 | condition = { 14 | filetype = { "c", "cpp" }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/init.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "eandrju/cellular-automaton.nvim", 4 | cmd = { "CellularAutomaton" }, 5 | }, 6 | { 7 | "OXY2DEV/helpview.nvim", 8 | ft = "help", 9 | submodules = false, 10 | dependencies = { 11 | "nvim-treesitter/nvim-treesitter", 12 | }, 13 | }, 14 | { 15 | "shortcuts/no-neck-pain.nvim", 16 | cmd = { "NoNeckPain" }, 17 | keys = { { "n", mode = { "n" }, "NoNeckPain" } }, 18 | opts = { 19 | width = 120, 20 | }, 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /lua/overseer/template/user/iverilog_run.lua: -------------------------------------------------------------------------------- 1 | return { 2 | name = "iverilog build and run", 3 | builder = function() 4 | local file = vim.fn.expand "%:p" 5 | local file_basename = vim.fn.fnamemodify(file, ":t:r") 6 | local output = vim.fn.fnamemodify(vim.fn.expand "%:p:h", ":p") .. file_basename .. ".out" 7 | return { 8 | cmd = { "iverilog" }, 9 | args = { file, "-o", output, "&&", output }, 10 | cwd = vim.fn.expand "%:p:h", 11 | } 12 | end, 13 | condition = { 14 | filetype = { "verilog", "systemverilog" }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /lua/user/plugins/lsp/lspconfig.lua: -------------------------------------------------------------------------------- 1 | return Args.feature.vscode and {} 2 | or { 3 | "neovim/nvim-lspconfig", 4 | dependencies = { 5 | { 6 | "mason-org/mason-lspconfig.nvim", 7 | dependencies = { { "williamboman/mason.nvim" } }, 8 | opts = { 9 | automatic_enable = false, 10 | }, 11 | }, 12 | { "j-hui/fidget.nvim" }, 13 | }, 14 | cmd = { "LspInfo", "LspLog" }, 15 | event = { "BufReadPre", "BufNewFile" }, 16 | config = function() 17 | require("user.lsp").setup() 18 | end, 19 | } 20 | -------------------------------------------------------------------------------- /after/queries/markdown/injections.scm: -------------------------------------------------------------------------------- 1 | ; extends 2 | ((inline) @injection.content 3 | (#lua-match? @injection.content "^%s*import") 4 | (#set! injection.language "typescript")) 5 | ((inline) @injection.content 6 | (#lua-match? @injection.content "export") 7 | (#set! injection.language "typescript")) 8 | ((inline) @injection.content 9 | (#lua-match? @injection.content "<.+/>") 10 | (#set! injection.language "typescriptreact")) 11 | ((inline) @injection.content 12 | (#lua-match? @injection.content "<.->.-") 13 | (#set! injection.language "typescriptreact")) 14 | -------------------------------------------------------------------------------- /lua/user/shared/utils/system.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.os = vim.loop.os_uname().sysname 4 | 5 | M.is_win = M.os == "Windows_NT" 6 | M.is_msys2 = M.is_win and vim.env.MINGW_PREFIX ~= nil 7 | 8 | local host_cached = nil 9 | M.get_host = function() 10 | if vim.fn.has "wsl" == 1 then 11 | if host_cached == nil then 12 | host_cached = vim.fn.system "cat /etc/resolv.conf | grep nameserver | cut -d ' ' -f 2" 13 | host_cached = host_cached:gsub("^%s*(.-)%s*$", "%1") 14 | end 15 | return host_cached 16 | end 17 | 18 | return "localhost" 19 | end 20 | 21 | return M 22 | -------------------------------------------------------------------------------- /lua/user/plugins/edit/luasnip.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "L3MON4D3/LuaSnip", 3 | dependencies = { 4 | { "rafamadriz/friendly-snippets" }, 5 | }, 6 | config = function() 7 | local luasnip = require "luasnip" 8 | 9 | luasnip.config.set_config { 10 | history = true, 11 | updateevents = "TextChanged,TextChangedI", 12 | } 13 | 14 | require("luasnip/loaders/from_vscode").lazy_load() 15 | 16 | map("i", "", function() 17 | luasnip.unlink_current() 18 | vim.cmd.stopinsert() 19 | end, { desc = "Escape snippet and stop insert mode" }) 20 | end, 21 | event = "InsertEnter", 22 | } 23 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/statusline/init.lua: -------------------------------------------------------------------------------- 1 | local stl_active = require "user.plugins.appearance.nougat.statusline.active" 2 | local stl_inactive = require "user.plugins.appearance.nougat.statusline.inactive" 3 | local stl_explorer = require "user.plugins.appearance.nougat.statusline.explorer" 4 | 5 | ---@param ctx nougat_core_expression_context 6 | return function(ctx) 7 | local filetype = vim.api.nvim_get_option_value("filetype", { buf = ctx.bufnr }) 8 | if filetype == "NvimTree" then 9 | return stl_explorer 10 | elseif ctx.is_focused then 11 | return stl_active 12 | else 13 | return stl_inactive 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lua/user/plugins/external/chezmoi.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "xvzc/chezmoi.nvim", 3 | dependencies = { "nvim-lua/plenary.nvim" }, 4 | init = function() 5 | vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { 6 | pattern = { "*/.local/share/chezmoi/*" }, 7 | callback = function(ev) 8 | local bufnr = ev.buf 9 | local edit_watch = function() 10 | require("chezmoi.commands.__edit").watch(bufnr) 11 | end 12 | vim.schedule(edit_watch) 13 | end, 14 | }) 15 | end, 16 | config = function() 17 | require("chezmoi").setup { 18 | -- your configurations 19 | } 20 | end, 21 | event = "BufReadPre", 22 | } 23 | -------------------------------------------------------------------------------- /lua/user/local-template/init.lua: -------------------------------------------------------------------------------- 1 | -- `local/init.lua` is executed after all other config is loaded. 2 | 3 | -- Setup lemonade clipboard for ssh 4 | local ssh_connection 5 | for w in vim.env.SSH_CONNECTION:gmatch "[^%s]+" do 6 | ssh_connection = w 7 | break 8 | end 9 | 10 | vim.g.clipboard = { 11 | name = "lemonade2", 12 | copy = { 13 | ["+"] = { "lemonade", "copy", "--host=" .. ssh_connection }, 14 | ["*"] = { "lemonade", "copy", "--host=" .. ssh_connection }, 15 | }, 16 | paste = { 17 | ["+"] = { "lemonade", "paste", "--host=" .. ssh_connection }, 18 | ["*"] = { "lemonade", "paste", "--host=" .. ssh_connection }, 19 | }, 20 | cache_enabled = 0, 21 | } 22 | -------------------------------------------------------------------------------- /lua/user/plugins/edit/flash.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/flash.nvim", 3 | ---@type Flash.Config 4 | opts = { 5 | modes = { 6 | search = { 7 | enabled = false, 8 | }, 9 | }, 10 | }, 11 | -- stylua: ignore 12 | keys = { 13 | { "s", mode = { "n", "o", "x" }, function() require("flash").jump() end, desc = "Flash" }, 14 | { "S", mode = { "n", "o", "x" }, function() require("flash").treesitter() end, desc = "Flash Treesitter" }, 15 | { "r", mode = "o", function() require("flash").remote() end, desc = "Remote Flash" }, 16 | { "R", mode = { "o", "x" }, function() require("flash").treesitter_search() end, desc = "Treesitter Search" }, 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /lua/user/local-template/plugins.lua: -------------------------------------------------------------------------------- 1 | return { 2 | -- Additional plugins 3 | { 4 | "romgrk/kirby.nvim", 5 | dependencies = { 6 | { "romgrk/fzy-lua-native", build = "make all" }, 7 | { "romgrk/kui.nvim" }, 8 | }, 9 | cmd = "KirbyFilePicker", 10 | }, 11 | -- Disable some plugins (local plugin spec is loaded last and can override config) 12 | { 13 | "aw-watcher-vim", 14 | enabled = false, 15 | }, 16 | -- Specify dir for plugin development 17 | { 18 | "docker-compose-info.nvim", 19 | dir = "~/dev/neovim/docker-compose-info.nvim", 20 | ft = "yaml", 21 | config = function() 22 | require("docker-compose-info").setup() 23 | end, 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nvim 2 | 3 | My neovim config. 4 | 5 | ## Setup 6 | 7 | ```bash 8 | cd ~/.config/nvim 9 | git clone https://github.com/nazo6/nvim 10 | nvim 11 | ``` 12 | 13 | ## Profiling 14 | 15 | 1. `git clone https://github.com/stevearc/profile.nvim` to config root 16 | 2. 17 | - To just enable profile `$env:NVIM_PROFILE=1 nvim`(powershell) 18 | or`NVIM_PROFILE=1 nvim` to start nvim. 19 | - Or to enable startup config profile execute 20 | `$env:NVIM_PROFILE=start nvim`(powershell) or`NVIM_PROFILE=start nvim`. 21 | 3. `` to toggle profile. 22 | 23 | ## Dependencies 24 | 25 | ### General 26 | 27 | - C compiler (treesitter) 28 | 29 | #### Windows 30 | 31 | - win32yank (wsl clipboard) 32 | 33 | #### Linux 34 | -------------------------------------------------------------------------------- /lua/user/plugins/common/mason.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "mason-org/mason.nvim", 3 | cmd = { "Mason", "MasonInstall" }, 4 | event = { "BufRead", "InsertEnter" }, 5 | dependencies = { 6 | { "WhoIsSethDaniel/mason-tool-installer.nvim" }, 7 | }, 8 | config = function() 9 | require("mason").setup { 10 | registries = { 11 | "github:mason-org/mason-registry", 12 | }, 13 | } 14 | 15 | -- local ensure_installed = {} 16 | -- 17 | -- require("mason-tool-installer").setup { 18 | -- ensure_installed = ensure_installed, 19 | -- auto_update = false, 20 | -- run_on_start = true, 21 | -- start_delay = 3000, 22 | -- } 23 | -- require("mason-tool-installer").run_on_start() 24 | end, 25 | } 26 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/winbar/init.lua: -------------------------------------------------------------------------------- 1 | local wbr_active = require "user.plugins.appearance.nougat.winbar.active" 2 | local wbr_inactive = require "user.plugins.appearance.nougat.winbar.inactive" 3 | local wbr_explorer = require "user.plugins.appearance.nougat.winbar.explorer" 4 | 5 | ---@param ctx nougat_core_expression_context 6 | return function(ctx) 7 | local filetype = vim.api.nvim_get_option_value("filetype", { buf = ctx.bufnr }) 8 | if filetype == "NvimTree" or filetype == "DiffviewFiles" then 9 | return wbr_explorer(ctx) 10 | elseif filetype == "no-neck-pain" then 11 | return require "nougat.bar" "winbar" 12 | elseif ctx.is_focused then 13 | return wbr_active 14 | else 15 | return wbr_inactive 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lua/overseer/template/user/deno_file.lua: -------------------------------------------------------------------------------- 1 | local function is_deno_project() 2 | local denols = vim.iter(vim.lsp.get_clients { bufnr = 0 }):find(function(c) 3 | return c.name == "denols" 4 | end) 5 | return not not denols 6 | end 7 | 8 | ---@type overseer.TemplateFileProvider 9 | return { 10 | generator = function() 11 | if not is_deno_project() then 12 | return {} 13 | end 14 | 15 | local file = vim.fn.expand "%:p" 16 | 17 | return { 18 | { 19 | cmd = { "deno" }, 20 | args = { "run", "-A", file }, 21 | cwd = vim.fn.expand "%:p:h", 22 | }, 23 | { 24 | cmd = { "deno" }, 25 | args = { "test", "-A", file }, 26 | cwd = vim.fn.expand "%:p:h", 27 | }, 28 | } 29 | end, 30 | } 31 | -------------------------------------------------------------------------------- /after/ftplugin/json.lua: -------------------------------------------------------------------------------- 1 | local filename = vim.fn.fnamemodify(vim.fn.bufname(), ":t") 2 | 3 | if filename == "package.json" then 4 | map("n", "ns", ":lua require('package-info').show()", { buffer = true }) 5 | map("n", "nc", ":lua require('package-info').hide()", { buffer = true }) 6 | map("n", "nu", ":lua require('package-info').update()", { buffer = true }) 7 | map("n", "nd", ":lua require('package-info').delete()", { buffer = true }) 8 | map("n", "ni", ":lua require('package-info').install()", { buffer = true }) 9 | map("n", "nr", ":lua require('package-info').reinstall()", { buffer = true }) 10 | map("n", "np", ":lua require('package-info').change_version()", { buffer = true }) 11 | end 12 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/oil.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "stevearc/oil.nvim", 3 | opts = { 4 | use_default_keymaps = false, 5 | keymaps = { 6 | ["?"] = "actions.show_help", 7 | [""] = "actions.select", 8 | [""] = "actions.select_vsplit", 9 | [""] = "actions.select_tab", 10 | [""] = "actions.preview", 11 | [""] = "actions.close", 12 | [""] = "actions.parent", 13 | ["_"] = "actions.open_cwd", 14 | ["`"] = "actions.cd", 15 | ["~"] = "actions.tcd", 16 | ["gs"] = "actions.change_sort", 17 | ["gx"] = "actions.open_external", 18 | ["g."] = "actions.toggle_hidden", 19 | ["g\\"] = "actions.toggle_trash", 20 | }, 21 | }, 22 | cmd = "Oil", 23 | dependencies = { "echasnovski/mini.icons" }, 24 | } 25 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/winbar/explorer.lua: -------------------------------------------------------------------------------- 1 | local Bar = require "nougat.bar" 2 | local Item = require "nougat.item" 3 | local sep = require "nougat.separator" 4 | 5 | local c = require "user.plugins.appearance.nougat.common" 6 | local color = c.color 7 | 8 | local wbr_active = Bar("winbar", {}) 9 | wbr_active:add_item(Item { 10 | content = "  ", 11 | hl = { fg = color.blue, bg = color.bg2 }, 12 | sep_right = sep.right_lower_triangle_solid(true), 13 | }) 14 | 15 | local wbr_inactive = Bar("winbar", {}) 16 | wbr_inactive:add_item(Item { 17 | content = "  ", 18 | hl = { fg = color.blue }, 19 | }) 20 | 21 | ---@param ctx nougat_core_expression_context 22 | return function(ctx) 23 | if ctx.is_focused then 24 | return wbr_active 25 | else 26 | return wbr_inactive 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/texlab.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | return create_setup { 4 | settings = { 5 | texlab = { 6 | build = { 7 | args = { "-pv", "-lualatex", "-output-directory=out" }, 8 | executable = "latexmk", 9 | forwardSearchAfter = true, 10 | onSave = true, 11 | }, 12 | chktex = { 13 | onEdit = true, 14 | onOpenAndSave = true, 15 | }, 16 | outputDirectory = "out", 17 | latexFormatter = "latexindent", 18 | forwardSearch = { 19 | executable = "sumatrapdf", 20 | args = { 21 | "-reuse-instance", 22 | "%p", 23 | "-forward-search", 24 | "%f", 25 | "%l", 26 | }, 27 | }, 28 | }, 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /lua/user/shared/utils/typst.lua: -------------------------------------------------------------------------------- 1 | -- Utils for typst 2 | local M = {} 3 | 4 | --- Main file of the given typst file. 5 | M.get_typst_main_file = function(path) 6 | for _, pattern in ipairs { "root.typ", "report.typ", "main.typ" } do 7 | local dir = vim.fs.root(path, pattern) 8 | if dir ~= nil then 9 | return vim.fs.joinpath(dir, pattern) 10 | end 11 | end 12 | return nil 13 | end 14 | 15 | --- Root dir of typst. This is basically parent directory of main_file, but it falls back to .git if not found. 16 | M.get_typst_root_dir = function(path) 17 | local root_file = M.get_typst_main_file(path) 18 | local root_dir 19 | if root_file == nil then 20 | root_dir = vim.fs.root(path, { ".git" }) 21 | else 22 | root_dir = vim.fs.dirname(root_file) 23 | end 24 | return root_dir 25 | end 26 | 27 | return M 28 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/winbar/inactive.lua: -------------------------------------------------------------------------------- 1 | local Bar = require "nougat.bar" 2 | local sep = require "nougat.separator" 3 | 4 | local c = require "user.plugins.appearance.nougat.common" 5 | local nut = c.nut 6 | local color = c.color 7 | 8 | local wbr = Bar("winbar", { 9 | hl = { bg = color.palette.sumiInk4 }, 10 | }) 11 | 12 | wbr:add_item(nut.buf.icon { 13 | hl = { bg = color.bg }, 14 | prefix = " ", 15 | }) 16 | wbr:add_item(nut.buf.filename { 17 | hl = { bg = color.bg }, 18 | prefix = " ", 19 | suffix = " ", 20 | }) 21 | wbr:add_item(nut.buf.filestatus { 22 | hl = { bg = color.bg }, 23 | suffix = " ", 24 | sep_right = sep.right_lower_triangle_solid(true), 25 | config = { 26 | modified = "󰏫", 27 | nomodifiable = "󰏯", 28 | readonly = "", 29 | sep = " ", 30 | }, 31 | }) 32 | 33 | return wbr 34 | -------------------------------------------------------------------------------- /lua/user/lsp/init.lua: -------------------------------------------------------------------------------- 1 | return { 2 | setup = function() 3 | local default_setup = require("user.lsp.config-builder").default_setup 4 | 5 | local function setup_server(server_name) 6 | if vim.tbl_contains(Args.lsp.disabled_servers, server_name) then 7 | return 8 | end 9 | 10 | local ok, config_fn = pcall(require, "user.lsp.server-configs." .. server_name) 11 | if not ok then 12 | config_fn = default_setup 13 | end 14 | config_fn(server_name) 15 | end 16 | 17 | for _, server_name in ipairs(require("mason-lspconfig").get_installed_servers()) do 18 | setup_server(server_name) 19 | end 20 | 21 | for _, server_name in ipairs(Args.lsp.local_servers) do 22 | setup_server(server_name) 23 | end 24 | 25 | require("user.lsp.settings-json").config() 26 | require "user.lsp.attach" 27 | end, 28 | } 29 | -------------------------------------------------------------------------------- /lua/user/plugins/edit/init.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "kylechui/nvim-surround", 4 | event = { "BufRead", "InsertEnter" }, 5 | config = function() 6 | require("nvim-surround").setup {} 7 | end, 8 | }, 9 | { 10 | "folke/todo-comments.nvim", 11 | dependencies = { { "nvim-lua/plenary.nvim" } }, 12 | event = { "BufRead" }, 13 | config = function() 14 | require("todo-comments").setup {} 15 | end, 16 | }, 17 | { 18 | "numToStr/Comment.nvim", 19 | dependencies = { { "JoosepAlviste/nvim-ts-context-commentstring" } }, 20 | event = { "BufRead" }, 21 | config = function() 22 | require("Comment").setup { 23 | pre_hook = require("ts_context_commentstring.integrations.comment_nvim").create_pre_hook(), 24 | } 25 | end, 26 | }, 27 | { 28 | "danymat/neogen", 29 | config = true, 30 | cmd = "Neogen", 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/buf/navic.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | 3 | local function prepare(item, ctx) end 4 | 5 | local function content(item, ctx) 6 | if package.loaded["nvim-navic"] then 7 | local navic = require "nvim-navic" 8 | if navic.is_available() then 9 | local location = navic.get_location() 10 | return location 11 | end 12 | end 13 | return "" 14 | end 15 | 16 | local mod = {} 17 | 18 | function mod.create(opts) 19 | local item = Item { 20 | priority = opts.priority, 21 | prepare = prepare, 22 | hidden = opts.hidden, 23 | hl = opts.hl, 24 | sep_left = opts.sep_left, 25 | prefix = opts.prefix, 26 | content = content, 27 | suffix = opts.suffix, 28 | sep_right = opts.sep_right, 29 | on_click = opts.on_click, 30 | context = opts.context, 31 | } 32 | 33 | return item 34 | end 35 | 36 | return mod 37 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/git/branch.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | 3 | local content = function(_, ctx) 4 | return ctx.branch 5 | end 6 | 7 | local mod = {} 8 | 9 | function mod.create(opts) 10 | local item = Item { 11 | priority = opts.priority, 12 | hidden = opts.hidden, 13 | hl = opts.hl, 14 | sep_left = opts.sep_left, 15 | prefix = opts.prefix, 16 | content = content, 17 | prepare = function(_, ctx) 18 | if opts.global then 19 | ctx.branch = vim.g.gitsigns_head or "" 20 | else 21 | ctx.branch = vim.b.gitsigns_head or "" 22 | end 23 | end, 24 | suffix = opts.suffix, 25 | sep_right = opts.sep_right, 26 | on_click = opts.on_click, 27 | context = opts.context, 28 | cache = { 29 | scope = "buf", 30 | clear = "BufModifiedSet", 31 | }, 32 | } 33 | 34 | return item 35 | end 36 | 37 | return mod 38 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/overseer.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "stevearc/overseer.nvim", 3 | cmd = { "OverseerRun", "OverseerToggle" }, 4 | init = function() 5 | map("n", "", "OverseerRun") 6 | map("n", "o", "OverseerToggle") 7 | end, 8 | config = function() 9 | require("overseer").setup { 10 | component_aliases = { 11 | default = { 12 | "user.remove_winbar", 13 | "open_output", 14 | "on_exit_set_status", 15 | "on_complete_notify", 16 | { "on_complete_dispose", require_view = { "SUCCESS", "FAILURE" } }, 17 | }, 18 | default_vscode = { 19 | "default", 20 | "on_result_diagnostics", 21 | }, 22 | default_builtin = { 23 | "on_exit_set_status", 24 | "on_complete_dispose", 25 | { "unique", soft = true }, 26 | }, 27 | }, 28 | } 29 | end, 30 | } 31 | -------------------------------------------------------------------------------- /lua/user/profile.lua: -------------------------------------------------------------------------------- 1 | local should_profile = os.getenv "NVIM_PROFILE" 2 | if should_profile ~= nil then 3 | vim.opt.runtimepath:append(vim.fn.stdpath "config" .. "/profile.nvim") 4 | 5 | require("profile").instrument_autocmds() 6 | if should_profile == "start" then 7 | require("profile").start "*" 8 | else 9 | require("profile").instrument "*" 10 | end 11 | 12 | local function toggle_profile() 13 | local prof = require "profile" 14 | if prof.is_recording() then 15 | prof.stop() 16 | vim.ui.input({ prompt = "Save profile to:", completion = "file", default = "profile.json" }, function(filename) 17 | if filename then 18 | prof.export(filename) 19 | vim.notify(string.format("Wrote %s", filename)) 20 | end 21 | end) 22 | else 23 | prof.start "*" 24 | end 25 | end 26 | vim.api.nvim_set_keymap("n", "", "", { callback = toggle_profile }) 27 | end 28 | -------------------------------------------------------------------------------- /lua/overseer/template/user/typst_watch_root.lua: -------------------------------------------------------------------------------- 1 | local utils = require "user.shared.utils.typst" 2 | 3 | return { 4 | name = "typst watch root", 5 | builder = function() 6 | local fname = vim.api.nvim_buf_get_name(0) 7 | local root_dir = utils.get_typst_root_dir(fname) 8 | local main_file = utils.get_typst_main_file(fname) 9 | 10 | if main_file == nil then 11 | return false, "Failed to find main typ file." 12 | end 13 | 14 | local pdf_file = vim.fn.fnamemodify(main_file, ":r") .. ".pdf" 15 | 16 | local args = { "watch", main_file, pdf_file } 17 | 18 | if root_dir == nil then 19 | root_dir = vim.fs.dirname(main_file) 20 | end 21 | 22 | table.insert(args, "--root") 23 | table.insert(args, root_dir) 24 | 25 | return { 26 | cmd = { "typst" }, 27 | args = args, 28 | cwd = vim.fn.expand "%:p:h", 29 | } 30 | end, 31 | condition = { 32 | filetype = { "typst" }, 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /lua/overseer/component/user/remove_winbar.lua: -------------------------------------------------------------------------------- 1 | ---@type overseer.ComponentFileDefinition 2 | return { 3 | desc = "Include a description of your component", 4 | constructor = function() 5 | ---@type overseer.ComponentSkeleton 6 | return { 7 | on_start = function(self, task) 8 | local bufnr = task:get_bufnr() 9 | if not bufnr then 10 | print "remove_winbar component: no buffer found for task" 11 | end 12 | self.au_id = vim.api.nvim_create_autocmd("BufWinEnter", { 13 | callback = function(args) 14 | if args.buf == bufnr then 15 | print(args.win) 16 | vim.api.nvim_set_option_value("winbar", "", { scope = "local", win = args.win }) 17 | end 18 | end, 19 | }) 20 | end, 21 | on_dispose = function(self) 22 | if self.au_id then 23 | vim.api.nvim_del_autocmd(self.au_id) 24 | end 25 | end, 26 | } 27 | end, 28 | } 29 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/buf/filetype.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | 3 | local buffer_cache = require "nougat.cache.buffer" 4 | local buffer_cache_store = buffer_cache.store 5 | 6 | buffer_cache.enable "filetype" 7 | 8 | local function prepare(item, ctx) end 9 | 10 | local function content(item, ctx) 11 | local cache = buffer_cache_store[ctx.bufnr] 12 | local ft = cache.filetype 13 | if ft == "" or ft == nil then 14 | ft = "-" 15 | end 16 | return ft 17 | end 18 | 19 | local mod = {} 20 | 21 | function mod.create(opts) 22 | local item = Item { 23 | priority = opts.priority, 24 | prepare = prepare, 25 | hidden = opts.hidden, 26 | hl = opts.hl, 27 | sep_left = opts.sep_left, 28 | prefix = opts.prefix, 29 | content = content, 30 | suffix = opts.suffix, 31 | sep_right = opts.sep_right, 32 | on_click = opts.on_click, 33 | context = opts.context, 34 | } 35 | 36 | return item 37 | end 38 | 39 | return mod 40 | -------------------------------------------------------------------------------- /after/ftplugin/toml.lua: -------------------------------------------------------------------------------- 1 | local filename = vim.fn.fnamemodify(vim.fn.bufname(), ":t") 2 | 3 | if filename == "Cargo.toml" then 4 | map("n", "ct", ":lua require('crates').toggle()", { buffer = true }) 5 | map("n", "cr", ":lua require('crates').reload()", { buffer = true }) 6 | 7 | map("n", "cv", ":lua require('crates').show_versions_popup()", { buffer = true }) 8 | map("n", "cf", ":lua require('crates').show_features_popup()", { buffer = true }) 9 | 10 | map("n", "cu", ":lua require('crates').update_crate()", { buffer = true }) 11 | map("n", "cu", ":lua require('crates').update_crates()", { buffer = true }) 12 | map("n", "ca", ":lua require('crates').update_all_crates()", { buffer = true }) 13 | map("n", "cU", ":lua require('crates').upgrade_crate()", { buffer = true }) 14 | map("n", "cU", ":lua require('crates').upgrade_crates()", { buffer = true }) 15 | map("n", "cA", ":lua require('crates').upgrade_all_crates()", { buffer = true }) 16 | end 17 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/winbar/active.lua: -------------------------------------------------------------------------------- 1 | local Bar = require "nougat.bar" 2 | local sep = require "nougat.separator" 3 | 4 | local c = require "user.plugins.appearance.nougat.common" 5 | local nut = c.nut 6 | local color = c.color 7 | 8 | local wbr = Bar("winbar", { 9 | hl = { bg = color.palette.winterRed, fg = color.palette.fujiWhite }, 10 | }) 11 | 12 | wbr:add_item(nut.buf.icon { 13 | hl = { bg = color.palette.waveRed }, 14 | prefix = " ", 15 | }) 16 | wbr:add_item(nut.buf.filename { 17 | hl = { bg = color.palette.waveRed, fg = "white" }, 18 | prefix = " ", 19 | suffix = " ", 20 | }) 21 | wbr:add_item(nut.buf.filestatus { 22 | hl = { bg = color.palette.waveRed, fg = "white" }, 23 | suffix = " ", 24 | sep_right = sep.right_lower_triangle_solid(true), 25 | config = { 26 | modified = "●", 27 | nomodifiable = "󰏯", 28 | readonly = "", 29 | sep = " ", 30 | }, 31 | }) 32 | wbr:add_item(nut.buf.navic { 33 | prefix = " ", 34 | suffix = " ", 35 | priority = -1, 36 | }) 37 | 38 | return wbr 39 | -------------------------------------------------------------------------------- /lua/user/plugins/common/hydra/venn.lua: -------------------------------------------------------------------------------- 1 | local hint = [[ 2 | Arrow^^^^^^ Select region with 3 | ^ ^ _K_ ^ ^ _f_: surround it with box 4 | _H_ ^ ^ _L_ 5 | ^ ^ _J_ ^ ^ __ 6 | ]] 7 | 8 | local M = {} 9 | 10 | M.key = "v" 11 | M.setup = function() 12 | local Hydra = require "hydra" 13 | Hydra { 14 | name = "Draw Diagram", 15 | hint = hint, 16 | config = { 17 | color = "pink", 18 | invoke_on_body = true, 19 | on_enter = function() 20 | vim.o.virtualedit = "all" 21 | end, 22 | hint = { 23 | float_opts = { 24 | border = "single", 25 | }, 26 | }, 27 | }, 28 | mode = "n", 29 | body = M.key, 30 | heads = { 31 | { "H", "h:VBox" }, 32 | { "J", "j:VBox" }, 33 | { "K", "k:VBox" }, 34 | { "L", "l:VBox" }, 35 | { "f", ":VBox", { mode = "v" } }, 36 | { "", nil, { exit = true } }, 37 | }, 38 | } 39 | end 40 | 41 | return M 42 | -------------------------------------------------------------------------------- /lua/user/plugins/edit/molten.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "benlubas/molten-nvim", 4 | version = "^1.0.0", -- use version <2.0.0 to avoid breaking changes 5 | build = ":UpdateRemotePlugins", 6 | ft = { "markdown" }, 7 | dependencies = { 8 | { 9 | "GCBallesteros/jupytext.nvim", 10 | config = true, 11 | opts = { 12 | style = "markdown", 13 | output_extension = "md", 14 | force_ft = "markdown", 15 | }, 16 | }, 17 | }, 18 | init = function() 19 | vim.g.python3_host_prog = vim.fn.expand "~/.virtualenvs/neovim/bin/python3" 20 | vim.g.molten_image_provider = "image.nvim" 21 | vim.g.molten_auto_open_output = false 22 | end, 23 | }, 24 | { 25 | "quarto-dev/quarto-nvim", 26 | dependencies = { 27 | "jmbuhr/otter.nvim", 28 | "nvim-treesitter/nvim-treesitter", 29 | }, 30 | opts = { 31 | lspFeatures = { 32 | chunks = "all", 33 | }, 34 | codeRunner = { 35 | default_method = "molten", 36 | }, 37 | }, 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/snacks.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/snacks.nvim", 3 | event = "BufReadPre", 4 | keys = { { 5 | "", 6 | mode = { "n" }, 7 | function() 8 | Snacks.lazygit.open(opts) 9 | end, 10 | } }, 11 | opts = function() 12 | -- Toggle the profiler 13 | Snacks.toggle.profiler():map "spp" 14 | -- Toggle the profiler highlights 15 | Snacks.toggle.profiler_highlights():map "sph" 16 | 17 | ---@type snacks.Config 18 | return { 19 | indent = { 20 | enable = true, 21 | animate = { 22 | duration = { 23 | total = 200, 24 | }, 25 | }, 26 | }, 27 | bigfile = { 28 | setup = function(ctx) 29 | vim.cmd [[NoMatchParen]] 30 | -- require("illuminate").pause_buf() 31 | Snacks.util.wo(0, { foldmethod = "manual", statuscolumn = "", conceallevel = 0 }) 32 | vim.schedule(function() 33 | vim.bo[ctx.buf].syntax = ctx.ft 34 | end) 35 | end, 36 | }, 37 | } 38 | end, 39 | } 40 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/tabline.lua: -------------------------------------------------------------------------------- 1 | local Bar = require "nougat.bar" 2 | local sep = require "nougat.separator" 3 | 4 | local c = require "user.plugins.appearance.nougat.common" 5 | local nut = c.nut 6 | local color = c.color 7 | 8 | local tal = Bar "tabline" 9 | tal:add_item(nut.tab.tablist.tabs { 10 | active_tab = { 11 | hl = { bg = color.bg, fg = color.blue }, 12 | prefix = " ", 13 | suffix = " ", 14 | content = { 15 | nut.tab.tablist.icon { suffix = " " }, 16 | nut.tab.tablist.label {}, 17 | nut.tab.tablist.modified { prefix = " ", config = { text = "●" } }, 18 | nut.tab.tablist.close { prefix = " ", config = { text = "󰅖" } }, 19 | }, 20 | }, 21 | inactive_tab = { 22 | hl = { bg = color.bg2, fg = color.fg2 }, 23 | prefix = " ", 24 | suffix = " ", 25 | content = { 26 | nut.tab.tablist.icon { suffix = " " }, 27 | nut.tab.tablist.label {}, 28 | nut.tab.tablist.modified { prefix = " ", config = { text = "●" } }, 29 | nut.tab.tablist.close { prefix = " ", config = { text = "󰅖" } }, 30 | }, 31 | }, 32 | }) 33 | 34 | return tal 35 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/hlslens.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "kevinhwang91/nvim-hlslens", 3 | event = { "BufRead" }, 4 | enabled = not Args.feature.vscode, 5 | init = function() 6 | local kopts = { silent = true } 7 | vim.api.nvim_set_keymap( 8 | "n", 9 | "n", 10 | [[execute('normal! ' . v:count1 . 'n')lua require('hlslens').start()]], 11 | kopts 12 | ) 13 | vim.api.nvim_set_keymap( 14 | "n", 15 | "N", 16 | [[execute('normal! ' . v:count1 . 'N')lua require('hlslens').start()]], 17 | kopts 18 | ) 19 | vim.api.nvim_set_keymap("n", "*", [[*lua require('hlslens').start()]], kopts) 20 | vim.api.nvim_set_keymap("n", "#", [[#lua require('hlslens').start()]], kopts) 21 | vim.api.nvim_set_keymap("n", "g*", [[g*lua require('hlslens').start()]], kopts) 22 | vim.api.nvim_set_keymap("n", "g#", [[g#lua require('hlslens').start()]], kopts) 23 | end, 24 | config = function() 25 | require("hlslens").setup { 26 | calm_down = true, 27 | nearest_only = true, 28 | nearest_float_when = "always", 29 | } 30 | end, 31 | } 32 | -------------------------------------------------------------------------------- /lua/user/plugins/ai/codecompanion.lua: -------------------------------------------------------------------------------- 1 | if Args.feature.vscode then 2 | return {} 3 | end 4 | 5 | return { 6 | "olimorris/codecompanion.nvim", 7 | keys = { 8 | { mode = "n", "ch", "CodeCompanionChat" }, 9 | { mode = "n", "cc", "CodeCompanion" }, 10 | }, 11 | cmd = { "CodeCompanionChat", "CodeCompanion" }, 12 | dependencies = { 13 | "nvim-lua/plenary.nvim", 14 | "nvim-treesitter/nvim-treesitter", 15 | }, 16 | config = function() 17 | require("user.plugins.ai.codecompanion.fidget"):init() 18 | require("codecompanion").setup { 19 | opts = { 20 | language = "Japanese", 21 | }, 22 | display = { 23 | chat = { 24 | window = { 25 | width = 0.25, 26 | position = "right", 27 | }, 28 | }, 29 | }, 30 | strategies = { 31 | chat = { 32 | roles = { 33 | llm = function(adapter) 34 | return " CodeCompanion (" .. adapter.formatted_name .. ", " .. adapter.model.name .. ")" 35 | end, 36 | user = " Me", 37 | }, 38 | }, 39 | }, 40 | } 41 | end, 42 | } 43 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/buf/filename.lua: -------------------------------------------------------------------------------- 1 | -- Almost same as built-in version, but fixed percent-encoding problem 2 | 3 | local Item = require "nougat.item" 4 | 5 | local function get_content(item, ctx) 6 | local config = item:config(ctx) 7 | local v = vim.fn.expand("%" .. config.modifier) 8 | if #v == 0 then 9 | v = config.unnamed 10 | elseif config.format then 11 | v = config.format(v, ctx) 12 | end 13 | v = v:gsub("%%", "%%%%") 14 | return v 15 | end 16 | 17 | local mod = {} 18 | 19 | function mod.create(opts) 20 | local item = Item { 21 | priority = opts.priority, 22 | hidden = opts.hidden, 23 | hl = opts.hl, 24 | sep_left = opts.sep_left, 25 | prefix = opts.prefix, 26 | content = get_content, 27 | suffix = opts.suffix, 28 | sep_right = opts.sep_right, 29 | config = vim.tbl_extend("force", { 30 | modifier = ":.", 31 | format = nil, 32 | unnamed = "[No Name]", 33 | }, opts.config or {}), 34 | on_click = opts.on_click, 35 | context = opts.context, 36 | cache = { 37 | scope = "buf", 38 | clear = "BufFilePost", 39 | }, 40 | } 41 | 42 | return item 43 | end 44 | 45 | return mod 46 | -------------------------------------------------------------------------------- /lua/user/shared/utils/vim.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | --- A helper function to wrap a module function to require a plugin before running 4 | --- From: https://github.com/AstroNvim/AstroNvim/blob/main/lua/astronvim/utils/init.lua 5 | -- @param plugin the plugin string to call `require("lazy").load` with 6 | -- @param module the system module where the functions live (e.g. `vim.ui`) 7 | -- @param func_names a string or a list like table of strings for functions to wrap in the given module (e.g. `{ "ui", "select }`) 8 | M.load_plugin_with_func = function(plugin, module, func_names) 9 | if type(func_names) == "string" then 10 | func_names = { func_names } 11 | end 12 | for _, func in ipairs(func_names) do 13 | local old_func = module[func] 14 | module[func] = function(...) 15 | module[func] = old_func 16 | require("lazy").load { plugins = { plugin } } 17 | module[func](...) 18 | end 19 | end 20 | end 21 | 22 | M.send_key = function(key) 23 | vim.fn.feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), "") 24 | end 25 | 26 | M.send_key_nomap = function(key) 27 | vim.fn.feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), "n") 28 | end 29 | 30 | return M 31 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/buf/encoding.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | 3 | local mod = {} 4 | 5 | local function prepare(item, ctx) 6 | local cache = item:cache(ctx) 7 | if not cache.encoding then 8 | local enc = (vim.bo.fenc ~= "" and vim.bo.fenc) or vim.o.enc 9 | cache.encoding = enc:upper() 10 | end 11 | end 12 | 13 | local function content(item, ctx) 14 | return item:cache(ctx).encoding 15 | end 16 | 17 | local cache_initial_value = { encoding = nil } 18 | 19 | function mod.create(opts) 20 | local item = Item { 21 | priority = opts.priority, 22 | prepare = prepare, 23 | hidden = opts.hidden, 24 | hl = opts.hl, 25 | sep_left = opts.sep_left, 26 | prefix = opts.prefix, 27 | content = content, 28 | suffix = opts.suffix, 29 | sep_right = opts.sep_right, 30 | on_click = opts.on_click, 31 | context = opts.context, 32 | cache = { 33 | name = "nnut.buf.encoding", 34 | scope = "buf", 35 | get = function(store, ctx) 36 | return store[ctx.bufnr] 37 | end, 38 | initial_value = cache_initial_value, 39 | clear = "BufWritePost", 40 | }, 41 | } 42 | 43 | return item 44 | end 45 | 46 | return mod 47 | -------------------------------------------------------------------------------- /lua/user/lsp/settings-json.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local function unflatten(tbl) 4 | local result = {} 5 | 6 | for flat_key, value in pairs(tbl) do 7 | local current = result 8 | local parts = {} 9 | for part in string.gmatch(flat_key, "[^%.]+") do 10 | table.insert(parts, part) 11 | end 12 | for i = 1, #parts - 1 do 13 | local part = parts[i] 14 | if current[part] == nil then 15 | current[part] = {} 16 | end 17 | current = current[part] 18 | end 19 | current[parts[#parts]] = value 20 | end 21 | 22 | return result 23 | end 24 | 25 | M.config = function() 26 | local root_dir = vim.fs.normalize(vim.fn.expand "%:p:h") 27 | 28 | local json_p = vim.fs.root(root_dir, { ".vscode/settings.json" }) 29 | if json_p == nil then 30 | return 31 | end 32 | json_p = vim.fs.joinpath(json_p, "settings.json") 33 | local lines = vim.fn.readfile(json_p) 34 | local text = table.concat(lines, "\n") 35 | 36 | local json = require "user.shared.json" 37 | require "user.shared.json.jsonc" 38 | local content = json.decode_jsonc(text) 39 | content = unflatten(content) 40 | 41 | vim.lsp.config("*", { 42 | settings = content, 43 | }) 44 | end 45 | 46 | return M 47 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/buf/fileformat.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | 3 | local mod = {} 4 | 5 | local function prepare(item, ctx) 6 | local cache = item:cache(ctx) 7 | if not cache.fileformat then 8 | local os = vim.bo.fileformat 9 | cache.fileformat = os == "unix" and "LF" or os == "mac" and "CR" or "CRLF" 10 | end 11 | end 12 | 13 | local function content(item, ctx) 14 | return item:cache(ctx).fileformat 15 | end 16 | 17 | local cache_initial_value = { fileformat = nil } 18 | 19 | function mod.create(opts) 20 | local item = Item { 21 | priority = opts.priority, 22 | prepare = prepare, 23 | hidden = opts.hidden, 24 | hl = opts.hl, 25 | sep_left = opts.sep_left, 26 | prefix = opts.prefix, 27 | content = content, 28 | suffix = opts.suffix, 29 | sep_right = opts.sep_right, 30 | on_click = opts.on_click, 31 | context = opts.context, 32 | cache = { 33 | name = "nnut.buf.fileformat", 34 | scope = "buf", 35 | get = function(store, ctx) 36 | return store[ctx.bufnr] 37 | end, 38 | initial_value = cache_initial_value, 39 | clear = "BufWritePost", 40 | }, 41 | } 42 | 43 | return item 44 | end 45 | 46 | return mod 47 | -------------------------------------------------------------------------------- /lua/user/lsp/config-builder.lua: -------------------------------------------------------------------------------- 1 | local client_capabilities = require("blink.cmp").get_lsp_capabilities { 2 | resolveSupport = { 3 | properties = { 4 | "documentation", 5 | "detail", 6 | "additionalTextEdits", 7 | "sortText", 8 | "filterText", 9 | "insertText", 10 | "insertTextFormat", 11 | "insertTextMode", 12 | }, 13 | }, 14 | textDocument = { 15 | foldingRange = { 16 | lineFoldingOnly = true, 17 | }, 18 | }, 19 | } 20 | local base_config = { 21 | capabilities = client_capabilities, 22 | before_init = require("user.lsp.settings-json").before_init, 23 | } 24 | 25 | local M = {} 26 | 27 | M.create_config = function(server_config) 28 | return vim.tbl_deep_extend("force", base_config, server_config) 29 | end 30 | 31 | --- @param server_config vim.lsp.Config|fun(server_name: string):vim.lsp.Config 32 | M.create_setup = function(server_config) 33 | return function(server_name) 34 | if type(server_config) == "function" then 35 | server_config = server_config(server_name) 36 | end 37 | vim.lsp.config(server_name, M.create_config(server_config)) 38 | vim.lsp.enable(server_name) 39 | end 40 | end 41 | 42 | M.default_setup = M.create_setup {} 43 | 44 | return M 45 | -------------------------------------------------------------------------------- /lua/user/plugins/lsp/init.lua: -------------------------------------------------------------------------------- 1 | return Args.feature.vscode and {} 2 | or { 3 | { "onsails/lspkind-nvim" }, 4 | { "b0o/schemastore.nvim" }, 5 | { "SmiteshP/nvim-navic", event = { "InsertEnter", "BufRead" } }, 6 | { "aznhe21/actions-preview.nvim" }, 7 | { 8 | "rachartier/tiny-inline-diagnostic.nvim", 9 | event = "LspAttach", 10 | priority = 1000, 11 | config = function() 12 | vim.diagnostic.config { virtual_text = false } 13 | require("tiny-inline-diagnostic").setup { 14 | options = { 15 | show_source = true, 16 | add_messages = { 17 | messages = true, 18 | display_count = true, 19 | }, 20 | multilines = { 21 | enabled = true, 22 | always_show = true, 23 | }, 24 | }, 25 | } 26 | end, 27 | }, 28 | { 29 | { 30 | "antosha417/nvim-lsp-file-operations", 31 | dependencies = { 32 | "nvim-lua/plenary.nvim", 33 | "nvim-tree/nvim-tree.lua", 34 | }, 35 | event = "LspAttach", 36 | config = function() 37 | require("lsp-file-operations").setup() 38 | end, 39 | }, 40 | }, 41 | } 42 | -------------------------------------------------------------------------------- /lua/user/args.lua: -------------------------------------------------------------------------------- 1 | --- In this modules, global `Args` variable is defined. 2 | --- This value can be thought as "Argument of config". By overriding these values in local `early-init.lua`, you can easily customize some components in config. 3 | --- This value should be only changed in `early-init.lua`. 4 | Args = { 5 | --- "feature" provides way to easily disable/enable component of config. 6 | feature = { 7 | --- Enables AI features 8 | ai = { 9 | enabled = true, 10 | --- Enables copilot related plugins 11 | copilot = true, 12 | }, 13 | 14 | --- Force enable osc52 clipboard. Useful in ssh environment. 15 | osc52 = vim.env.SSH_CLIENT ~= nil, 16 | 17 | --- Enables denops powered plugins. Useful in environment that deno is not available. 18 | denops = true, 19 | 20 | vscode = not not vim.g.vscode, 21 | 22 | --- Enables rest.nvim plugin. This is gated because it has dependencies that fails sometime. 23 | rest = false, 24 | 25 | --- Use resolved windows addreess instead of localhost for some config 26 | wsl_nat = false, 27 | }, 28 | lsp = { 29 | --- Defines `local server` that is configured even if server is not installed by mason. 30 | local_servers = {}, 31 | disabled_servers = {}, 32 | }, 33 | } 34 | -------------------------------------------------------------------------------- /lua/user/plugins/ai/copilot.lua: -------------------------------------------------------------------------------- 1 | if not Args.feature.ai.copilot or Args.feature.vscode then 2 | return {} 3 | end 4 | 5 | return { 6 | { 7 | "zbirenbaum/copilot.lua", 8 | dependencies = { 9 | { "neovim/nvim-lspconfig" }, 10 | }, 11 | event = { "BufRead", "BufNewFile" }, 12 | cmd = { "Copilot" }, 13 | keys = { 14 | { mode = "n", "cp", "Copilot panel" }, 15 | }, 16 | config = function() 17 | require("copilot").setup { 18 | suggestion = { 19 | enabled = false, 20 | }, 21 | filetypes = { 22 | yaml = true, 23 | markdown = true, 24 | }, 25 | } 26 | end, 27 | }, 28 | { 29 | "folke/sidekick.nvim", 30 | opts = {}, 31 | event = { "BufRead", "BufNewFile" }, 32 | dependencies = { 33 | { "zbirenbaum/copilot.lua" }, 34 | }, 35 | keys = { 36 | { 37 | "", 38 | function() 39 | -- if there is a next edit, jump to it, otherwise apply it if any 40 | if not require("sidekick").nes_jump_or_apply() then 41 | return "" -- fallback to normal tab 42 | end 43 | end, 44 | expr = true, 45 | desc = "Goto/Apply Next Edit Suggestion", 46 | }, 47 | }, 48 | }, 49 | } 50 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/dressing.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "stevearc/dressing.nvim", 3 | init = function() 4 | require("user.shared.utils.vim").load_plugin_with_func("dressing.nvim", vim.ui, { "input", "select" }) 5 | end, 6 | config = function() 7 | require("dressing").setup { 8 | input = { 9 | enabled = true, 10 | default_prompt = "Input:", 11 | prompt_align = "left", 12 | insert_only = true, 13 | start_in_insert = true, 14 | 15 | border = "rounded", 16 | relative = "cursor", 17 | 18 | prefer_width = 40, 19 | width = nil, 20 | -- min_width and max_width can be a list of mixed types. 21 | -- min_width = {20, 0.2} means "the greater of 20 columns or 20% of total" 22 | max_width = { 140, 0.9 }, 23 | min_width = { 60, 0.5 }, 24 | 25 | mappings = { 26 | i = { 27 | [""] = "Close", 28 | [""] = "Confirm", 29 | [""] = "HistoryPrev", 30 | [""] = "HistoryNext", 31 | }, 32 | }, 33 | override = function(conf) 34 | conf.anchor = "SW" 35 | end, 36 | }, 37 | select = { 38 | enabled = true, 39 | backend = { "telescope", "builtin" }, 40 | }, 41 | } 42 | end, 43 | } 44 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/buf/copilot.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | 3 | local mod = {} 4 | 5 | function mod.create(opts) 6 | local item = Item { 7 | init = opts.init, 8 | priority = opts.priority, 9 | hidden = opts.hidden, 10 | hl = opts.hl, 11 | sep_left = opts.sep_left, 12 | prefix = opts.prefix, 13 | content = function() 14 | local content = nil 15 | if package.loaded["copilot"] then 16 | local status = require "copilot.status" 17 | local copilot_status = status.data.status 18 | 19 | if copilot_status == "Normal" then 20 | content = "" 21 | elseif copilot_status == "InProgress" then 22 | content = "  " 23 | elseif copilot_status == "Warning" then 24 | content = "  " 25 | end 26 | end 27 | if content ~= nil then 28 | content = " " .. content 29 | end 30 | return content 31 | end, 32 | suffix = opts.suffix, 33 | sep_right = opts.sep_right, 34 | on_click = opts.on_click, 35 | context = opts.context, 36 | ctx = opts.ctx, 37 | -- cache = { 38 | -- scope = "buf", 39 | -- clear = { 40 | -- "LspAttach", 41 | -- "LspDetach", 42 | -- }, 43 | -- }, 44 | } 45 | 46 | return item 47 | end 48 | 49 | return mod 50 | -------------------------------------------------------------------------------- /lua/user/plugins/common/possession.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "jedrzejboczar/possession.nvim", 3 | dependencies = { "nvim-lua/plenary.nvim" }, 4 | enabled = not Args.feature.vscode, 5 | config = function() 6 | require("possession").setup { 7 | silent = true, 8 | load_silent = true, 9 | autosave = { 10 | current = false, 11 | tmp = false, 12 | tmp_name = "tmp", 13 | on_load = true, 14 | on_quit = true, 15 | }, 16 | commands = { 17 | save = "PossessionSave", 18 | load = "PossessionLoad", 19 | rename = "PossessionRename", 20 | close = "PossessionClose", 21 | delete = "PossessionDelete", 22 | show = "PossessionShow", 23 | list = "PossessionList", 24 | migrate = "PossessionMigrate", 25 | }, 26 | plugins = { 27 | nvim_tree = true, 28 | tabby = true, 29 | dap = true, 30 | close_windows = { 31 | match = { 32 | filetype = { "no-neck-pain", "OverseerList" }, 33 | buftype = { "terminal" }, 34 | }, 35 | preserve_layout = false, 36 | }, 37 | delete_hidden_buffers = { 38 | force = function(buf) 39 | return vim.api.nvim_get_option_value("buftype", { buf = buf }) == "terminal" 40 | end, 41 | }, 42 | }, 43 | } 44 | end, 45 | } 46 | -------------------------------------------------------------------------------- /lua/user/plugins/debug/dap.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "mfussenegger/nvim-dap", 3 | dependencies = { 4 | { "rcarriga/nvim-dap-ui", dependencies = { { "nvim-neotest/nvim-nio" } } }, 5 | { "theHamsta/nvim-dap-virtual-text" }, 6 | { "jay-babu/mason-nvim-dap.nvim", dependencies = { "williamboman/mason.nvim" } }, 7 | }, 8 | init = function() 9 | map("n", "d", ":lua require'dapui'.toggle()", { desc = "[dapui] Toggle" }) 10 | map("n", "df", ":lua require'dapui'.eval()", { desc = "[dapui] Eval" }) 11 | map("n", "", ":lua require'dap'.continue()", { desc = "[dap] Continue" }) 12 | map("n", "", ":lua require'dap'.step_over()", { desc = "[dap] Step over" }) 13 | map("n", "", ":lua require'dap'.step_into()", { desc = "[dap] Step into" }) 14 | map("n", "", ":lua require'dap'.step_out()", { desc = "[dap] Step out" }) 15 | map("n", "b", ":lua require'dap'.toggle_breakpoint()", { desc = "[dap] Toggle breakpoint" }) 16 | map("n", "bc", ":lua require'dap'.set_breakpoint(vim.fn.input('Breakpoint condition: '))", {}) 17 | end, 18 | config = function() 19 | require("nvim-dap-virtual-text").setup {} 20 | 21 | vim.schedule(function() 22 | require("dapui").setup() 23 | require("mason-nvim-dap").setup { 24 | handlers = {}, 25 | } 26 | end) 27 | end, 28 | } 29 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/skkleton.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "vim-skk/skkeleton", 4 | keys = { { "", mode = { "i", "c" }, "(skkeleton-enable)" } }, 5 | enabled = Args.feature.denops, 6 | dependencies = { "vim-denops/denops.vim", "delphinus/skkeleton_indicator.nvim" }, 7 | init = function() 8 | vim.api.nvim_create_autocmd("User", { 9 | pattern = "skkeleton-initialize-pre", 10 | callback = function() 11 | local server = "127.0.0.1" 12 | 13 | if Args.feature.wsl_nat then 14 | if vim.fn.has "wsl" == 1 then 15 | server = 16 | vim.fn.system [[ip route | grep 'default via' | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}']] 17 | server = server:gsub("%s+", "") 18 | end 19 | end 20 | 21 | local encoding = "utf-8" 22 | if vim.fn.has "mac" == 1 then 23 | encoding = "euc-jp" 24 | end 25 | 26 | vim.fn["skkeleton#config"] { 27 | eggLikeNewline = true, 28 | registerConvertResult = true, 29 | sources = { "skk_server" }, 30 | skkServerReqEnc = encoding, 31 | skkServerResEnc = encoding, 32 | skkServerHost = server, 33 | } 34 | end, 35 | }) 36 | end, 37 | config = function() 38 | require("skkeleton_indicator").setup {} 39 | end, 40 | }, 41 | } 42 | -------------------------------------------------------------------------------- /lua/user/shared/lsp-selector/web.lua: -------------------------------------------------------------------------------- 1 | -- Select lsp for web development 2 | -- 3 | -- 1. If there is a package.json or tsconfig.json in the current directory, use vtsls 4 | -- 2. If there is a deno.json or deno.jsonc in the current directory, use denols 5 | -- 3. If both are present, use the one with nearest root 6 | 7 | local cache = {} 8 | 9 | return { 10 | judge = function(bufnr) 11 | local path = vim.fs.dirname(vim.api.nvim_buf_get_name(bufnr)) 12 | if cache[path] == nil then 13 | local node_root = vim.fs.root(bufnr, { "package.json", "tsconfig.json" }) 14 | local deno_root = vim.fs.root(bufnr, { "deno.json", "deno.jsonc" }) 15 | 16 | if node_root and deno_root then 17 | local _, node_count = string.gsub(node_root, "/", "") 18 | local _, deno_count = string.gsub(deno_root, "/", "") 19 | 20 | if node_count < deno_count then 21 | deno_root = nil 22 | else 23 | node_root = nil 24 | end 25 | end 26 | 27 | if node_root then 28 | cache[path] = { 29 | type = "node", 30 | root = node_root, 31 | } 32 | elseif deno_root then 33 | cache[path] = { 34 | type = "deno", 35 | root = deno_root, 36 | } 37 | else 38 | cache[path] = { 39 | type = "deno", 40 | root = vim.fs.dirname(path), 41 | } 42 | end 43 | end 44 | 45 | return cache[path] 46 | end, 47 | } 48 | -------------------------------------------------------------------------------- /lua/user/config/filetype.lua: -------------------------------------------------------------------------------- 1 | local loaded = false 2 | 3 | vim.api.nvim_create_autocmd("BufReadPre", { 4 | group = vim.api.nvim_create_augroup("custom-filetype", {}), 5 | once = true, 6 | callback = function() 7 | if not loaded then 8 | loaded = true 9 | vim.filetype.add { 10 | extension = { 11 | xaml = "xml", 12 | saty = "satysfi", 13 | satyh = "satysfi", 14 | nu = "nu", 15 | surql = "surrealdb", 16 | v = "systemverilog", 17 | cir = "ngspice", 18 | mdx = "mdx", 19 | }, 20 | filename = { 21 | [".swcrc"] = "json", 22 | [".latexmkrc"] = "perl", 23 | -- Technitium DNS Server app 24 | ["dnsApp.config"] = "json", 25 | [".styluaignore"] = "gitignore", 26 | [".prettierignore"] = "gitignore", 27 | [".eslintignore"] = "gitignore", 28 | }, 29 | pattern = { 30 | ["${HOME}/.local/share/chezmoi/.*"] = { 31 | function(path, buf) 32 | if path:match "/dot_" then 33 | return vim.filetype.match { 34 | filename = path:gsub("/dot_", "/."), 35 | buf = buf, 36 | } 37 | end 38 | end, 39 | { priority = -math.huge }, 40 | }, 41 | }, 42 | } 43 | 44 | vim.treesitter.language.register("markdown", "mdx") 45 | end 46 | end, 47 | }) 48 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/buf/fmo.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | 3 | local function prepare(item, ctx) 4 | local cache = item:cache(ctx) 5 | if not cache.formatters then 6 | if package.loaded["fmo"] ~= nil then 7 | cache.formatters = require("fmo").get_formatters(0) 8 | end 9 | end 10 | end 11 | 12 | local function content(item, ctx) 13 | local formatters = item:cache(ctx).formatters 14 | if formatters ~= nil and #formatters > 0 then 15 | local str = "" 16 | for _, formatter in ipairs(formatters) do 17 | str = str .. formatter.type .. ":" .. formatter.name .. " " 18 | end 19 | return str 20 | end 21 | return nil 22 | end 23 | 24 | local cache_initial_value = { formatters = nil } 25 | 26 | local mod = {} 27 | 28 | function mod.create(opts) 29 | local item = Item { 30 | priority = opts.priority, 31 | prepare = prepare, 32 | hidden = opts.hidden, 33 | hl = opts.hl, 34 | sep_left = opts.sep_left, 35 | prefix = opts.prefix, 36 | content = content, 37 | suffix = opts.suffix, 38 | sep_right = opts.sep_right, 39 | on_click = opts.on_click, 40 | context = opts.context, 41 | cache = { 42 | name = "nnut.buf.fmo", 43 | scope = "buf", 44 | get = function(store, ctx) 45 | return store[ctx.bufnr] 46 | end, 47 | initial_value = cache_initial_value, 48 | clear = "LspAttach", 49 | }, 50 | } 51 | 52 | return item 53 | end 54 | 55 | return mod 56 | -------------------------------------------------------------------------------- /scripts/benchmark.ts: -------------------------------------------------------------------------------- 1 | const times: number[] = []; 2 | 3 | for (let i = 0; i < 10; i++) { 4 | const cmd = new Deno.Command( 5 | "nvim", 6 | { 7 | args: [ 8 | "--startuptime", 9 | `${i}.log`, 10 | "--cmd", 11 | "autocmd VimEnter * qall", 12 | ], 13 | }, 14 | ); 15 | await cmd.output(); 16 | const text = await Deno.readTextFile(`${i}.log`); 17 | await Deno.remove(`${i}.log`); 18 | const lines = text.split("\n"); 19 | const last_line = lines.find((line) => { 20 | return line.includes("BufEnter autocommands"); 21 | }); 22 | if (!last_line) { 23 | throw new Error("Failed to find last line"); 24 | } 25 | const time = last_line.split(" ")[0]; 26 | times.push(Number(time)); 27 | } 28 | 29 | const [min, max, sum] = times.reduce((pre, crr) => { 30 | const min = Math.min(pre[0], crr); 31 | const max = Math.max(pre[1], crr); 32 | const sum = pre[2] + crr; 33 | 34 | return [min, max, sum]; 35 | }, [100000, 0, 0]); 36 | const avg = Math.round((sum / times.length) * 100) / 100; 37 | 38 | const data = [ 39 | { 40 | "name": "Average nvim startup time", 41 | "unit": "ms", 42 | "value": avg, 43 | }, 44 | { 45 | "name": "Min nvim startup time", 46 | "unit": "ms", 47 | "value": min, 48 | }, 49 | { 50 | "name": "Max nvim startup time", 51 | "unit": "ms", 52 | "value": max, 53 | }, 54 | ]; 55 | 56 | await Deno.writeTextFile("data.json", JSON.stringify(data)); 57 | -------------------------------------------------------------------------------- /lua/user/lazy.lua: -------------------------------------------------------------------------------- 1 | local lazypath = vim.fn.stdpath "data" .. "/lazy/lazy.nvim" 2 | if not vim.loop.fs_stat(lazypath) then 3 | vim.fn.system { 4 | "git", 5 | "clone", 6 | "--filter=blob:none", 7 | "--single-branch", 8 | "https://github.com/folke/lazy.nvim.git", 9 | lazypath, 10 | } 11 | end 12 | vim.opt.runtimepath:prepend(lazypath) 13 | 14 | local spec = { 15 | { import = "user.plugins.appearance" }, 16 | { import = "user.plugins.common" }, 17 | { import = "user.plugins.debug" }, 18 | { import = "user.plugins.edit" }, 19 | { import = "user.plugins.external" }, 20 | { import = "user.plugins.git" }, 21 | { import = "user.plugins.language" }, 22 | { import = "user.plugins.lsp" }, 23 | { import = "user.plugins.tools" }, 24 | { import = "user.plugins.treesitter" }, 25 | } 26 | 27 | if Args.feature.ai.enabled then 28 | table.insert(spec, { import = "user.plugins.ai" }) 29 | end 30 | 31 | local available, local_spec = pcall(require, "user.local.plugins") 32 | if available then 33 | table.insert(spec, local_spec) 34 | end 35 | 36 | require("lazy").setup(spec, { 37 | defaults = { 38 | lazy = true, 39 | }, 40 | change_detection = { 41 | enabled = false, 42 | }, 43 | performance = { 44 | rtp = { 45 | disabled_plugins = { 46 | "gzip", 47 | "matchit", 48 | "netrwPlugin", 49 | "tarPlugin", 50 | "tohtml", 51 | "zipPlugin", 52 | "man", 53 | }, 54 | }, 55 | }, 56 | }) 57 | 58 | map("n", "l", "Lazy") 59 | -------------------------------------------------------------------------------- /.github/workflows/benchmark.yml: -------------------------------------------------------------------------------- 1 | name: benchmark 2 | on: 3 | workflow_dispatch: 4 | 5 | jobs: 6 | benchmark: 7 | timeout-minutes: 15 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [ubuntu-latest, windows-latest] 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | 17 | - name: Setup neovim 18 | uses: rhysd/action-setup-vim@v1 19 | with: 20 | neovim: true 21 | version: nightly 22 | 23 | - name: Setup deno 24 | uses: denoland/setup-deno@v1 25 | with: 26 | deno-version: v1.x 27 | 28 | - name: copy config (Linux) 29 | if: runner.os == 'Linux' 30 | run: cp -r ./ ~/.config/nvim/ 31 | 32 | - name: copy config (Windows) 33 | if: runner.os == 'Windows' 34 | run: cp -r ./ ~/AppData/Local/nvim/ 35 | 36 | - name: Install plugins 37 | run: | 38 | nvim --headless "+Lazy! sync" +qa 39 | nvim -c qa 40 | - name: Run benchmark 41 | run: | 42 | deno run --unstable --allow-all ./scripts/benchmark.ts 43 | - name: Upload benchmark 44 | uses: benchmark-action/github-action-benchmark@v1 45 | with: 46 | tool: customSmallerIsBetter 47 | output-file-path: data.json 48 | github-token: ${{ secrets.GITHUB_TOKEN }} 49 | benchmark-data-dir-path: bench/${{ matrix.os }} 50 | auto-push: true 51 | comment-on-alert: false 52 | fail-on-alert: false 53 | alert-threshold: '200%' 54 | alert-comment-cc-users: '@nazo6' 55 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/fidget.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "j-hui/fidget.nvim", 4 | init = function() 5 | require("user.shared.utils.vim").load_plugin_with_func("fidget.nvim", vim, "notify") 6 | end, 7 | config = function() 8 | local function percentage_bar(percentage) 9 | local length = 12 10 | local incomplete = "‥" 11 | local complete = "─" 12 | local sep = "→" 13 | 14 | local complete_length = math.floor((percentage / 100) * length) 15 | 16 | return string.rep(complete, complete_length > 0 and complete_length - 1 or complete_length) 17 | .. (complete_length > 0 and sep or "") 18 | .. string.rep(incomplete, length - complete_length) 19 | end 20 | 21 | require("fidget").setup { 22 | progress = { 23 | display = { 24 | format_message = function(msg) 25 | local message = msg.message 26 | if not message then 27 | message = msg.done and "Completed" or "In progress..." 28 | end 29 | if msg.percentage ~= nil then 30 | local percent_bar = string.format("%s%% %s", msg.percentage, percentage_bar(msg.percentage)) 31 | message = string.format("%s %s", message, percent_bar) 32 | end 33 | return message 34 | end, 35 | }, 36 | }, 37 | notification = { 38 | override_vim_notify = true, 39 | window = { 40 | winblend = 50, 41 | }, 42 | }, 43 | } 44 | end, 45 | }, 46 | } 47 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/tailwindcss.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | 3 | local filetypes = vim.lsp.config.tailwindcss.filetypes 4 | table.insert(filetypes, "rust") 5 | 6 | return create_setup { 7 | filetypes = filetypes, 8 | root_dir = function(bufnr, cb) 9 | local root = vim.fs.root(bufnr, { 10 | "tailwind.config.js", 11 | "tailwind.config.cjs", 12 | "tailwind.config.mjs", 13 | "tailwind.config.ts", 14 | }) 15 | 16 | if root ~= nil then 17 | cb(root) 18 | end 19 | 20 | local package_json_dir = vim.fs.root(bufnr, { "package.json" }) 21 | if package_json_dir ~= nil then 22 | local contents = vim.fn.readfile(vim.fs.joinpath(package_json_dir, "package.json")) 23 | contents = table.concat(contents, "\n") 24 | if contents then 25 | local json = vim.json.decode(contents) 26 | if json and json.devDependencies and json.devDependencies.tailwindcss then 27 | cb(package_json_dir) 28 | end 29 | end 30 | end 31 | end, 32 | init_options = { 33 | userLanguages = { 34 | eelixir = "html-eex", 35 | eruby = "erb", 36 | rust = "html", 37 | }, 38 | }, 39 | settings = { 40 | tailwindCSS = { 41 | experimental = { 42 | classRegex = { 43 | 'class\\s*:\\s*"([^"]*)', 44 | }, 45 | }, 46 | }, 47 | }, 48 | on_attach = function(_, bufnr) 49 | vim.keymap.set( 50 | "n", 51 | "tt", 52 | "Telescope tailwind css", 53 | { buffer = bufnr, desc = "[telescope] Tailwind" } 54 | ) 55 | end, 56 | } 57 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/statusline/explorer.lua: -------------------------------------------------------------------------------- 1 | local core = require "nougat.core" 2 | local Bar = require "nougat.bar" 3 | local Item = require "nougat.item" 4 | local sep = require "nougat.separator" 5 | 6 | local c = require "user.plugins.appearance.nougat.common" 7 | local nut = c.nut 8 | local color = c.color 9 | local stl = Bar "statusline" 10 | 11 | stl:add_item(nut.mode {}) 12 | stl:add_item(Item { 13 | hl = { bg = color.bg2, fg = "white" }, 14 | content = vim.fn.getcwd(0, 0), 15 | prefix = " ", 16 | suffix = " ", 17 | sep_right = sep.right_lower_triangle_solid(true), 18 | }) 19 | 20 | stl:add_item(nut.spacer()) 21 | stl:add_item(nut.truncation_point()) 22 | 23 | stl:add_item(nut.git.status { 24 | hl = { bg = color.bg2 }, 25 | added_hl = { fg = color.green }, 26 | added_prefix = " +", 27 | changed_prefix = " ~", 28 | removed_prefix = " -", 29 | changed_hl = { fg = color.blue }, 30 | removed_hl = { fg = color.red }, 31 | suffix = " ", 32 | -- sep_left = sep.left_lower_triangle_solid(true), 33 | }) 34 | stl:add_item(nut.git.branch { 35 | hl = { bg = color.green, fg = color.bg2 }, 36 | prefix = "  ", 37 | suffix = " ", 38 | hidden = function(_, ctx) 39 | return ctx.branch == "" 40 | end, 41 | sep_left = sep.left_lower_triangle_solid(true), 42 | global = true, 43 | }) 44 | 45 | stl:add_item(Item { 46 | hl = { bg = color.bg2, fg = color.blue }, 47 | sep_left = sep.left_lower_triangle_solid(true), 48 | content = core.group { 49 | core.code("l", { min_width = 2 }), 50 | ":", 51 | core.code("c", { min_width = 2 }), 52 | }, 53 | prefix = " ", 54 | suffix = " ", 55 | }) 56 | 57 | return stl 58 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/buf/icon.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | local buf_cache = require "nougat.cache.buffer" 3 | 4 | local has_devicons, devicons = pcall(require, "nvim-web-devicons") 5 | 6 | buf_cache.enable "filetype" 7 | 8 | local filetype_overide = { 9 | fugitive = "git", 10 | gitcommit = "git", 11 | } 12 | 13 | local function prepare(item, ctx) 14 | local filetype = buf_cache.get("filetype", ctx.bufnr) or "" 15 | local cache = item:cache(ctx) 16 | if not cache.c then 17 | local ft = filetype_overide[filetype] or filetype 18 | cache.c, cache.hl.fg = devicons.get_icon_color_by_filetype(ft, { default = true }) 19 | end 20 | end 21 | 22 | local function content(item, ctx) 23 | return item:cache(ctx).c 24 | end 25 | 26 | local cache_initial_value = { c = nil, hl = {} } 27 | 28 | local mod = {} 29 | 30 | function mod.create(opts) 31 | local item = Item { 32 | priority = opts.priority, 33 | prepare = prepare, 34 | hidden = opts.hidden, 35 | hl = function(item, ctx) 36 | return { fg = item:cache(ctx).hl.fg, bg = opts.hl.bg } 37 | end, 38 | 39 | sep_left = opts.sep_left, 40 | prefix = opts.prefix, 41 | content = content, 42 | suffix = opts.suffix, 43 | sep_right = opts.sep_right, 44 | on_click = opts.on_click, 45 | context = opts.context, 46 | cache = { 47 | name = "nnut.buf.icon", 48 | scope = "buf", 49 | get = function(store, ctx) 50 | return store[ctx.bufnr] 51 | end, 52 | initial_value = cache_initial_value, 53 | clear = "BufFilePost", 54 | }, 55 | } 56 | 57 | if not has_devicons then 58 | item.hidden = true 59 | end 60 | 61 | return item 62 | end 63 | 64 | return mod 65 | -------------------------------------------------------------------------------- /lua/user/early-init.lua: -------------------------------------------------------------------------------- 1 | vim.g.mapleader = " " 2 | vim.g.maplocalleader = "," 3 | 4 | if vim.fn.has "win32" == 1 then 5 | -- HACK: For some reason, the default `vim.ui.open` function does not work correctly on my environment. 6 | -- Prepending `cmd /c` to default cmd for `vim.ui.open` makes it work. 7 | local o = vim.ui.open 8 | vim.ui.open = function(...) 9 | local args = { ... } 10 | if args[2] == nil or (type(args[2]) == "table" and args[2].cmd == nil) then 11 | if args[2] == nil then 12 | args[2] = {} 13 | end 14 | args[2].cmd = { "cmd", "/c", "rundll32", "url.dll,FileProtocolHandler" } 15 | end 16 | o(unpack(args)) 17 | end 18 | end 19 | 20 | --- speeded up map function 21 | ---@param mode string|table 22 | --- 23 | ---@param lhs string 24 | ---@param rhs string|function 25 | --- 26 | ---@param opts table|nil 27 | function map(mode, lhs, rhs, opts) 28 | opts = opts or {} 29 | 30 | mode = type(mode) == "string" and { mode } or mode 31 | 32 | if opts.expr and opts.replace_keycodes ~= false then 33 | opts.replace_keycodes = true 34 | end 35 | 36 | if opts.remap == nil then 37 | -- default remap value is false 38 | opts.noremap = true 39 | else 40 | -- remaps behavior is opposite of noremap option. 41 | opts.noremap = not opts.remap 42 | opts.remap = nil 43 | end 44 | 45 | if type(rhs) == "function" then 46 | opts.callback = rhs 47 | rhs = "" 48 | end 49 | 50 | if opts.buffer then 51 | local bufnr = opts.buffer == true and 0 or opts.buffer 52 | opts.buffer = nil 53 | for _, m in ipairs(mode) do 54 | vim.api.nvim_buf_set_keymap(bufnr, m, lhs, rhs, opts) 55 | end 56 | else 57 | opts.buffer = nil 58 | for _, m in ipairs(mode) do 59 | vim.api.nvim_set_keymap(m, lhs, rhs, opts) 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/tinymist.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | local utils = require "user.shared.utils.typst" 3 | 4 | local pinned = {} 5 | 6 | local typst_utils = { 7 | --- @param client vim.lsp.Client 8 | unPinMain = function(client, bufnr) 9 | client:exec_cmd({ 10 | title = "unpin", 11 | command = "tinymist.pinMain", 12 | arguments = { vim.v.null }, 13 | }, { bufnr = bufnr }) 14 | end, 15 | 16 | --- @param client vim.lsp.Client 17 | pinMain = function(client, bufnr, path) 18 | client:exec_cmd({ 19 | title = "pin", 20 | command = "tinymist.pinMain", 21 | arguments = { path }, 22 | }, { bufnr = bufnr }) 23 | end, 24 | } 25 | 26 | return create_setup { 27 | on_attach = function(client, bufnr) 28 | vim.api.nvim_buf_create_user_command(bufnr, "TypstPinCurrent", function() 29 | typst_utils.pinMain(client, bufnr, vim.api.nvim_buf_get_name(0)) 30 | end, {}) 31 | 32 | vim.api.nvim_buf_create_user_command(bufnr, "TypstPin", function(opts) 33 | typst_utils.pinMain(client, bufnr, opts.fargs[1]) 34 | end, { nargs = 1 }) 35 | 36 | vim.api.nvim_buf_create_user_command(bufnr, "TypstUnpin", function() 37 | typst_utils.unPinMain(client) 38 | end, {}) 39 | 40 | local root_file = utils.get_typst_main_file(vim.api.nvim_buf_get_name(bufnr)) 41 | if root_file ~= nil then 42 | if not pinned[root_file] then 43 | vim.defer_fn(function() 44 | typst_utils.pinMain(client, bufnr, root_file) 45 | pinned[root_file] = true 46 | vim.notify("[tinymist] Pinned to " .. root_file) 47 | end, 1000) 48 | end 49 | end 50 | end, 51 | root_dir = function(bufnr, cb) 52 | cb(utils.get_typst_root_dir(vim.api.nvim_buf_get_name(bufnr))) 53 | end, 54 | settings = { 55 | formatterMode = "typstyle", 56 | compileStatus = "enable", 57 | }, 58 | } 59 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/toggleterm.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "akinsho/toggleterm.nvim", 3 | 4 | cmd = { "ToggleTerm", "ToggleTermOpen" }, 5 | init = function() 6 | map("n", [[]], function() 7 | local tmp = vim.opt.shellcmdflag 8 | if require("user.shared.utils.system").is_msys2 then 9 | vim.opt.shellcmdflag = "-li" 10 | end 11 | vim.cmd 'execute v:count1 . "ToggleTerm"' 12 | vim.opt.shellcmdflag = tmp 13 | end, { desc = "[toggleterm] toggle" }) 14 | map("t", [[]], "ToggleTerm", { desc = "[toggleterm] toggle" }) 15 | map("t", "", "") 16 | 17 | vim.api.nvim_create_autocmd("TermOpen", { 18 | pattern = "*", 19 | group = vim.api.nvim_create_augroup("terminal", { clear = true }), 20 | callback = function() 21 | map("n", "q", [[q]], { buffer = 0, desc = "Quit terminal buffer" }) 22 | end, 23 | }) 24 | end, 25 | config = function() 26 | require("toggleterm").setup { 27 | hide_numbers = false, 28 | shade_filetypes = {}, 29 | shade_terminals = true, 30 | start_in_insert = true, 31 | insert_mappings = true, 32 | persist_size = true, 33 | close_on_exit = false, 34 | on_open = function() 35 | vim.fn.timer_start(1, function() 36 | vim.cmd "startinsert!" 37 | end) 38 | end, 39 | shell = function() 40 | local shell = vim.o.shell 41 | 42 | -- In windows native, SHELL env variable does not exist. So vim.opt.shell will be automatically set to 'cmd.exe'. 43 | -- I would like to use pwsh instead, so set it. 44 | if require("user.shared.utils.system").is_win then 45 | if vim.env.SHELL == nil then 46 | if vim.env.NU_VERSION ~= nil then 47 | shell = "nu.exe" 48 | else 49 | shell = "pwsh.exe" 50 | end 51 | end 52 | end 53 | return shell 54 | end, 55 | } 56 | end, 57 | } 58 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/git/status.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | 3 | local prepare = function(_, ctx) 4 | local git_status = vim.b.gitsigns_status_dict 5 | if git_status == nil then 6 | git_status = {} 7 | end 8 | if git_status["added"] == nil then 9 | git_status["added"] = 0 10 | end 11 | if git_status["changed"] == nil then 12 | git_status["changed"] = 0 13 | end 14 | if git_status["removed"] == nil then 15 | git_status["removed"] = 0 16 | end 17 | 18 | ctx.gitstatus = git_status 19 | end 20 | 21 | local content = function(key, opts) 22 | return Item { 23 | priority = opts.priority, 24 | hidden = function(_, ctx) 25 | return ctx.gitstatus[key] == 0 26 | end, 27 | hl = { fg = opts[key .. "_hl"].fg, bg = opts.hl.bg }, 28 | prefix = opts[key .. "_prefix"], 29 | content = function(_, ctx) 30 | return tostring(ctx.gitstatus[key]) 31 | end, 32 | prepare = prepare, 33 | -- suffix = opts.suffix, 34 | -- sep_right = opts.sep_right, 35 | on_click = opts.on_click, 36 | context = opts.context, 37 | cache = { 38 | scope = "buf", 39 | clear = "BufModifiedSet", 40 | }, 41 | } 42 | end 43 | 44 | local mod = {} 45 | 46 | function mod.create(opts) 47 | local item = Item { 48 | priority = opts.priority, 49 | hidden = function(_, ctx) 50 | return ctx.gitstatus.added == 0 and ctx.gitstatus.changed == 0 and ctx.gitstatus.removed == 0 51 | end, 52 | hl = opts.hl, 53 | sep_left = opts.sep_left, 54 | prefix = opts.prefix, 55 | content = { 56 | content("added", opts), 57 | content("changed", opts), 58 | content("removed", opts), 59 | }, 60 | prepare = prepare, 61 | suffix = opts.suffix, 62 | sep_right = opts.sep_right, 63 | on_click = opts.on_click, 64 | context = opts.context, 65 | cache = { 66 | scope = "buf", 67 | clear = "BufModifiedSet", 68 | }, 69 | } 70 | 71 | return item 72 | end 73 | 74 | return mod 75 | -------------------------------------------------------------------------------- /lua/user/plugins/treesitter/init.lua: -------------------------------------------------------------------------------- 1 | ---@diagnostic disable: inject-field 2 | return Args.feature.vscode and {} 3 | or { 4 | { 5 | "nvim-treesitter/nvim-treesitter", 6 | event = { "BufReadPre", "BufNewFile" }, 7 | build = ":TSUpdate", 8 | cmd = { "TSInstall", "TSUpdate", "TSUninstall" }, 9 | branch = "main", 10 | dependencies = { 11 | { 12 | "nazo6/ts-query-installer.nvim", 13 | config = function() 14 | require("ts-query-installer").setup { 15 | sources = { 16 | satysfi = { 17 | repo = "https://github.com/monaqa/tree-sitter-satysfi", 18 | }, 19 | surrealdb = { 20 | repo = "https://github.com/DariusCorvus/tree-sitter-surrealdb", 21 | }, 22 | }, 23 | } 24 | end, 25 | }, 26 | { "williamboman/mason.nvim" }, 27 | }, 28 | config = function() 29 | vim.api.nvim_create_autocmd("FileType", { 30 | group = vim.api.nvim_create_augroup("vim-treesitter-start", {}), 31 | callback = function() 32 | pcall(vim.treesitter.start) 33 | end, 34 | }) 35 | end, 36 | }, 37 | { 38 | "atusy/tsnode-marker.nvim", 39 | ft = { "markdown" }, 40 | init = function() 41 | vim.api.nvim_create_autocmd("FileType", { 42 | group = vim.api.nvim_create_augroup("tsnode-marker-markdown", {}), 43 | pattern = { "markdown" }, 44 | callback = function(ctx) 45 | require("tsnode-marker").set_automark(ctx.buf, { 46 | target = { "code_fence_content" }, 47 | hl_group = "CursorLine", 48 | }) 49 | end, 50 | }) 51 | end, 52 | }, 53 | { 54 | "windwp/nvim-ts-autotag", 55 | event = { "BufRead" }, 56 | opts = { 57 | aliases = { 58 | ["mdx"] = "typescriptreact", 59 | }, 60 | }, 61 | }, 62 | } 63 | -------------------------------------------------------------------------------- /lua/user/plugins/ai/codecompanion/fidget.lua: -------------------------------------------------------------------------------- 1 | local progress = require "fidget.progress" 2 | 3 | local M = {} 4 | 5 | function M:init() 6 | local group = vim.api.nvim_create_augroup("CodeCompanionFidgetHooks", {}) 7 | 8 | vim.api.nvim_create_autocmd({ "User" }, { 9 | pattern = "CodeCompanionRequestStarted", 10 | group = group, 11 | callback = function(request) 12 | local handle = M:create_progress_handle(request) 13 | M:store_progress_handle(request.data.id, handle) 14 | end, 15 | }) 16 | 17 | vim.api.nvim_create_autocmd({ "User" }, { 18 | pattern = "CodeCompanionRequestFinished", 19 | group = group, 20 | callback = function(request) 21 | local handle = M:pop_progress_handle(request.data.id) 22 | if handle then 23 | M:report_exit_status(handle, request) 24 | handle:finish() 25 | end 26 | end, 27 | }) 28 | end 29 | 30 | M.handles = {} 31 | 32 | function M:store_progress_handle(id, handle) 33 | M.handles[id] = handle 34 | end 35 | 36 | function M:pop_progress_handle(id) 37 | local handle = M.handles[id] 38 | M.handles[id] = nil 39 | return handle 40 | end 41 | 42 | function M:create_progress_handle(request) 43 | return progress.handle.create { 44 | title = " Requesting assistance (" .. request.data.strategy .. ")", 45 | message = "In progress...", 46 | lsp_client = { 47 | name = M:llm_role_title(request.data.adapter), 48 | }, 49 | } 50 | end 51 | 52 | function M:llm_role_title(adapter) 53 | local parts = {} 54 | table.insert(parts, adapter.formatted_name) 55 | if adapter.model and adapter.model ~= "" then 56 | table.insert(parts, "(" .. adapter.model .. ")") 57 | end 58 | return table.concat(parts, " ") 59 | end 60 | 61 | function M:report_exit_status(handle, request) 62 | if request.data.status == "success" then 63 | handle.message = "Completed" 64 | elseif request.data.status == "error" then 65 | handle.message = " Error" 66 | else 67 | handle.message = "󰜺 Cancelled" 68 | end 69 | end 70 | 71 | return M 72 | -------------------------------------------------------------------------------- /lua/user/lsp/attach.lua: -------------------------------------------------------------------------------- 1 | vim.api.nvim_create_autocmd("LspAttach", { 2 | callback = function(ctx) 3 | local map = vim.keymap.set 4 | local client = vim.lsp.get_client_by_id(ctx.data.client_id) 5 | assert(client, "No client found") 6 | local bufnr = ctx.buf 7 | 8 | vim.lsp.inlay_hint.enable(true) 9 | 10 | if client.name == "copilot" then 11 | return 12 | end 13 | 14 | if client.server_capabilities.documentSymbolProvider then 15 | require("nvim-navic").attach(client, bufnr) 16 | end 17 | 18 | map("n", "gi", "lua vim.lsp.buf.implementation()", { buffer = bufnr, desc = "[LSP] Go implementation" }) 19 | 20 | map("n", "gd", "Glance definitions", { buffer = bufnr, desc = "[LSP] Go definitions" }) 21 | map( 22 | "n", 23 | "gD", 24 | "lua vim.lsp.buf.definition()", 25 | { buffer = bufnr, desc = "[LSP] Go definitions using builtin func" } 26 | ) 27 | map("n", "gr", "Glance references", { buffer = bufnr, desc = "[LSP] Go references" }) 28 | 29 | map("n", "K", "lua vim.lsp.buf.hover({border='rounded'})", { buffer = bufnr, desc = "[LSP] Hover" }) 30 | map( 31 | { "n", "i" }, 32 | "", 33 | "lua vim.lsp.buf.signature_help({border='rounded'})", 34 | { buffer = bufnr, desc = "[LSP] Signature help" } 35 | ) 36 | 37 | map("n", "rn", "lua vim.lsp.buf.rename()", { buffer = bufnr, desc = "[LSP] Rename" }) 38 | map( 39 | { "n", "v" }, 40 | "ca", 41 | [[lua require("actions-preview").code_actions()]], 42 | { buffer = bufnr, desc = "[LSP] Code actions" } 43 | ) 44 | map( 45 | "n", 46 | "e", 47 | "lua vim.diagnostic.open_float(0,{border='rounded'})", 48 | { buffer = bufnr, desc = "[LSP] Show diagnostics" } 49 | ) 50 | 51 | map( 52 | "n", 53 | "q", 54 | "lua vim.lsp.diagnostic.set_loclist()", 55 | { buffer = bufnr, desc = "[LSP] Set loclist" } 56 | ) 57 | end, 58 | }) 59 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/smart-splits.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "mrjones2014/smart-splits.nvim", 3 | init = function() 4 | map("n", "", "lua require('smart-splits').resize_left()") 5 | map("n", "", "lua require('smart-splits').resize_down()") 6 | map("n", "", "lua require('smart-splits').resize_up()") 7 | map("n", "", "lua require('smart-splits').resize_right()") 8 | -- moving between splits 9 | map("n", "", "lua require('smart-splits').move_cursor_left()") 10 | map("n", "", "lua require('smart-splits').move_cursor_down()") 11 | map("n", "", "lua require('smart-splits').move_cursor_up()") 12 | map("n", "", "lua require('smart-splits').move_cursor_right()") 13 | end, 14 | config = function() 15 | require("smart-splits").setup { 16 | -- Ignored filetypes (only while resizing) 17 | ignored_filetypes = { 18 | "nofile", 19 | "quickfix", 20 | "prompt", 21 | }, 22 | -- Ignored buffer types (only while resizing) 23 | ignored_buftypes = { "neo-tree", "NvimTree" }, 24 | -- when moving cursor between splits left or right, 25 | -- place the cursor on the same row of the *screen* 26 | -- regardless of line numbers. False by default. 27 | -- Can be overridden via function parameter, see Usage. 28 | move_cursor_same_row = false, 29 | -- resize mode options 30 | resize_mode = { 31 | -- key to exit persistent resize mode 32 | quit_key = "", 33 | -- keys to use for moving in resize mode 34 | -- in order of left, down, up' right 35 | resize_keys = { "h", "j", "k", "l" }, 36 | -- set to true to silence the notifications 37 | -- when entering/exiting persistent resize mode 38 | silent = false, 39 | -- must be functions, they will be executed when 40 | -- entering or exiting the resize mode 41 | hooks = { 42 | on_enter = nil, 43 | on_leave = nil, 44 | }, 45 | }, 46 | } 47 | end, 48 | } 49 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/ufo.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "kevinhwang91/nvim-ufo", 3 | dependencies = { 4 | "kevinhwang91/promise-async", 5 | { 6 | "luukvbaal/statuscol.nvim", 7 | config = function() 8 | local builtin = require "statuscol.builtin" 9 | require("statuscol").setup { 10 | relculright = true, 11 | segments = { 12 | { text = { builtin.foldfunc }, click = "v:lua.ScFa" }, 13 | { text = { "%s" }, click = "v:lua.ScSa" }, 14 | { text = { builtin.lnumfunc, " " }, click = "v:lua.ScLa" }, 15 | }, 16 | } 17 | end, 18 | }, 19 | }, 20 | init = function() 21 | map("n", "zR", [[lua require("ufo").openAllFolds()]]) 22 | map("n", "zM", [[lua require("ufo").closeAllFolds()]]) 23 | end, 24 | config = function() 25 | require("ufo").setup { 26 | provider_selector = function(bufnr, filetype, buftype) 27 | return { "treesitter", "indent" } 28 | end, 29 | fold_virt_text_handler = function(virtText, lnum, endLnum, width, truncate) 30 | local newVirtText = {} 31 | local suffix = (" 󰁂 %d "):format(endLnum - lnum) 32 | local sufWidth = vim.fn.strdisplaywidth(suffix) 33 | local targetWidth = width - sufWidth 34 | local curWidth = 0 35 | for _, chunk in ipairs(virtText) do 36 | local chunkText = chunk[1] 37 | local chunkWidth = vim.fn.strdisplaywidth(chunkText) 38 | if targetWidth > curWidth + chunkWidth then 39 | table.insert(newVirtText, chunk) 40 | else 41 | chunkText = truncate(chunkText, targetWidth - curWidth) 42 | local hlGroup = chunk[2] 43 | table.insert(newVirtText, { chunkText, hlGroup }) 44 | chunkWidth = vim.fn.strdisplaywidth(chunkText) 45 | if curWidth + chunkWidth < targetWidth then 46 | suffix = suffix .. (" "):rep(targetWidth - curWidth - chunkWidth) 47 | end 48 | break 49 | end 50 | curWidth = curWidth + chunkWidth 51 | end 52 | table.insert(newVirtText, { suffix, "MoreMsg" }) 53 | return newVirtText 54 | end, 55 | } 56 | end, 57 | } 58 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/buf/lsp_servers.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | local core = require "nougat.core" 3 | local get_hl_name = require("nougat.util.hl").get_hl_name 4 | 5 | local function get_content(item, ctx) 6 | ---@type nougat_nut_lsp_servers_config_config 7 | local config = item:config(ctx) 8 | local clients = vim.lsp.get_clients { bufnr = ctx.bufnr } 9 | local part_idx, parts = 0, {} 10 | for _, client in ipairs(clients) do 11 | local content = config.content(client, item, ctx) 12 | if content then 13 | if not content[1] then 14 | content = { content } 15 | end 16 | for idx = 1, #content do 17 | local part = content[idx] 18 | if type(part) == "table" then 19 | if part.hl then 20 | part_idx = core.add_highlight(get_hl_name(part.hl, ctx.hl), nil, parts, part_idx) 21 | end 22 | part_idx = part_idx + 1 23 | parts[part_idx] = part.content 24 | if part.hl then 25 | part_idx = core.add_highlight(get_hl_name(item.hl or ctx.hl, ctx.hl), nil, parts, part_idx) 26 | end 27 | else 28 | part_idx = part_idx + 1 29 | parts[part_idx] = part 30 | end 31 | part_idx = part_idx + 1 32 | parts[part_idx] = config.sep 33 | end 34 | end 35 | end 36 | return table.concat(parts, nil, 1, part_idx - 1) 37 | end 38 | 39 | local mod = {} 40 | 41 | ---@param opts nougat_nut_lsp_servers_config 42 | function mod.create(opts) 43 | local config = vim.tbl_deep_extend("force", { 44 | content = function(client) 45 | return client.name 46 | end, 47 | sep = " ", 48 | }, opts.config or {}) 49 | ---@cast config nougat_nut_lsp_servers_config_config|nougat_nut_lsp_servers_config_config[] 50 | 51 | local item = Item { 52 | init = opts.init, 53 | priority = opts.priority, 54 | hidden = opts.hidden, 55 | hl = opts.hl, 56 | sep_left = opts.sep_left, 57 | prefix = opts.prefix, 58 | content = get_content, 59 | suffix = opts.suffix, 60 | sep_right = opts.sep_right, 61 | config = config, 62 | on_click = opts.on_click, 63 | context = opts.context, 64 | ctx = opts.ctx, 65 | cache = { 66 | scope = "buf", 67 | clear = { 68 | "LspAttach", 69 | "LspDetach", 70 | }, 71 | }, 72 | } 73 | 74 | return item 75 | end 76 | 77 | return mod 78 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/common.lua: -------------------------------------------------------------------------------- 1 | return { 2 | nut = { 3 | buf = { 4 | diagnostic_count = require("nougat.nut.buf.diagnostic_count").create, 5 | filename = require("user.plugins.appearance.nougat.nut.buf.filename").create, 6 | filestatus = require("nougat.nut.buf.filestatus").create, 7 | filetype = require("user.plugins.appearance.nougat.nut.buf.filetype").create, 8 | icon = require("user.plugins.appearance.nougat.nut.buf.icon").create, 9 | navic = require("user.plugins.appearance.nougat.nut.buf.navic").create, 10 | fileformat = require("user.plugins.appearance.nougat.nut.buf.fileformat").create, 11 | encoding = require("user.plugins.appearance.nougat.nut.buf.encoding").create, 12 | fmo = require("user.plugins.appearance.nougat.nut.buf.fmo").create, 13 | copilot = require("user.plugins.appearance.nougat.nut.buf.copilot").create, 14 | }, 15 | git = { 16 | branch = require("user.plugins.appearance.nougat.nut.git.branch").create, 17 | status = require("user.plugins.appearance.nougat.nut.git.status").create, 18 | }, 19 | tab = { 20 | tablist = { 21 | tabs = require("nougat.nut.tab.tablist").create, 22 | close = require("nougat.nut.tab.tablist.close").create, 23 | icon = require("nougat.nut.tab.tablist.icon").create, 24 | label = require("nougat.nut.tab.tablist.label").create, 25 | modified = require("nougat.nut.tab.tablist.modified").create, 26 | }, 27 | }, 28 | lsp = { 29 | servers = require("nougat.nut.lsp.servers").create, 30 | }, 31 | mode = require("user.plugins.appearance.nougat.nut.mode").create, 32 | spacer = require("nougat.nut.spacer").create, 33 | truncation_point = require("nougat.nut.truncation_point").create, 34 | }, 35 | ---@type nougat.color 36 | color = require("nougat.color").get(), 37 | separators = { 38 | vertical_bar = "┃", 39 | vertical_bar_thin = "│", 40 | left = "", 41 | right = "", 42 | block = "█", 43 | left_filled = "", 44 | right_filled = "", 45 | slant_left = "", 46 | slant_left_thin = "", 47 | slant_right = "", 48 | slant_right_thin = "", 49 | slant_left_2 = "", 50 | slant_left_2_thin = "", 51 | slant_right_2 = "", 52 | slant_right_2_thin = "", 53 | left_rounded = "", 54 | left_rounded_thin = "", 55 | right_rounded = "", 56 | right_rounded_thin = "", 57 | circle = " ", 58 | }, 59 | } 60 | -------------------------------------------------------------------------------- /lua/user/config/keymaps.lua: -------------------------------------------------------------------------------- 1 | -- move 2 | map("n", "k", "gk") 3 | map("n", "gk", "k") 4 | map("n", "j", "gj") 5 | map("n", "gj", "j") 6 | 7 | map({ "n", "v" }, "", "^", { desc = "Move to first of line" }) 8 | map({ "n", "v" }, "", "$", { desc = "Move to end of line" }) 9 | 10 | map("n", "", "") 11 | map("n", "", "") 12 | 13 | map({ "n", "x" }, "c", [["_c]]) 14 | map({ "n", "x" }, "d", [["_d]]) 15 | 16 | map("n", "dp", "lua vim.diagnostic.goto_prev()") 17 | map("n", "dn", "lua vim.diagnostic.goto_next()") 18 | 19 | -- action 20 | map("n", "q", "q", { desc = "Exit neovim" }) 21 | map("n", "w", "w", { desc = "Save file" }) 22 | 23 | map("n", "", function() 24 | if vim.api.nvim_win_get_config(0).zindex then 25 | vim.api.nvim_win_close(0, false) 26 | end 27 | end, { 28 | desc = "close window if it's a popup", 29 | }) 30 | 31 | map("n", "f", function() 32 | local cwd = vim.fn.getcwd() 33 | vim.ui.open(cwd) 34 | end, { desc = "Open cwd" }) 35 | 36 | map("n", "re", "Restart", { desc = "Restart neovim" }) 37 | 38 | -- inspired by term-edit.nvim, simple version 39 | vim.api.nvim_create_autocmd("TermOpen", { 40 | pattern = "*", 41 | callback = function() 42 | map("n", "i", function() 43 | local term_mode_pos_res = vim.fn.getcursorcharpos(0) 44 | local term_mode_pos = { term_mode_pos_res[2], term_mode_pos_res[3] } 45 | 46 | vim.cmd.startinsert() 47 | 48 | vim.defer_fn(function() 49 | local ins_mode_pos_res = vim.fn.getcursorcharpos(0) 50 | local ins_mode_pos = { ins_mode_pos_res[2], ins_mode_pos_res[3] } 51 | 52 | if term_mode_pos[1] == ins_mode_pos[1] then 53 | local diff = term_mode_pos[2] - ins_mode_pos[2] 54 | if diff < 0 then 55 | local keys = string.rep("", diff * -1) 56 | local k = vim.api.nvim_replace_termcodes(keys, true, true, true) 57 | vim.api.nvim_feedkeys(k, "n", false) 58 | end 59 | if diff > 0 then 60 | local keys = string.rep("", diff) 61 | local k = vim.api.nvim_replace_termcodes(keys, true, true, true) 62 | vim.api.nvim_feedkeys(k, "n", false) 63 | end 64 | end 65 | end, 10) 66 | end) 67 | end, 68 | }) 69 | 70 | -- overwite default 71 | if not Args.feature.vscode then 72 | map("n", "K", "") 73 | end 74 | map("n", "", "") 75 | -------------------------------------------------------------------------------- /lua/user/lsp/server-configs/denols.lua: -------------------------------------------------------------------------------- 1 | local create_setup = require("user.lsp.config-builder").create_setup 2 | local node_or_deno = require("user.shared.lsp-selector.web").judge 3 | 4 | local deno_client = nil 5 | 6 | -- HACK: Overrides vim.uri_to_bufnr to handle deno:/ protocol. 7 | -- For default lsp handler, lspconfig automatically sets this handler, 8 | -- but if LSP methods is called from other places (ex: glance.nvim), this does not work. 9 | 10 | ---@return nil|vim.lsp.Client 11 | local function get_deno_client() 12 | if deno_client == nil then 13 | deno_client = vim.lsp.get_clients({ name = "denols" })[1] 14 | end 15 | return deno_client 16 | end 17 | 18 | local function virtual_text_document_handler(bufnr, res, client) 19 | if not res then 20 | return nil 21 | end 22 | 23 | local lines = vim.split(res.result, "\n") 24 | 25 | local current_buf = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) 26 | if #current_buf ~= 0 then 27 | return nil 28 | end 29 | 30 | vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) 31 | vim.api.nvim_set_option_value("readonly", true, { buf = bufnr }) 32 | vim.api.nvim_set_option_value("modified", false, { buf = bufnr }) 33 | vim.api.nvim_set_option_value("modifiable", false, { buf = bufnr }) 34 | -- HACK: If buflisted is 0, glance executes `:e` and it causes to open empty buffer. 35 | vim.api.nvim_set_option_value("buflisted", true, { buf = bufnr }) 36 | vim.lsp.buf_attach_client(bufnr, client.id) 37 | end 38 | 39 | return create_setup(function() 40 | local uri_to_bufnr_orig = vim.uri_to_bufnr 41 | 42 | vim.uri_to_bufnr = function(uri) 43 | local buf = uri_to_bufnr_orig(uri) 44 | 45 | if uri:match "^deno:" then 46 | local client = get_deno_client() 47 | if client ~= nil then 48 | local params = { 49 | textDocument = { 50 | uri = uri, 51 | }, 52 | } 53 | local result = client:request_sync("deno/virtualTextDocument", params) 54 | virtual_text_document_handler(buf, result, client) 55 | end 56 | end 57 | 58 | return buf 59 | end 60 | 61 | return { 62 | root_dir = function(bufnr, cb) 63 | if node_or_deno(bufnr).type == "deno" then 64 | cb(node_or_deno(bufnr).root) 65 | end 66 | end, 67 | settings = { 68 | enable = true, 69 | lint = true, 70 | unstable = true, 71 | }, 72 | on_attach = function(client) 73 | client.server_capabilities.executeCommandProvider = true 74 | end, 75 | } 76 | end) 77 | -------------------------------------------------------------------------------- /lua/user/plugins/git/diffview.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "sindrets/diffview.nvim", 3 | dependencies = { 4 | { "nvim-lua/plenary.nvim" }, 5 | }, 6 | cmd = { "DiffviewOpen", "DiffviewFileHistory" }, 7 | init = function() 8 | map("n", "", "DiffviewOpen") 9 | map("n", "", "DiffviewFileHistory") 10 | 11 | map("n", "GitCommit", function() 12 | local Input = require "nui.input" 13 | local event = require("nui.utils.autocmd").event 14 | local input = Input({ 15 | position = "50%", 16 | relative = "editor", 17 | size = { 18 | width = 50, 19 | }, 20 | border = { 21 | style = "rounded", 22 | text = { 23 | top = "Enter commit message (Leave empty to open buffer):", 24 | top_align = "center", 25 | }, 26 | }, 27 | }, { 28 | on_submit = function(value) 29 | if #value == 0 then 30 | vim.cmd "Git commit" 31 | else 32 | vim.cmd([[Git commit -m "]] .. value .. [["]]) 33 | end 34 | end, 35 | }) 36 | input:mount() 37 | input:map("i", "", function() 38 | input:unmount() 39 | end) 40 | input:on(event.BufLeave, function() 41 | input:unmount() 42 | end) 43 | end) 44 | end, 45 | config = function() 46 | local actions = require "diffview.actions" 47 | 48 | require("diffview").setup { 49 | keymaps = { 50 | file_panel = { 51 | { "n", "q", "DiffviewClose", { desc = "Close diffview" } }, 52 | { "n", "j", actions.select_next_entry, { desc = "Select next entry" } }, 53 | { "n", "", actions.select_next_entry, { desc = "Select next entry" } }, 54 | { "n", "k", actions.select_prev_entry, { desc = "Select prev entry" } }, 55 | { "n", "", actions.select_prev_entry, { desc = "Select prev entry" } }, 56 | { "n", "c", "GitCommit", { desc = "Open commit window" } }, 57 | { "n", "?", actions.help "file_panel", { desc = "Open the help panel" } }, 58 | 59 | { "n", "p", "Git pull", { desc = "Open the help panel" } }, 60 | { "n", "P", "Git push", { desc = "Open the help panel" } }, 61 | }, 62 | file_history_panel = { 63 | { "n", "q", "DiffviewClose", { desc = "Close diffview" } }, 64 | { "n", "?", actions.help "file_history_panel", { desc = "Open the help panel" } }, 65 | }, 66 | }, 67 | } 68 | end, 69 | } 70 | -------------------------------------------------------------------------------- /lua/user/plugins/language/flutter.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "akinsho/flutter-tools.nvim", 3 | dependencies = { { "nvim-lua/plenary.nvim" } }, 4 | ft = { "dart" }, 5 | enabled = not Args.feature.vscode, 6 | config = function() 7 | require("flutter-tools").setup { 8 | ui = { border = "rounded" }, 9 | debugger = { 10 | enabled = true, 11 | run_via_dap = false, 12 | register_configurations = function(paths) 13 | if require("user.shared.utils.system").is_win then 14 | require("dap").adapters.dart = { 15 | command = paths.dart_sdk .. "\\bin\\dart.exe", 16 | args = { 17 | "--disable-dart-dev", 18 | "--packages=" .. paths.flutter_sdk .. "\\packages\\flutter_tools\\.packages", 19 | paths.flutter_sdk .. "\\bin\\cache\\flutter_tools.snapshot", 20 | "debug-adapter", 21 | }, 22 | options = { 23 | initialize_timeout_sec = 10, 24 | }, 25 | type = "executable", 26 | } 27 | end 28 | 29 | require("dap").configurations.dart = { 30 | { 31 | type = "dart", 32 | request = "launch", 33 | name = "Launch flutter", 34 | dartSdkPath = paths.dart_sdk, 35 | flutterSdkPath = paths.flutter_sdk, 36 | program = "${workspaceFolder}/lib/main.dart", 37 | cwd = "${workspaceFolder}", 38 | args = { "-d", "windows" }, 39 | }, 40 | { 41 | type = "dart", 42 | request = "attach", 43 | name = "Connect flutter", 44 | dartSdkPath = paths.dart_sdk, 45 | flutterSdkPath = paths.flutter_sdk, 46 | program = "${workspaceFolder}/lib/main.dart", 47 | cwd = "${workspaceFolder}", 48 | }, 49 | } 50 | end, 51 | }, 52 | widget_guides = { enabled = true }, 53 | closing_tags = { prefix = ">", enabled = true }, 54 | dev_log = { open_cmd = "tabedit" }, 55 | dev_tools = { 56 | autostart = true, 57 | autoopen_browser = true, 58 | }, 59 | lsp = { 60 | settings = { showTodos = true, completeFunctionCalls = true }, 61 | }, 62 | } 63 | 64 | vim.api.nvim_create_augroup("FlutterOutlineMap", {}) 65 | vim.api.nvim_create_autocmd({ "FileType" }, { 66 | group = "FlutterOutlineMap", 67 | once = true, 68 | pattern = { "dart", "flutterToolsOutline" }, 69 | callback = function() 70 | map("n", "o", "FlutterOutlineToggle", { buffer = true }) 71 | end, 72 | }) 73 | end, 74 | } 75 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/nut/mode.lua: -------------------------------------------------------------------------------- 1 | local Item = require "nougat.item" 2 | local color = require("nougat.color").get() 3 | local on_event = require("nougat.util").on_event 4 | 5 | local mode_group = { 6 | ["n"] = "normal", 7 | ["no"] = "normal", 8 | ["nov"] = "normal", 9 | ["noV"] = "normal", 10 | ["no"] = "normal", 11 | ["niI"] = "normal", 12 | ["niR"] = "normal", 13 | ["niV"] = "normal", 14 | ["nt"] = "normal", 15 | ["ntT"] = "normal", 16 | 17 | ["v"] = "visual", 18 | ["vs"] = "visual", 19 | ["V"] = "visual", 20 | ["Vs"] = "visual", 21 | [""] = "visual", 22 | ["s"] = "visual", 23 | 24 | ["s"] = "visual", 25 | ["S"] = "visual", 26 | [""] = "visual", 27 | 28 | ["i"] = "insert", 29 | ["ic"] = "insert", 30 | ["ix"] = "insert", 31 | 32 | ["R"] = "replace", 33 | ["Rc"] = "replace", 34 | ["Rx"] = "replace", 35 | ["Rv"] = "replace", 36 | ["Rvc"] = "replace", 37 | ["Rvx"] = "replace", 38 | 39 | ["c"] = "commandline", 40 | ["cv"] = "commandline", 41 | ["ce"] = "commandline", 42 | ["r"] = "commandline", 43 | ["rm"] = "commandline", 44 | ["r?"] = "commandline", 45 | ["!"] = "commandline", 46 | 47 | ["t"] = "terminal", 48 | 49 | ["-"] = "inactive", 50 | } 51 | 52 | local default_highlight = { 53 | normal = { 54 | bg = "fg", 55 | fg = "bg", 56 | }, 57 | visual = { 58 | bg = color.yellow, 59 | fg = "bg", 60 | }, 61 | insert = { 62 | bg = color.blue, 63 | fg = "bg", 64 | }, 65 | replace = { 66 | bg = color.magenta, 67 | fg = "bg", 68 | }, 69 | commandline = { 70 | bg = color.green, 71 | fg = "bg", 72 | }, 73 | terminal = { 74 | bg = color.cyan, 75 | fg = "bg", 76 | }, 77 | inactive = { 78 | bg = "fg", 79 | fg = "bg", 80 | }, 81 | } 82 | 83 | local cache = { 84 | mode = "n", 85 | group = mode_group["n"], 86 | } 87 | 88 | on_event("ModeChanged", function() 89 | local event = vim.v.event 90 | local old_mode, new_mode = event.old_mode, event.new_mode 91 | cache.mode, cache.group = new_mode, mode_group[new_mode] 92 | if old_mode == "t" then 93 | vim.schedule(function() 94 | vim.cmd "redrawstatus" 95 | end) 96 | end 97 | end) 98 | 99 | local function get_hl(item, ctx) 100 | return default_highlight[ctx.is_focused and cache.group or "inactive"] 101 | end 102 | 103 | local mod = {} 104 | 105 | function mod.create(opts) 106 | opts = opts or {} 107 | 108 | local item = Item { 109 | priority = opts.priority, 110 | hidden = opts.hidden, 111 | hl = get_hl, 112 | sep_left = opts.sep_left, 113 | prefix = opts.prefix, 114 | content = " ", 115 | suffix = opts.suffix, 116 | sep_right = opts.sep_right, 117 | on_click = opts.on_click, 118 | context = opts.context, 119 | } 120 | 121 | return item 122 | end 123 | 124 | return mod 125 | -------------------------------------------------------------------------------- /lua/user/plugins/common/hydra/windows.lua: -------------------------------------------------------------------------------- 1 | local window_hint = [[ 2 | ^^^^^^^^^^^^ Move ^^ Size ^^ ^^ Split 3 | ^^^^^^^^^^^^------------- ^^-----------^^ ^^--------------- 4 | ^ ^ _k_ ^ ^ ^ ^ _K_ ^ ^ ^ __ ^ _s_: horizontally 5 | _h_ ^ ^ _l_ _H_ ^ ^ _L_ __ __ _v_: vertically 6 | ^ ^ _j_ ^ ^ ^ ^ _J_ ^ ^ ^ __ ^ _q_, _c_: close 7 | focus^^^^^^ window^^^^^^ ^_=_: equalize^ _z_: maximize 8 | ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^^ ^ ^ _o_: remain only 9 | ]] 10 | 11 | local M = {} 12 | 13 | M.key = "w" 14 | 15 | M.setup = function() 16 | local Hydra = require "hydra" 17 | local cmd = require("hydra.keymap-util").cmd 18 | local pcmd = require("hydra.keymap-util").pcmd 19 | local splits = require "smart-splits" 20 | 21 | Hydra { 22 | name = "Windows", 23 | hint = window_hint, 24 | config = { 25 | invoke_on_body = true, 26 | hint = { 27 | offset = -1, 28 | float_opts = { 29 | border = "single", 30 | }, 31 | }, 32 | }, 33 | mode = "n", 34 | body = M.key, 35 | heads = { 36 | { "h", "h" }, 37 | { "j", "j" }, 38 | { "k", pcmd("wincmd k", "E11", "close") }, 39 | { "l", "l" }, 40 | 41 | { "H", cmd "WinShift left" }, 42 | { "J", cmd "WinShift down" }, 43 | { "K", cmd "WinShift up" }, 44 | { "L", cmd "WinShift right" }, 45 | 46 | { 47 | "", 48 | function() 49 | splits.resize_left(2) 50 | end, 51 | }, 52 | { 53 | "", 54 | function() 55 | splits.resize_down(2) 56 | end, 57 | }, 58 | { 59 | "", 60 | function() 61 | splits.resize_up(2) 62 | end, 63 | }, 64 | { 65 | "", 66 | function() 67 | splits.resize_right(2) 68 | end, 69 | }, 70 | { "=", "=", { desc = "equalize" } }, 71 | 72 | { "s", pcmd("split", "E36") }, 73 | { "", pcmd("split", "E36"), { desc = false } }, 74 | { "v", pcmd("vsplit", "E36") }, 75 | { "", pcmd("vsplit", "E36"), { desc = false } }, 76 | 77 | { "w", "w", { exit = true, desc = false } }, 78 | { "", "w", { exit = true, desc = false } }, 79 | 80 | { "z", cmd "WindowsMaximaze", { exit = true, desc = "maximize" } }, 81 | { "", cmd "WindowsMaximaze", { exit = true, desc = false } }, 82 | 83 | { "o", "o", { exit = true, desc = "remain only" } }, 84 | { "", "o", { exit = true, desc = false } }, 85 | 86 | { "c", pcmd("close", "E444") }, 87 | { "q", pcmd("close", "E444"), { desc = "close window" } }, 88 | { "", pcmd("close", "E444"), { desc = false } }, 89 | { "", pcmd("close", "E444"), { desc = false } }, 90 | 91 | { "", nil, { exit = true, desc = false } }, 92 | }, 93 | } 94 | end 95 | 96 | return M 97 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/nougat/statusline/active.lua: -------------------------------------------------------------------------------- 1 | local core = require "nougat.core" 2 | local Bar = require "nougat.bar" 3 | local Item = require "nougat.item" 4 | local sep = require "nougat.separator" 5 | 6 | local c = require "user.plugins.appearance.nougat.common" 7 | local nut = c.nut 8 | local color = c.color 9 | local stl = Bar "statusline" 10 | 11 | stl:add_item(nut.mode {}) 12 | stl:add_item(nut.buf.filetype { 13 | hl = { bg = color.bg2, fg = "white" }, 14 | prefix = " ", 15 | suffix = " ", 16 | }) 17 | stl:add_item(nut.buf.fileformat { 18 | hl = { bg = color.bg2, fg = "white" }, 19 | sep_left = { 20 | content = c.separators.vertical_bar, 21 | hl = { bg = -1, fg = color.bg4 }, 22 | }, 23 | prefix = " ", 24 | suffix = " ", 25 | }) 26 | stl:add_item(nut.buf.encoding { 27 | hl = { bg = color.bg2, fg = "white" }, 28 | sep_left = { 29 | content = c.separators.vertical_bar, 30 | hl = { bg = -1, fg = color.bg4 }, 31 | }, 32 | sep_right = sep.right_lower_triangle_solid(true), 33 | prefix = " ", 34 | suffix = " ", 35 | }) 36 | stl:add_item(nut.buf.diagnostic_count { 37 | prefix = " ", 38 | suffix = " ", 39 | hl = { bg = color.bg }, 40 | config = { 41 | error = { prefix = " " }, 42 | warn = { prefix = " " }, 43 | info = { prefix = " " }, 44 | hint = { prefix = "󰌶 " }, 45 | }, 46 | -- sep_right = sep.right_lower_triangle_solid(true), 47 | }) 48 | stl:add_item(nut.lsp.servers { 49 | hl = { fg = color.fg }, 50 | prefix = "  ", 51 | config = { 52 | content = function(client) 53 | if client.name ~= "copilot" then 54 | return client.name 55 | end 56 | end, 57 | }, 58 | }) 59 | stl:add_item(nut.buf.fmo { 60 | hl = { fg = color.fg }, 61 | prefix = "  ", 62 | }) 63 | 64 | stl:add_item(nut.buf.copilot { 65 | prefix = " ", 66 | hl = { fg = color.fg }, 67 | }) 68 | 69 | stl:add_item(nut.spacer()) 70 | stl:add_item(nut.truncation_point()) 71 | 72 | stl:add_item(nut.git.status { 73 | hl = { bg = color.bg2 }, 74 | added_hl = { fg = color.green }, 75 | added_prefix = " +", 76 | changed_prefix = " ~", 77 | removed_prefix = " -", 78 | changed_hl = { fg = color.blue }, 79 | removed_hl = { fg = color.red }, 80 | suffix = " ", 81 | sep_left = sep.left_lower_triangle_solid(true), 82 | }) 83 | stl:add_item(nut.git.branch { 84 | hl = { bg = color.green, fg = color.bg2 }, 85 | prefix = "  ", 86 | suffix = " ", 87 | hidden = function(_, ctx) 88 | return ctx.branch == "" 89 | end, 90 | sep_left = sep.left_lower_triangle_solid(true), 91 | }) 92 | 93 | stl:add_item(Item { 94 | hl = { bg = color.bg2, fg = color.blue }, 95 | sep_left = sep.left_lower_triangle_solid(true), 96 | content = core.group { 97 | core.code("l", { min_width = 2 }), 98 | ":", 99 | core.code("c", { min_width = 2 }), 100 | }, 101 | prefix = " ", 102 | suffix = " ", 103 | }) 104 | 105 | return stl 106 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/telescope.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "nvim-telescope/telescope.nvim", 4 | cmd = "Telescope", 5 | dependencies = { 6 | { "nvim-lua/plenary.nvim" }, 7 | { "williamboman/mason.nvim" }, 8 | 9 | { "jvgrootveld/telescope-zoxide" }, 10 | { "tsakirist/telescope-lazy.nvim" }, 11 | { "nvim-telescope/telescope-symbols.nvim" }, 12 | { "lpoto/telescope-docker.nvim" }, 13 | { "debugloop/telescope-undo.nvim" }, 14 | { "nazo6/telescope-tailwind.nvim" }, 15 | { "fdschmidt93/telescope-egrepify.nvim" }, 16 | }, 17 | init = function() 18 | map("n", "", "Telescope find_files", { desc = "[telescope] Find files" }) 19 | map("n", "p", "Telescope egrepify", { desc = "[telescope] Live grep" }) 20 | map("n", "k", "Telescope keymaps", { desc = "[telescope] Keymap" }) 21 | map("n", "z", "Telescope zoxide list", { desc = "[telescope] Zoxide" }) 22 | map("n", "u", "Telescope undo", { desc = "[telescope] Undo" }) 23 | 24 | map("n", "te", "Telescope", { desc = "[telescope] builtin" }) 25 | map("n", "tn", "Telescope fidget2", { desc = "[telescope] Notifications" }) 26 | map("n", "tt", "TodoTelescope", { desc = "[telescope] TODO list" }) 27 | end, 28 | config = function() 29 | local actions = require "telescope.actions" 30 | local open_with_trouble = function(...) 31 | require("trouble.sources.telescope").open(...) 32 | end 33 | require("telescope").setup { 34 | defaults = { 35 | winblend = 15, 36 | mappings = { 37 | i = { 38 | [""] = actions.close, 39 | [""] = open_with_trouble, 40 | }, 41 | n = { 42 | [""] = open_with_trouble, 43 | }, 44 | }, 45 | vimgrep_arguments = { 46 | "rg", 47 | -- Search hidden files but ignore .git dir 48 | "--hidden", 49 | "-g", 50 | "!.git/", 51 | "--color=never", 52 | "--no-heading", 53 | "--with-filename", 54 | "--line-number", 55 | "--column", 56 | "--smart-case", 57 | }, 58 | }, 59 | pickers = { 60 | keymaps = { 61 | show_plug = false, 62 | }, 63 | find_files = { 64 | hidden = true, 65 | }, 66 | }, 67 | extensions = { 68 | zoxide = { 69 | mappings = { 70 | default = { 71 | action = function(selection) 72 | vim.cmd.tcd(selection.path) 73 | end, 74 | }, 75 | }, 76 | }, 77 | }, 78 | } 79 | end, 80 | }, 81 | { 82 | "pwntester/octo.nvim", 83 | cmd = "Octo", 84 | dependencies = { 85 | "nvim-lua/plenary.nvim", 86 | "nvim-telescope/telescope.nvim", 87 | "echasnovski/mini.icons", 88 | }, 89 | config = function() 90 | require("octo").setup() 91 | end, 92 | }, 93 | } 94 | -------------------------------------------------------------------------------- /lua/user/plugins/appearance/kanagawa.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "rebelot/kanagawa.nvim", 3 | lazy = false, 4 | priority = 1000, 5 | config = function() 6 | local kanagawa = require "kanagawa" 7 | kanagawa.setup { 8 | commentStyle = { italic = true }, 9 | keywordStyle = { italic = true }, 10 | statementStyle = { bold = true }, 11 | variablebuiltinStyle = { italic = true }, 12 | undercurl = true, 13 | specialReturn = true, 14 | specialException = true, 15 | transparent = false, 16 | theme = "wave", 17 | compile = true, 18 | } 19 | 20 | local colors = require("kanagawa.colors").setup { theme = "wave" } 21 | local theme = colors.theme 22 | local palette = colors.palette 23 | _G.color_palette = palette 24 | 25 | local overrides = { 26 | Visual = { bg = "#2b4960" }, 27 | 28 | DiffAdd = { bg = palette.autumnGreen }, 29 | 30 | DiagnosticVirtualTextError = { link = "DiagnosticError" }, 31 | DiagnosticVirtualTextWarn = { link = "DiagnosticWarn" }, 32 | DiagnosticVirtualTextInfo = { link = "DiagnosticInfo" }, 33 | DiagnosticVirtualTextHint = { link = "DiagnosticHint" }, 34 | 35 | DiagnosticSignInfo = { fg = palette.dragonBlue }, 36 | DiagnosticSignWarn = { fg = palette.roninYellow }, 37 | 38 | NeoTreeNormal = { fg = palette.fujiWhite, bg = palette.sumiInk2 }, 39 | NeoTreeNormalNC = { fg = palette.fujiWhite, bg = palette.sumiInk2 }, 40 | NeoTreeCursorLine = { bg = palette.sumiInk4 }, 41 | 42 | ScrollView = { bg = "#342e4f" }, 43 | 44 | IlluminatedWordText = { fg = "NONE", bg = "#472739" }, 45 | IlluminatedWordRead = { fg = "NONE", bg = "#472739" }, 46 | IlluminatedWordWrite = { fg = "NONE", bg = "#472739" }, 47 | 48 | DiffChange = { bg = palette.waveBlue2 }, 49 | 50 | GitSignsAddNr = { link = "DiffAdd" }, 51 | GitSignsChangeNr = { link = "DiffChange" }, 52 | GitSignsDeleteNr = { link = "DiffDelete" }, 53 | 54 | NeoTreeGitModified = { fg = palette.autumnYellow, bg = "NONE" }, 55 | Folded = { bg = "#342e4f" }, 56 | 57 | FidgetTitle = { fg = palette.fujiWhite }, 58 | FidgetTask = { fg = palette.oldWhite }, 59 | 60 | PackageInfoOutdatedVersion = { link = "DiagnosticWarn" }, 61 | PackageInfoUpToDateVersion = { link = "DiagnosticInfo" }, 62 | 63 | IblIndent = { fg = theme.ui.whitespace }, 64 | IblWhitespace = { fg = theme.ui.whitespace }, 65 | IblScope = { fg = theme.ui.special }, 66 | NvimTreeWindowPicker = { bg = palette.autumnRed }, 67 | } 68 | vim.api.nvim_create_autocmd("ColorScheme", { 69 | pattern = "*", 70 | callback = function() 71 | for group, styles in pairs(overrides) do 72 | vim.api.nvim_set_hl(0, group, styles) 73 | end 74 | end, 75 | }) 76 | 77 | vim.api.nvim_create_autocmd({ "BufWritePost" }, { 78 | pattern = "*/nvim/lua/user/plugins/appearance/kanagawa.lua", 79 | group = vim.api.nvim_create_augroup("kanagawa_compile", { clear = true }), 80 | callback = function() 81 | vim.cmd "KanagawaCompile" 82 | end, 83 | }) 84 | 85 | vim.cmd "colorscheme kanagawa" 86 | end, 87 | } 88 | -------------------------------------------------------------------------------- /lua/user/plugins/language/init.lua: -------------------------------------------------------------------------------- 1 | return Args.feature.vscode and {} 2 | or { 3 | { "teal-language/vim-teal", ft = { "teal" } }, 4 | { 5 | "hat0uma/csvview.nvim", 6 | ft = { "csv", "tsv" }, 7 | config = function() 8 | vim.api.nvim_create_autocmd("BufRead", { 9 | group = vim.api.nvim_create_augroup("csvview", {}), 10 | pattern = "*.csv,*.tsv", 11 | callback = function() 12 | require("csvview").enable() 13 | end, 14 | }) 15 | 16 | require("csvview").setup() 17 | end, 18 | }, 19 | { "dag/vim-fish", ft = { "fish" } }, 20 | { "kevinoid/vim-jsonc", ft = { "json" } }, 21 | { 22 | "ionide/Ionide-vim", 23 | 24 | init = function() 25 | vim.g["fsharp#lsp_auto_setup"] = 0 26 | end, 27 | }, 28 | 29 | { "vxpm/ferris.nvim", ft = "rust", opts = {} }, 30 | { 31 | "Saecki/crates.nvim", 32 | event = { "BufReadPre Cargo.toml" }, 33 | dependencies = { { "nvim-lua/plenary.nvim" } }, 34 | config = function() 35 | require("crates").setup { 36 | lsp = { 37 | enabled = true, 38 | actions = true, 39 | completion = true, 40 | hover = true, 41 | }, 42 | } 43 | end, 44 | }, 45 | { 46 | "vuki656/package-info.nvim", 47 | event = { "BufRead package.json" }, 48 | dependencies = { { "MunifTanjim/nui.nvim" } }, 49 | config = function() 50 | require("package-info").setup { 51 | icons = { 52 | enable = true, 53 | style = { 54 | up_to_date = "  ", 55 | outdated = "  ", 56 | }, 57 | }, 58 | } 59 | end, 60 | }, 61 | 62 | { 63 | "rest-nvim/rest.nvim", 64 | ft = { "http" }, 65 | cmd = { "Rest" }, 66 | dependencies = { { "nvim-treesitter/nvim-treesitter" } }, 67 | enabled = Args.feature.rest, 68 | }, 69 | 70 | { 71 | "f3fora/nvim-texlabconfig", 72 | config = function() 73 | require("texlabconfig").setup() 74 | end, 75 | ft = { "tex", "bib" }, 76 | cmd = { "TexlabInverseSearch" }, 77 | }, 78 | 79 | { 80 | "nanotee/sqls.nvim", 81 | ft = { "sql" }, 82 | }, 83 | 84 | { "yioneko/nvim-vtsls" }, 85 | { 86 | "dmmulroy/tsc.nvim", 87 | cmd = "TSC", 88 | opts = {}, 89 | }, 90 | 91 | { 92 | "ellisonleao/glow.nvim", 93 | ft = { "markdown" }, 94 | cmd = { "Glow" }, 95 | config = function() 96 | require("glow").setup { 97 | border = "single", 98 | } 99 | end, 100 | }, 101 | 102 | { "Hoffs/omnisharp-extended-lsp.nvim" }, 103 | 104 | { 105 | "chomosuke/typst-preview.nvim", 106 | ft = "typst", 107 | version = "1.*", 108 | build = function() 109 | require("typst-preview").update() 110 | end, 111 | opts = { 112 | get_root = function(fname) 113 | return require("user.shared.utils.typst").get_typst_root_dir(fname) 114 | end, 115 | get_main_file = function(path) 116 | return require("user.shared.utils.typst").get_typst_main_file(path) 117 | end, 118 | }, 119 | }, 120 | 121 | { 122 | "folke/lazydev.nvim", 123 | ft = "lua", 124 | dependencies = { 125 | { "gonstoll/wezterm-types", lazy = true }, 126 | }, 127 | opts = { 128 | library = { 129 | { path = "${3rd}/luv/library", words = { "vim%.uv" } }, 130 | { path = "snacks.nvim", words = { "Snacks" } }, 131 | { path = "wezterm-types", mods = { "wezterm" } }, 132 | }, 133 | }, 134 | }, 135 | } 136 | -------------------------------------------------------------------------------- /lua/user/plugins/edit/insx.lua: -------------------------------------------------------------------------------- 1 | local my_utils = { 2 | ---@param filetypes string[] 3 | ---@return insx.Override 4 | no_filetype = function(filetypes) 5 | return { 6 | ---@param enabled insx.Enabled 7 | ---@param ctx insx.Context 8 | enabled = function(enabled, ctx) 9 | return not (vim.tbl_contains(filetypes, ctx.filetype)) and enabled(ctx) 10 | end, 11 | } 12 | end, 13 | } 14 | 15 | return { 16 | "hrsh7th/nvim-insx", 17 | event = { "InsertEnter" }, 18 | config = function() 19 | local insx = require "insx" 20 | local esc = require("insx.helper.regex").esc 21 | 22 | local jump_next = require "insx.recipe.jump_next" 23 | local auto_pair = require "insx.recipe.auto_pair" 24 | local delete_pair = require "insx.recipe.delete_pair" 25 | local pair_spacing = require "insx.recipe.pair_spacing" 26 | local fast_wrap = require "insx.recipe.fast_wrap" 27 | local fast_break = require "insx.recipe.fast_break" 28 | 29 | -- quotes 30 | for _, quote in ipairs { 31 | { '"', {} }, 32 | { "'", { my_utils.no_filetype { "rust", "systemverilog" } } }, 33 | { "`", { my_utils.no_filetype { "markdown" } } }, 34 | { "$", { insx.with.filetype { "tex", "typst" } } }, 35 | } do 36 | -- jump_out 37 | insx.add( 38 | quote[1], 39 | jump_next { 40 | jump_pat = { 41 | [[\\\@", insx.with(delete_pair.strings { open_pat = esc(quote[1]), close_pat = esc(quote[1]) }, quote[2])) 48 | insx.add( 49 | "", 50 | insx.with(delete_pair.strings { open_pat = esc(quote[1]), close_pat = esc(quote[1]) }, quote[2]) 51 | ) 52 | 53 | insx.add("", insx.with(fast_wrap { close = quote[1] }, quote[2])) 54 | end 55 | 56 | -- pairs 57 | for open, close in pairs { 58 | ["("] = ")", 59 | ["["] = "]", 60 | ["{"] = "}", 61 | } do 62 | -- jump_out 63 | insx.add( 64 | close, 65 | jump_next { 66 | jump_pat = { 67 | [[\%#]] .. esc(close) .. [[\zs]], 68 | }, 69 | } 70 | ) 71 | insx.add(open, auto_pair.strings { open = open, close = close }) 72 | insx.add("", delete_pair { open_pat = esc(open), close_pat = esc(close) }) 73 | insx.add("", delete_pair { open_pat = esc(open), close_pat = esc(close) }) 74 | 75 | insx.add("", pair_spacing.increase { open_pat = esc(open), close_pat = esc(close) }) 76 | insx.add("", pair_spacing.decrease { open_pat = esc(open), close_pat = esc(close) }) 77 | insx.add("", pair_spacing.decrease { open_pat = esc(open), close_pat = esc(close) }) 78 | 79 | insx.add("", fast_break { open_pat = esc(open), close_pat = esc(close) }) 80 | insx.add("", fast_wrap { close = close }) 81 | end 82 | 83 | insx.add("", { 84 | ---@param ctx insx.Context 85 | action = function(ctx) 86 | local row, col = ctx.row(), ctx.col() 87 | if require("luasnip").expand_or_locally_jumpable() then 88 | ctx.send "luasnip-expand-or-jump" 89 | else 90 | if vim.iter({ [["]], "'", "]", "}", ")", "`", "$" }):find(ctx.after():sub(1, 1)) ~= nil then 91 | ctx.move(row, col + 1) 92 | else 93 | ctx.send "" 94 | end 95 | end 96 | end, 97 | }) 98 | 99 | -- tags. 100 | -- insx.add( 101 | -- "", 102 | -- require "insx.recipe.fast_break" { 103 | -- open_pat = insx.helper.search.Tag.Open, 104 | -- close_pat = insx.helper.search.Tag.Close, 105 | -- } 106 | -- ) 107 | end, 108 | } 109 | -------------------------------------------------------------------------------- /lua/user/plugins/external/fmo.lua: -------------------------------------------------------------------------------- 1 | return Args.feature.vscode and {} 2 | or { 3 | { 4 | "nazo6/format-order.nvim", 5 | event = { "BufRead" }, 6 | dependencies = { 7 | { 8 | "stevearc/conform.nvim", 9 | dependencies = { "williamboman/mason.nvim" }, 10 | config = function() 11 | require("conform").setup { 12 | formatters = { 13 | dioxus_fmt = { 14 | command = "dx", 15 | args = { "fmt", "-f", "$FILENAME" }, 16 | stdin = false, 17 | cwd = require("conform.util").root_file { "Dioxus.toml" }, 18 | require_cwd = true, 19 | condition = require("conform.util").root_file { "Dioxus.toml" }, 20 | }, 21 | deno_fmt = { 22 | stdin = false, 23 | args = { "fmt", "$FILENAME" }, 24 | }, 25 | }, 26 | } 27 | end, 28 | }, 29 | }, 30 | config = function() 31 | ---@type table 32 | local f = { 33 | prettierd = { 34 | type = "conform", 35 | name = "prettierd", 36 | root_pattern = { 37 | ".prettierrc", 38 | ".prettierrc.json", 39 | ".prettierrc.yml", 40 | ".prettierrc.yaml", 41 | ".prettierrc.json5", 42 | ".prettierrc.js", 43 | ".prettierrc.cjs", 44 | ".prettierrc.mjs", 45 | ".prettierrc.toml", 46 | "prettier.config.js", 47 | "prettier.config.cjs", 48 | }, 49 | }, 50 | deno_fmt = { type = "conform", name = "deno_fmt", root_pattern = { "deno.json", "deno.jsonc" } }, 51 | deno_fmt_mdx = { type = "conform", name = "deno_fmt_mdx", root_pattern = { "deno.json", "deno.jsonc" } }, 52 | biome = { type = "conform", name = "biome", root_pattern = { "biome.json", "biome.jsonc" } }, 53 | biome_check = { type = "conform", name = "biome-check", root_pattern = { "biome.json", "biome.jsonc" } }, 54 | stylua = { type = "conform", name = "stylua", root_pattern = { "stylua.toml" } }, 55 | rust_analyzer = { type = "lsp", name = "rust_analyzer" }, 56 | mdx_analyzer = { type = "lsp", name = "rust_analyzer" }, 57 | dioxus_fmt = { type = "conform", name = "dioxus_fmt", root_pattern = { "Dioxus.toml" } }, 58 | ruff = { type = "conform", name = "ruff_format", root_pattern = { "pyproject.toml" } }, 59 | } 60 | 61 | ---@type fmo.FormatterGroup[] 62 | local common_web = { 63 | { f.biome_check }, 64 | { 65 | { type = "lsp", name = "denols" }, 66 | { 67 | f.prettierd, 68 | f.deno_fmt, 69 | }, 70 | f.biome, 71 | }, 72 | } 73 | local web_default = { f.biome, f.biome_check } 74 | 75 | require("fmo").setup { 76 | fallback_lsp = { 77 | no_formatter = true, 78 | }, 79 | filetypes = { 80 | html = { default = web_default, unpack(common_web) }, 81 | css = { default = web_default, unpack(common_web) }, 82 | javascript = { default = web_default, unpack(common_web) }, 83 | javascriptreact = { default = web_default, unpack(common_web) }, 84 | typescript = { default = web_default, unpack(common_web) }, 85 | typescriptreact = { default = web_default, unpack(common_web) }, 86 | json = { default = web_default, unpack(common_web) }, 87 | jsonc = { default = web_default, unpack(common_web) }, 88 | markdown = { default = f.prettierd, unpack(common_web) }, 89 | mdx = { default = f.prettierd, unpack(common_web) }, 90 | lua = { default = f.stylua }, 91 | python = { default = f.ruff }, 92 | rust = { 93 | { f.dioxus_fmt }, 94 | { f.rust_analyzer }, 95 | }, 96 | svelte = { default = web_default, unpack(common_web) }, 97 | nu = { default = { f.topiary_nu } }, 98 | }, 99 | } 100 | 101 | local auto_fmt = true 102 | 103 | vim.api.nvim_create_user_command("AutoFmtDisable", function(opts) 104 | auto_fmt = false 105 | end, {}) 106 | 107 | vim.api.nvim_create_user_command("AutoFmtEnable", function(opts) 108 | auto_fmt = true 109 | end, {}) 110 | 111 | vim.api.nvim_create_autocmd({ "BufWritePre" }, { 112 | callback = function() 113 | if auto_fmt then 114 | require("fmo").format() 115 | end 116 | end, 117 | }) 118 | end, 119 | }, 120 | } 121 | -------------------------------------------------------------------------------- /lua/user/config/options.lua: -------------------------------------------------------------------------------- 1 | local opt = vim.opt 2 | 3 | -- Behavior 4 | opt.shortmess:append "I" 5 | 6 | opt.mouse = "a" 7 | opt.mousemodel = "popup" 8 | vim.cmd.aunmenu { "PopUp.How-to\\ disable\\ mouse" } 9 | vim.cmd.aunmenu { "PopUp.-1-" } 10 | 11 | opt.clipboard:append "unnamedplus" 12 | if Args.feature.osc52 then 13 | local function paste() 14 | return { 15 | vim.split(vim.fn.getreg "", "\n"), 16 | vim.fn.getregtype "", 17 | } 18 | end 19 | 20 | vim.g.clipboard = { 21 | name = "osc52", 22 | copy = { 23 | ["+"] = require("vim.ui.clipboard.osc52").copy "+", 24 | ["*"] = require("vim.ui.clipboard.osc52").copy "*", 25 | }, 26 | paste = { 27 | ["+"] = paste, 28 | ["*"] = paste, 29 | }, 30 | } 31 | else 32 | if vim.fn.has "win32" == 1 then 33 | vim.g.clipboard = { 34 | copy = { 35 | ["+"] = "win32yank.exe -i --crlf", 36 | ["*"] = "win32yank.exe -i --crlf", 37 | }, 38 | paste = { 39 | ["+"] = "win32yank.exe -o --lf", 40 | ["*"] = "win32yank.exe -o --lf", 41 | }, 42 | } 43 | end 44 | end 45 | 46 | opt.undofile = true 47 | 48 | opt.confirm = true 49 | opt.autoread = true 50 | opt.fileformat = "unix" 51 | opt.fileformats = "unix,dos" 52 | 53 | opt.smartcase = true 54 | opt.ignorecase = true 55 | opt.inccommand = "split" 56 | 57 | opt.numberwidth = 3 58 | 59 | opt.foldcolumn = "1" 60 | opt.foldlevel = 99 61 | opt.foldlevelstart = 99 62 | opt.foldenable = true 63 | opt.fillchars = { 64 | eob = " ", 65 | fold = " ", 66 | foldopen = "", 67 | foldsep = " ", 68 | foldclose = ">", 69 | } 70 | 71 | opt.updatetime = 300 72 | 73 | opt.exrc = true 74 | 75 | vim.cmd [[autocmd BufWinEnter * if &filetype == 'help' | wincmd L | endif]] 76 | 77 | if require("user.shared.utils.system").is_msys2 then 78 | vim.opt.shellcmdflag = "-c" 79 | vim.opt.shellxquote = "" 80 | vim.opt.shellquote = "" 81 | end 82 | 83 | -- Key 84 | opt.timeoutlen = 400 85 | 86 | -- Editing 87 | opt.tabstop = 2 88 | opt.shiftwidth = 2 89 | opt.expandtab = true 90 | 91 | -- Appearance 92 | if vim.fn.has "termguicolors" == 1 then 93 | opt.termguicolors = true 94 | end 95 | 96 | opt.laststatus = 3 97 | 98 | opt.title = true 99 | local wsl_prefix = vim.fn.has "wsl" == 1 and " [wsl]" or "" 100 | opt.titlestring = "%{getcwd()}" .. " - NVIM" .. wsl_prefix 101 | 102 | opt.number = true 103 | opt.signcolumn = "yes" 104 | opt.cursorline = true 105 | opt.sidescrolloff = 16 106 | opt.list = true 107 | 108 | opt.winblend = 15 109 | opt.pumblend = 15 110 | 111 | vim.diagnostic.config { 112 | virtual_text = true, 113 | virtual_lines = false, 114 | severity_sort = true, 115 | signs = { 116 | text = { 117 | [vim.diagnostic.severity.ERROR] = " ", 118 | [vim.diagnostic.severity.WARN] = " ", 119 | [vim.diagnostic.severity.INFO] = " ", 120 | [vim.diagnostic.severity.HINT] = " ", 121 | }, 122 | }, 123 | } 124 | 125 | -- Prevent closing terminal in insert mode if exited 126 | vim.api.nvim_create_autocmd("TermClose", { 127 | callback = function(ctx) 128 | vim.cmd "stopinsert" 129 | vim.api.nvim_create_autocmd("TermEnter", { 130 | callback = function() 131 | vim.cmd "stopinsert" 132 | end, 133 | buffer = ctx.buf, 134 | }) 135 | end, 136 | nested = true, 137 | }) 138 | 139 | vim.g.markdown_fenced_languages = { 140 | "ts=typescript", 141 | } 142 | 143 | vim.api.nvim_create_user_command("LspLogClear", function() 144 | local log_path = vim.fs.joinpath(vim.fn.stdpath "state", "lsp.log") 145 | vim.fn.delete(log_path) 146 | end, {}) 147 | 148 | vim.api.nvim_create_autocmd("VimEnter", { 149 | nested = true, 150 | once = true, 151 | callback = function() 152 | if vim.g.NVIM_RESTARTING then 153 | vim.g.NVIM_RESTARTING = false 154 | vim.schedule(function() 155 | local session = require "possession.session" 156 | local ok = pcall(session.load, "restart") 157 | if ok then 158 | require("possession.session").delete("restart", { no_confirm = true }) 159 | end 160 | end) 161 | end 162 | end, 163 | }) 164 | 165 | if vim.fn.has "nvim-0.12" == 1 then 166 | vim.api.nvim_create_user_command("Restart", function() 167 | require("possession.session").save("restart", { no_confirm = true }) 168 | vim.cmd [[silent! bufdo bwipeout]] 169 | 170 | vim.g.NVIM_RESTARTING = true 171 | 172 | vim.cmd [[restart]] 173 | end, {}) 174 | else 175 | vim.api.nvim_create_user_command("Restart", function() 176 | if vim.fn.has "gui_running" then 177 | vim.notify("GUI is not supported", vim.log.levels.WARN) 178 | end 179 | 180 | require("possession.session").save("restart", { no_confirm = true }) 181 | vim.cmd [[silent! bufdo bwipeout]] 182 | 183 | vim.g.NVIM_RESTARTING = true 184 | 185 | vim.cmd [[qa!]] 186 | end, {}) 187 | end 188 | -------------------------------------------------------------------------------- /lua/user/plugins/edit/cmp.lua: -------------------------------------------------------------------------------- 1 | local sources_default = { "lazydev", "lsp", "path", "snippets", "buffer" } 2 | if Args.feature.ai.copilot then 3 | table.insert(sources_default, "copilot") 4 | end 5 | 6 | local source_priority = { 7 | copilot = 6, 8 | lazydev = 5, 9 | lsp = 4, 10 | path = 3, 11 | snippets = 2, 12 | buffer = 1, 13 | } 14 | 15 | ---@type table 16 | local sources_providers = { 17 | lazydev = { 18 | name = "LazyDev", 19 | module = "lazydev.integrations.blink", 20 | }, 21 | lsp = { 22 | fallbacks = {}, 23 | async = true, 24 | }, 25 | } 26 | if Args.feature.ai.copilot == true then 27 | sources_providers.copilot = { 28 | name = "copilot", 29 | module = "blink-copilot", 30 | score_offset = 1, 31 | async = true, 32 | transform_items = function(_, items) 33 | for _, item in ipairs(items) do 34 | item.copilot = true 35 | end 36 | return items 37 | end, 38 | } 39 | end 40 | 41 | return { 42 | { 43 | "saghen/blink.cmp", 44 | dependencies = { "fang2hou/blink-copilot", enabled = (Args.feature.ai.copilot == true) }, 45 | event = { "InsertEnter", "CmdlineEnter" }, 46 | version = "v1.*", 47 | enabled = not Args.feature.vscode, 48 | 49 | config = function() 50 | -- HACK: I found that and mapping is not working after pressing when there is no completion candidates (Maybe related to https://github.com/neovim/neovim/issues/9905). 51 | -- By manually mapping them to blink.cmp functions, it works. 52 | map("i", "", function() 53 | require("blink.cmp").select_next() 54 | end) 55 | map("i", "", function() 56 | require("blink.cmp").select_prev() 57 | end) 58 | 59 | require("blink.cmp").setup { 60 | keymap = { 61 | preset = "none", 62 | [""] = { "select_prev" }, 63 | [""] = { "select_next" }, 64 | [""] = { "accept", "fallback" }, 65 | [""] = { "scroll_documentation_down", "fallback" }, 66 | [""] = { "scroll_documentation_up", "fallback" }, 67 | }, 68 | fuzzy = { 69 | implementation = "lua", 70 | sorts = { 71 | function(a, b) 72 | local a_priority = source_priority[a.source_id] 73 | if not a_priority then 74 | a_priority = 0 75 | end 76 | local b_priority = source_priority[b.source_id] 77 | if not b_priority then 78 | b_priority = 0 79 | end 80 | if a_priority ~= b_priority then 81 | return a_priority > b_priority 82 | end 83 | end, 84 | "score", 85 | "sort_text", 86 | }, 87 | }, 88 | appearance = { 89 | use_nvim_cmp_as_default = true, 90 | nerd_font_variant = "mono", 91 | }, 92 | completion = { 93 | list = { 94 | selection = { 95 | auto_insert = true, 96 | preselect = false, 97 | }, 98 | }, 99 | menu = { 100 | draw = { 101 | columns = { { "kind_icon" }, { "label", "label_description", gap = 1 }, { "source_name" } }, 102 | components = { 103 | kind_icon = { 104 | text = function(ctx) 105 | local icon = ctx.kind_icon 106 | if ctx.item.copilot then 107 | icon = " " 108 | end 109 | return icon .. ctx.icon_gap 110 | end, 111 | }, 112 | source_name = { 113 | text = function(ctx) 114 | if ctx.source_name == "LSP" then 115 | return "[" .. vim.lsp.get_client_by_id(ctx.item.client_id).name .. "]" 116 | else 117 | return ctx.source_name 118 | end 119 | end, 120 | }, 121 | }, 122 | }, 123 | }, 124 | documentation = { 125 | auto_show = true, 126 | auto_show_delay_ms = 50, 127 | window = { 128 | border = "rounded", 129 | }, 130 | }, 131 | }, 132 | sources = { 133 | default = sources_default, 134 | providers = sources_providers, 135 | }, 136 | snippets = { 137 | preset = "luasnip", 138 | }, 139 | signature = { enabled = true }, 140 | 141 | cmdline = { 142 | keymap = { 143 | [""] = { "select_prev", "fallback" }, 144 | [""] = { "select_next", "fallback" }, 145 | [""] = { "select_prev", "fallback" }, 146 | [""] = { "select_next", "fallback" }, 147 | }, 148 | completion = { 149 | list = { 150 | selection = { 151 | auto_insert = true, 152 | preselect = false, 153 | }, 154 | }, 155 | menu = { 156 | auto_show = true, 157 | draw = { 158 | columns = { { "kind_icon" }, { "label", "label_description", gap = 1 } }, 159 | }, 160 | }, 161 | }, 162 | }, 163 | } 164 | end, 165 | }, 166 | } 167 | -------------------------------------------------------------------------------- /lua/user/plugins/tools/nvim-tree.lua: -------------------------------------------------------------------------------- 1 | local function on_attach(bufnr) 2 | local api = require "nvim-tree.api" 3 | 4 | local function opts(desc) 5 | return { 6 | desc = "nvim-tree: " .. desc, 7 | buffer = bufnr, 8 | noremap = true, 9 | silent = true, 10 | nowait = true, 11 | } 12 | end 13 | 14 | map("n", "", api.tree.change_root_to_node, opts "CD") 15 | map("n", "", api.node.open.replace_tree_buffer, opts "Open: In Place") 16 | map("n", "", api.node.show_info_popup, opts "Info") 17 | map("n", "", api.fs.rename_sub, opts "Rename: Omit Filename") 18 | -- map("n", "", api.node.open.tab, opts "Open: New Tab") 19 | map("n", "", api.node.open.vertical, opts "Open: Vertical Split") 20 | map("n", "", api.node.open.horizontal, opts "Open: Horizontal Split") 21 | map("n", "h", api.node.navigate.parent_close, opts "Close Directory") 22 | map("n", "l", api.node.open.edit, opts "Open") 23 | map("n", "", api.node.open.preview, opts "Open Preview") 24 | map("n", ">", api.node.navigate.sibling.next, opts "Next Sibling") 25 | map("n", "<", api.node.navigate.sibling.prev, opts "Previous Sibling") 26 | map("n", ".", api.node.run.cmd, opts "Run Command") 27 | map("n", "-", api.tree.change_root_to_parent, opts "Up") 28 | map("n", "a", api.fs.create, opts "Create") 29 | map("n", "bmv", api.marks.bulk.move, opts "Move Bookmarked") 30 | map("n", "B", api.tree.toggle_no_buffer_filter, opts "Toggle No Buffer") 31 | map("n", "c", api.fs.copy.node, opts "Copy") 32 | map("n", "C", api.tree.toggle_git_clean_filter, opts "Toggle Git Clean") 33 | map("n", "[c", api.node.navigate.git.prev, opts "Prev Git") 34 | map("n", "]c", api.node.navigate.git.next, opts "Next Git") 35 | map("n", "d", api.fs.remove, opts "Delete") 36 | map("n", "D", api.fs.trash, opts "Trash") 37 | map("n", "e", api.fs.rename_basename, opts "Rename: Basename") 38 | map("n", "]e", api.node.navigate.diagnostics.next, opts "Next Diagnostic") 39 | map("n", "[e", api.node.navigate.diagnostics.prev, opts "Prev Diagnostic") 40 | map("n", "F", api.live_filter.clear, opts "Clean Filter") 41 | map("n", "f", api.live_filter.start, opts "Filter") 42 | map("n", "?", api.tree.toggle_help, opts "Help") 43 | map("n", "gy", api.fs.copy.absolute_path, opts "Copy Absolute Path") 44 | map("n", "H", api.tree.toggle_hidden_filter, opts "Toggle Dotfiles") 45 | map("n", "I", api.tree.toggle_gitignore_filter, opts "Toggle Git Ignore") 46 | map("n", "J", api.node.navigate.sibling.last, opts "Last Sibling") 47 | map("n", "K", api.node.navigate.sibling.first, opts "First Sibling") 48 | map("n", "m", api.marks.toggle, opts "Toggle Bookmark") 49 | map("n", "o", api.node.open.edit, opts "Open") 50 | map("n", "O", api.node.open.no_window_picker, opts "Open: No Window Picker") 51 | map("n", "p", api.fs.paste, opts "Paste") 52 | map("n", "P", api.node.navigate.parent, opts "Parent Directory") 53 | map("n", "q", api.tree.close, opts "Close") 54 | map("n", "", api.tree.close, opts "Close") 55 | map("n", "r", api.fs.rename, opts "Rename") 56 | map("n", "R", api.tree.reload, opts "Refresh") 57 | map("n", "U", api.tree.toggle_custom_filter, opts "Toggle Hidden") 58 | map("n", "W", api.tree.collapse_all, opts "Collapse") 59 | map("n", "x", api.fs.cut, opts "Cut") 60 | map("n", "y", api.fs.copy.filename, opts "Copy Name") 61 | map("n", "Y", api.fs.copy.relative_path, opts "Copy Relative Path") 62 | map("n", "<2-LeftMouse>", api.node.open.edit, opts "Open") 63 | map("n", "<2-RightMouse>", api.tree.change_root_to_node, opts "CD") 64 | 65 | map("n", "s", "", opts "Nop") 66 | map("n", "v", "", opts "Nop") 67 | map("n", "", "", opts "Nop") 68 | map("n", "", "", opts "Nop") 69 | 70 | map("n", "f", api.node.run.system, opts "System open") 71 | end 72 | 73 | return { 74 | "kyazdani42/nvim-tree.lua", 75 | dependencies = { "echasnovski/mini.icons" }, 76 | cmd = { "NvimTreeToggle" }, 77 | init = function() 78 | map("n", "", "NvimTreeToggle", { silent = true }) 79 | end, 80 | config = function() 81 | require("nvim-tree").setup { 82 | disable_netrw = true, 83 | hijack_netrw = true, 84 | hijack_cursor = true, 85 | sync_root_with_cwd = true, 86 | system_open = { 87 | cmd = nil, 88 | args = {}, 89 | }, 90 | git = { 91 | timeout = 1000, 92 | }, 93 | filters = { 94 | git_ignored = false, 95 | }, 96 | filesystem_watchers = { 97 | ignore_dirs = { 98 | ".ccls-cache", 99 | "build", 100 | "node_modules", 101 | "target", 102 | }, 103 | }, 104 | diagnostics = { 105 | enable = true, 106 | show_on_dirs = true, 107 | show_on_open_dirs = false, 108 | icons = { 109 | hint = "", 110 | info = "", 111 | warning = "", 112 | error = "", 113 | }, 114 | }, 115 | on_attach = on_attach, 116 | renderer = { 117 | highlight_git = true, 118 | icons = { 119 | show = { 120 | file = true, 121 | folder = true, 122 | folder_arrow = false, 123 | git = false, 124 | }, 125 | }, 126 | indent_markers = { 127 | enable = true, 128 | }, 129 | }, 130 | update_focused_file = { 131 | enable = true, 132 | update_root = false, 133 | ignore_list = {}, 134 | }, 135 | actions = { 136 | change_dir = { 137 | enable = true, 138 | global = true, 139 | restrict_above_cwd = false, 140 | }, 141 | open_file = { 142 | window_picker = { 143 | enable = true, 144 | chars = "FJDKSLA;CMRUEIWOQP", 145 | }, 146 | quit_on_open = true, 147 | }, 148 | }, 149 | } 150 | end, 151 | } 152 | -------------------------------------------------------------------------------- /lua/telescope/_extensions/fidget2.lua: -------------------------------------------------------------------------------- 1 | local actions = require("telescope.actions") 2 | local action_state = require("telescope.actions.state") 3 | local conf = require("telescope.config").values 4 | local entry_display = require("telescope.pickers.entry_display") 5 | local finders = require("telescope.finders") 6 | local notification = require("fidget.notification") 7 | local pickers = require("telescope.pickers") 8 | local telescope = require("telescope") 9 | local previewers = require("telescope.previewers") 10 | 11 | --- Format HistoryItem, used in Telescope or Neovim messages. 12 | --- 13 | ---@param entry HistoryItem 14 | ---@return table 15 | local format_entry = function(entry) 16 | local chunks = {} 17 | 18 | table.insert(chunks, { vim.fn.strftime("%c", entry.last_updated), "Comment" }) 19 | 20 | if entry.group_name and #entry.group_name > 0 then 21 | table.insert(chunks, { entry.group_name, "Special" }) 22 | else 23 | table.insert(chunks, { " ", "MsgArea" }) 24 | end 25 | 26 | table.insert(chunks, { " | ", "Comment" }) 27 | 28 | if entry.annote and #entry.annote > 0 then 29 | table.insert(chunks, { entry.annote, entry.style }) 30 | else 31 | table.insert(chunks, { " ", "MsgArea" }) 32 | end 33 | 34 | table.insert(chunks, { entry.message:match "([^\n]*)", "MsgArea" }) 35 | 36 | return chunks 37 | end 38 | 39 | local notification_previewer = function() 40 | return previewers.new_buffer_previewer({ 41 | title = "Notification Details", 42 | define_preview = function(self, entry, _) 43 | local notification_entry = entry.value 44 | local bufnr = self.state.bufnr 45 | 46 | vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {}) 47 | 48 | local lines = { 49 | "Timestamp: " .. vim.fn.strftime("%c", notification_entry.last_updated), 50 | "Group: " .. (notification_entry.group_name or ""), 51 | "Annotation: " .. (notification_entry.annote or ""), 52 | "Style: " .. (notification_entry.style or ""), 53 | "", 54 | "Message:", 55 | "--------", 56 | "", 57 | } 58 | 59 | local message_lines = vim.split(notification_entry.message, "\n") 60 | for _, line in ipairs(message_lines) do 61 | table.insert(lines, line) 62 | end 63 | 64 | vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) 65 | 66 | vim.api.nvim_buf_set_option(bufnr, "filetype", "markdown") 67 | 68 | local ns_id = vim.api.nvim_create_namespace("fidget_preview") 69 | 70 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, "Title", 0, 0, 10) 71 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, "Title", 1, 0, 6) 72 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, "Title", 2, 0, 11) 73 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, "Title", 3, 0, 6) 74 | 75 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, "Identifier", 0, 11, -1) 76 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, "Special", 1, 7, -1) 77 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, "String", 2, 12, -1) 78 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, "Comment", 3, 7, -1) 79 | 80 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, "Title", 5, 0, -1) 81 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, "Comment", 6, 0, -1) 82 | 83 | if notification_entry.style then 84 | local hl_group = notification_entry.style 85 | for i = 8, #lines do 86 | vim.api.nvim_buf_add_highlight(bufnr, ns_id, hl_group, i - 1, 0, -1) 87 | end 88 | end 89 | end, 90 | }) 91 | end 92 | 93 | local create_entry_maker = function(wrap) 94 | return function(entry) 95 | return { 96 | value = entry, 97 | display = function() 98 | local display_content = format_entry(entry) 99 | 100 | if wrap then 101 | local win_width = vim.api.nvim_win_get_width(0) - 10 102 | local msg = entry.message 103 | 104 | if #msg > win_width then 105 | msg = msg:sub(1, win_width - 3) .. "..." 106 | end 107 | 108 | display_content[#display_content] = { msg, "MsgArea" } 109 | end 110 | 111 | return entry_display.create({ 112 | separator = " ", 113 | items = { 114 | {}, 115 | {}, 116 | {}, 117 | { width = 2 }, 118 | { remaining = true }, 119 | }, 120 | })(display_content) 121 | end, 122 | ordinal = entry.message, 123 | } 124 | end 125 | end 126 | 127 | local fidget_picker = function(opts) 128 | opts = opts or {} 129 | 130 | local default_config = { 131 | wrap_text = false, 132 | use_previewer = true, 133 | } 134 | 135 | local config = vim.tbl_deep_extend("force", default_config, opts) 136 | 137 | local picker_opts = { 138 | prompt_title = "Notifications", 139 | finder = finders.new_table({ 140 | results = notification.get_history(), 141 | entry_maker = create_entry_maker(config.wrap_text), 142 | }), 143 | sorter = conf.generic_sorter(opts), 144 | } 145 | 146 | if config.use_previewer then 147 | picker_opts.previewer = notification_previewer() 148 | end 149 | 150 | picker_opts.attach_mappings = function(prompt_bufnr, _) 151 | actions.select_default:replace(function() 152 | actions.close(prompt_bufnr) 153 | 154 | local selected = action_state.get_selected_entry() 155 | if not selected then 156 | return 157 | end 158 | 159 | vim.api.nvim_echo(format_entry(selected.value), false, {}) 160 | end) 161 | 162 | actions.select_horizontal:replace(function() 163 | actions.close(prompt_bufnr) 164 | end) 165 | 166 | actions.select_vertical:replace(function() 167 | actions.close(prompt_bufnr) 168 | end) 169 | 170 | actions.select_tab:replace(function() 171 | actions.close(prompt_bufnr) 172 | end) 173 | 174 | return true 175 | end 176 | 177 | pickers.new(opts, picker_opts):find() 178 | end 179 | 180 | return telescope.register_extension({ 181 | setup = function(ext_config) 182 | _G.__fidget_telescope_config = ext_config or {} 183 | end, 184 | exports = { 185 | fidget2 = function(opts) 186 | local config = vim.tbl_deep_extend( 187 | "force", 188 | _G.__fidget_telescope_config or {}, 189 | opts or {} 190 | ) 191 | fidget_picker(config) 192 | end, 193 | }, 194 | }) 195 | -------------------------------------------------------------------------------- /lua/user/shared/json/jsonc.lua: -------------------------------------------------------------------------------- 1 | local type = type 2 | local next = next 3 | local error = error 4 | local tonumber = tonumber 5 | local string_char = string.char 6 | local string_byte = string.byte 7 | local string_find = string.find 8 | local string_match = string.match 9 | local string_gsub = string.gsub 10 | local string_sub = string.sub 11 | local string_format = string.format 12 | 13 | local utf8_char 14 | 15 | if _VERSION == "Lua 5.1" or _VERSION == "Lua 5.2" then 16 | local math_floor = math.floor 17 | function utf8_char(c) 18 | if c <= 0x7f then 19 | return string_char(c) 20 | elseif c <= 0x7ff then 21 | return string_char(math_floor(c / 64) + 192, c % 64 + 128) 22 | elseif c <= 0xffff then 23 | return string_char(math_floor(c / 4096) + 224, math_floor(c % 4096 / 64) + 128, c % 64 + 128) 24 | elseif c <= 0x10ffff then 25 | return string_char( 26 | math_floor(c / 262144) + 240, 27 | math_floor(c % 262144 / 4096) + 128, 28 | math_floor(c % 4096 / 64) + 128, 29 | c % 64 + 128 30 | ) 31 | end 32 | error(string_format("invalid UTF-8 code '%x'", c)) 33 | end 34 | else 35 | utf8_char = utf8.char 36 | end 37 | 38 | local json = require "user.shared.json" 39 | 40 | local encode_escape_map = { 41 | ['"'] = '\\"', 42 | ["\\"] = "\\\\", 43 | ["/"] = "\\/", 44 | ["\b"] = "\\b", 45 | ["\f"] = "\\f", 46 | ["\n"] = "\\n", 47 | ["\r"] = "\\r", 48 | ["\t"] = "\\t", 49 | } 50 | 51 | local decode_escape_set = {} 52 | local decode_escape_map = {} 53 | for k, v in next, encode_escape_map do 54 | decode_escape_map[v] = k 55 | decode_escape_set[string_byte(v, 2)] = true 56 | end 57 | 58 | local statusBuf 59 | local statusPos 60 | local statusTop 61 | local statusAry = {} 62 | local statusRef = {} 63 | 64 | local function find_line() 65 | local line = 1 66 | local pos = 1 67 | while true do 68 | local f, _, nl1, nl2 = string_find(statusBuf, "([\n\r])([\n\r]?)", pos) 69 | if not f then 70 | return line, statusPos - pos + 1 71 | end 72 | local newpos = f + ((nl1 == nl2 or nl2 == "") and 1 or 2) 73 | if newpos > statusPos then 74 | return line, statusPos - pos + 1 75 | end 76 | pos = newpos 77 | line = line + 1 78 | end 79 | end 80 | 81 | local function decode_error(msg) 82 | error(string_format("ERROR: %s at line %d col %d", msg, find_line()), 2) 83 | end 84 | 85 | local function get_word() 86 | return string_match(statusBuf, "^[^ \t\r\n%]},]*", statusPos) 87 | end 88 | 89 | local function skip_comment(b) 90 | if 91 | b ~= 47 --[[ '/' ]] 92 | then 93 | return 94 | end 95 | local c = string_byte(statusBuf, statusPos + 1) 96 | if 97 | c == 42 --[[ '*' ]] 98 | then 99 | -- block comment 100 | local pos = string_find(statusBuf, "*/", statusPos) 101 | if pos then 102 | statusPos = pos + 2 103 | else 104 | statusPos = #statusBuf + 1 105 | end 106 | return true 107 | elseif 108 | c == 47 --[[ '/' ]] 109 | then 110 | -- line comment 111 | local pos = string_find(statusBuf, "[\r\n]", statusPos) 112 | if pos then 113 | statusPos = pos 114 | else 115 | statusPos = #statusBuf + 1 116 | end 117 | return true 118 | end 119 | end 120 | 121 | local function next_byte() 122 | local pos = string_find(statusBuf, "[^ \t\r\n]", statusPos) 123 | if pos then 124 | statusPos = pos 125 | local b = string_byte(statusBuf, pos) 126 | if not skip_comment(b) then 127 | return b 128 | end 129 | return next_byte() 130 | end 131 | return -1 132 | end 133 | 134 | local function decode_unicode_surrogate(s1, s2) 135 | return utf8_char(0x10000 + (tonumber(s1, 16) - 0xd800) * 0x400 + (tonumber(s2, 16) - 0xdc00)) 136 | end 137 | 138 | local function decode_unicode_escape(s) 139 | return utf8_char(tonumber(s, 16)) 140 | end 141 | 142 | local function decode_string() 143 | local has_unicode_escape = false 144 | local has_escape = false 145 | local i = statusPos + 1 146 | while true do 147 | i = string_find(statusBuf, '[%z\1-\31\\"]', i) 148 | if not i then 149 | decode_error "expected closing quote for string" 150 | end 151 | local x = string_byte(statusBuf, i) 152 | if x < 32 then 153 | statusPos = i 154 | decode_error "control character in string" 155 | end 156 | if 157 | x == 34 --[[ '"' ]] 158 | then 159 | local s = string_sub(statusBuf, statusPos + 1, i - 1) 160 | if has_unicode_escape then 161 | s = string_gsub( 162 | string_gsub(s, "\\u([dD][89aAbB]%x%x)\\u([dD][c-fC-F]%x%x)", decode_unicode_surrogate), 163 | "\\u(%x%x%x%x)", 164 | decode_unicode_escape 165 | ) 166 | end 167 | if has_escape then 168 | s = string_gsub(s, "\\.", decode_escape_map) 169 | end 170 | statusPos = i + 1 171 | return s 172 | end 173 | --assert(x == 92 --[[ "\\" ]]) 174 | local nx = string_byte(statusBuf, i + 1) 175 | if 176 | nx == 117 --[[ "u" ]] 177 | then 178 | if not string_match(statusBuf, "^%x%x%x%x", i + 2) then 179 | statusPos = i 180 | decode_error "invalid unicode escape in string" 181 | end 182 | has_unicode_escape = true 183 | i = i + 6 184 | else 185 | if not decode_escape_set[nx] then 186 | statusPos = i 187 | decode_error("invalid escape char '" .. (nx and string_char(nx) or "") .. "' in string") 188 | end 189 | has_escape = true 190 | i = i + 2 191 | end 192 | end 193 | end 194 | 195 | local function decode_number() 196 | local num, c = string_match(statusBuf, "^([0-9]+%.?[0-9]*)([eE]?)", statusPos) 197 | if 198 | not num or string_byte(num, -1) == 0x2E --[[ "." ]] 199 | then 200 | decode_error("invalid number '" .. get_word() .. "'") 201 | end 202 | if c ~= "" then 203 | num = string_match(statusBuf, "^([^eE]*[eE][-+]?[0-9]+)[ \t\r\n%]},/]", statusPos) 204 | if not num then 205 | decode_error("invalid number '" .. get_word() .. "'") 206 | end 207 | end 208 | statusPos = statusPos + #num 209 | return tonumber(num) 210 | end 211 | 212 | local function decode_number_zero() 213 | local num, c = string_match(statusBuf, "^(.%.?[0-9]*)([eE]?)", statusPos) 214 | if 215 | not num 216 | or string_byte(num, -1) == 0x2E --[[ "." ]] 217 | or string_match(statusBuf, "^.[0-9]+", statusPos) 218 | then 219 | decode_error("invalid number '" .. get_word() .. "'") 220 | end 221 | if c ~= "" then 222 | num = string_match(statusBuf, "^([^eE]*[eE][-+]?[0-9]+)[ \t\r\n%]},/]", statusPos) 223 | if not num then 224 | decode_error("invalid number '" .. get_word() .. "'") 225 | end 226 | end 227 | statusPos = statusPos + #num 228 | return tonumber(num) 229 | end 230 | 231 | local function decode_number_negative() 232 | statusPos = statusPos + 1 233 | local c = string_byte(statusBuf, statusPos) 234 | if c then 235 | if c == 0x30 then 236 | return -decode_number_zero() 237 | elseif c > 0x30 and c < 0x3A then 238 | return -decode_number() 239 | end 240 | end 241 | decode_error("invalid number '" .. get_word() .. "'") 242 | end 243 | 244 | local function decode_true() 245 | if string_sub(statusBuf, statusPos, statusPos + 3) ~= "true" then 246 | decode_error("invalid literal '" .. get_word() .. "'") 247 | end 248 | statusPos = statusPos + 4 249 | return true 250 | end 251 | 252 | local function decode_false() 253 | if string_sub(statusBuf, statusPos, statusPos + 4) ~= "false" then 254 | decode_error("invalid literal '" .. get_word() .. "'") 255 | end 256 | statusPos = statusPos + 5 257 | return false 258 | end 259 | 260 | local function decode_null() 261 | if string_sub(statusBuf, statusPos, statusPos + 3) ~= "null" then 262 | decode_error("invalid literal '" .. get_word() .. "'") 263 | end 264 | statusPos = statusPos + 4 265 | return json.null 266 | end 267 | 268 | local function decode_array() 269 | statusPos = statusPos + 1 270 | local res = {} 271 | local chr = next_byte() 272 | if 273 | chr == 93 --[[ ']' ]] 274 | then 275 | statusPos = statusPos + 1 276 | return res 277 | end 278 | statusTop = statusTop + 1 279 | statusAry[statusTop] = true 280 | statusRef[statusTop] = res 281 | return res 282 | end 283 | 284 | local function decode_object() 285 | statusPos = statusPos + 1 286 | local res = {} 287 | local chr = next_byte() 288 | if 289 | chr == 125 --[[ ']' ]] 290 | then 291 | statusPos = statusPos + 1 292 | return json.createEmptyObject() 293 | end 294 | statusTop = statusTop + 1 295 | statusAry[statusTop] = false 296 | statusRef[statusTop] = res 297 | return res 298 | end 299 | 300 | local decode_uncompleted_map = { 301 | [string_byte '"'] = decode_string, 302 | [string_byte "0"] = decode_number_zero, 303 | [string_byte "1"] = decode_number, 304 | [string_byte "2"] = decode_number, 305 | [string_byte "3"] = decode_number, 306 | [string_byte "4"] = decode_number, 307 | [string_byte "5"] = decode_number, 308 | [string_byte "6"] = decode_number, 309 | [string_byte "7"] = decode_number, 310 | [string_byte "8"] = decode_number, 311 | [string_byte "9"] = decode_number, 312 | [string_byte "-"] = decode_number_negative, 313 | [string_byte "t"] = decode_true, 314 | [string_byte "f"] = decode_false, 315 | [string_byte "n"] = decode_null, 316 | [string_byte "["] = decode_array, 317 | [string_byte "{"] = decode_object, 318 | } 319 | local function unexpected_character() 320 | decode_error("unexpected character '" .. string_sub(statusBuf, statusPos, statusPos) .. "'") 321 | end 322 | local function unexpected_eol() 323 | decode_error "unexpected character ''" 324 | end 325 | 326 | local decode_map = {} 327 | for i = 0, 255 do 328 | decode_map[i] = decode_uncompleted_map[i] or unexpected_character 329 | end 330 | decode_map[-1] = unexpected_eol 331 | 332 | local function decode() 333 | return decode_map[next_byte()]() 334 | end 335 | 336 | local function decode_item() 337 | local top = statusTop 338 | local ref = statusRef[top] 339 | if statusAry[top] then 340 | ref[#ref + 1] = decode() 341 | else 342 | local key = decode_string() 343 | if 344 | next_byte() ~= 58 --[[ ':' ]] 345 | then 346 | decode_error "expected ':'" 347 | end 348 | statusPos = statusPos + 1 349 | ref[key] = decode() 350 | end 351 | if top == statusTop then 352 | repeat 353 | local chr = next_byte() 354 | statusPos = statusPos + 1 355 | if 356 | chr == 44 --[[ "," ]] 357 | then 358 | local c = next_byte() 359 | if statusAry[statusTop] then 360 | if 361 | c ~= 93 --[[ "]" ]] 362 | then 363 | return 364 | end 365 | else 366 | if 367 | c ~= 125 --[[ "}" ]] 368 | then 369 | return 370 | end 371 | end 372 | statusPos = statusPos + 1 373 | else 374 | if statusAry[statusTop] then 375 | if 376 | chr ~= 93 --[[ "]" ]] 377 | then 378 | decode_error "expected ']' or ','" 379 | end 380 | else 381 | if 382 | chr ~= 125 --[[ "}" ]] 383 | then 384 | decode_error "expected '}' or ','" 385 | end 386 | end 387 | end 388 | statusTop = statusTop - 1 389 | until statusTop == 0 390 | end 391 | end 392 | 393 | function json.decode_jsonc(str) 394 | if type(str) ~= "string" then 395 | error("expected argument of type string, got " .. type(str)) 396 | end 397 | statusBuf = str 398 | statusPos = 1 399 | statusTop = 0 400 | if next_byte() == -1 then 401 | return json.null 402 | end 403 | local res = decode() 404 | while statusTop > 0 do 405 | decode_item() 406 | end 407 | if string_find(statusBuf, "[^ \t\r\n]", statusPos) then 408 | decode_error "trailing garbage" 409 | end 410 | return res 411 | end 412 | 413 | return json 414 | -------------------------------------------------------------------------------- /lua/user/shared/json/init.lua: -------------------------------------------------------------------------------- 1 | local type = type 2 | local next = next 3 | local error = error 4 | local tonumber = tonumber 5 | local tostring = tostring 6 | local table_concat = table.concat 7 | local table_sort = table.sort 8 | local string_char = string.char 9 | local string_byte = string.byte 10 | local string_find = string.find 11 | local string_match = string.match 12 | local string_gsub = string.gsub 13 | local string_sub = string.sub 14 | local string_format = string.format 15 | local setmetatable = setmetatable 16 | local getmetatable = getmetatable 17 | local huge = math.huge 18 | local tiny = -huge 19 | 20 | local utf8_char 21 | local math_type 22 | 23 | if _VERSION == "Lua 5.1" or _VERSION == "Lua 5.2" then 24 | local math_floor = math.floor 25 | function utf8_char(c) 26 | if c <= 0x7f then 27 | return string_char(c) 28 | elseif c <= 0x7ff then 29 | return string_char(math_floor(c / 64) + 192, c % 64 + 128) 30 | elseif c <= 0xffff then 31 | return string_char(math_floor(c / 4096) + 224, math_floor(c % 4096 / 64) + 128, c % 64 + 128) 32 | elseif c <= 0x10ffff then 33 | return string_char( 34 | math_floor(c / 262144) + 240, 35 | math_floor(c % 262144 / 4096) + 128, 36 | math_floor(c % 4096 / 64) + 128, 37 | c % 64 + 128 38 | ) 39 | end 40 | error(string_format("invalid UTF-8 code '%x'", c)) 41 | end 42 | 43 | function math_type(v) 44 | if v >= -2147483648 and v <= 2147483647 and math_floor(v) == v then 45 | return "integer" 46 | end 47 | return "float" 48 | end 49 | else 50 | utf8_char = utf8.char 51 | math_type = math.type 52 | end 53 | 54 | local json = {} 55 | 56 | json.supportSparseArray = true 57 | 58 | local objectMt = {} 59 | 60 | function json.createEmptyObject() 61 | return setmetatable({}, objectMt) 62 | end 63 | 64 | function json.isObject(t) 65 | if t[1] ~= nil then 66 | return false 67 | end 68 | return next(t) ~= nil or getmetatable(t) == objectMt 69 | end 70 | 71 | if debug and debug.upvalueid then 72 | -- Generate a lightuserdata 73 | json.null = debug.upvalueid(json.createEmptyObject, 1) 74 | else 75 | json.null = function() end 76 | end 77 | 78 | -- json.encode -- 79 | local statusVisited 80 | local statusBuilder 81 | 82 | local encode_map = {} 83 | 84 | local encode_escape_map = { 85 | ['"'] = '\\"', 86 | ["\\"] = "\\\\", 87 | ["/"] = "\\/", 88 | ["\b"] = "\\b", 89 | ["\f"] = "\\f", 90 | ["\n"] = "\\n", 91 | ["\r"] = "\\r", 92 | ["\t"] = "\\t", 93 | } 94 | 95 | local decode_escape_set = {} 96 | local decode_escape_map = {} 97 | for k, v in next, encode_escape_map do 98 | decode_escape_map[v] = k 99 | decode_escape_set[string_byte(v, 2)] = true 100 | end 101 | 102 | for i = 0, 31 do 103 | local c = string_char(i) 104 | if not encode_escape_map[c] then 105 | encode_escape_map[c] = string_format("\\u%04x", i) 106 | end 107 | end 108 | 109 | local function encode(v) 110 | local res = encode_map[type(v)](v) 111 | statusBuilder[#statusBuilder + 1] = res 112 | end 113 | 114 | encode_map["nil"] = function() 115 | return "null" 116 | end 117 | 118 | local function encode_string(v) 119 | return string_gsub(v, '[%z\1-\31\\"]', encode_escape_map) 120 | end 121 | 122 | function encode_map.string(v) 123 | statusBuilder[#statusBuilder + 1] = '"' 124 | statusBuilder[#statusBuilder + 1] = encode_string(v) 125 | return '"' 126 | end 127 | 128 | function encode_map.number(v) 129 | if math_type(v) == "integer" then 130 | return string_format("%d", v) 131 | end 132 | if v ~= v then 133 | error "NaN is not supported in JSON" 134 | elseif v <= tiny then 135 | error "-Inf is not supported in JSON" 136 | elseif v >= huge then 137 | error "Inf is not supported in JSON" 138 | end 139 | local g = string_format("%.16g", v) 140 | if tonumber(g) == v then 141 | return g 142 | end 143 | return string_format("%.17g", v) 144 | end 145 | 146 | if string_match(tostring(1 / 2), "%p") == "," then 147 | local _encode_number = encode_map.number 148 | function encode_map.number(v) 149 | return string_gsub(_encode_number(v), ",", ".") 150 | end 151 | end 152 | 153 | function encode_map.boolean(v) 154 | if v then 155 | return "true" 156 | else 157 | return "false" 158 | end 159 | end 160 | 161 | function encode_map.table(t) 162 | local first_val = next(t) 163 | if first_val == nil then 164 | if getmetatable(t) == objectMt then 165 | return "{}" 166 | else 167 | return "[]" 168 | end 169 | end 170 | if statusVisited[t] then 171 | error "circular reference" 172 | end 173 | statusVisited[t] = true 174 | if type(first_val) == "string" then 175 | local keys = {} 176 | for k in next, t do 177 | if type(k) ~= "string" then 178 | error("invalid table: mixed or invalid key types: " .. tostring(k)) 179 | end 180 | keys[#keys + 1] = k 181 | end 182 | table_sort(keys) 183 | do 184 | local k = keys[1] 185 | statusBuilder[#statusBuilder + 1] = '{"' 186 | statusBuilder[#statusBuilder + 1] = encode_string(k) 187 | statusBuilder[#statusBuilder + 1] = '":' 188 | encode(t[k]) 189 | end 190 | for i = 2, #keys do 191 | local k = keys[i] 192 | statusBuilder[#statusBuilder + 1] = ',"' 193 | statusBuilder[#statusBuilder + 1] = encode_string(k) 194 | statusBuilder[#statusBuilder + 1] = '":' 195 | encode(t[k]) 196 | end 197 | statusVisited[t] = nil 198 | return "}" 199 | elseif json.supportSparseArray then 200 | local max = 0 201 | for k in next, t do 202 | if math_type(k) ~= "integer" or k <= 0 then 203 | error("invalid table: mixed or invalid key types: " .. tostring(k)) 204 | end 205 | if max < k then 206 | max = k 207 | end 208 | end 209 | statusBuilder[#statusBuilder + 1] = "[" 210 | encode(t[1]) 211 | for i = 2, max do 212 | statusBuilder[#statusBuilder + 1] = "," 213 | encode(t[i]) 214 | end 215 | statusVisited[t] = nil 216 | return "]" 217 | else 218 | if t[1] == nil then 219 | error "invalid table: sparse array is not supported" 220 | end 221 | ---@diagnostic disable-next-line: undefined-global 222 | if jit and t[0] ~= nil then 223 | -- 0 is the first index in luajit 224 | error("invalid table: mixed or invalid key types: " .. 0) 225 | end 226 | statusBuilder[#statusBuilder + 1] = "[" 227 | encode(t[1]) 228 | local count = 2 229 | while t[count] ~= nil do 230 | statusBuilder[#statusBuilder + 1] = "," 231 | encode(t[count]) 232 | count = count + 1 233 | end 234 | if next(t, count - 1) ~= nil then 235 | local k = next(t, count - 1) 236 | if type(k) == "number" then 237 | error "invalid table: sparse array is not supported" 238 | else 239 | error("invalid table: mixed or invalid key types: " .. tostring(k)) 240 | end 241 | end 242 | statusVisited[t] = nil 243 | return "]" 244 | end 245 | end 246 | 247 | local function encode_unexpected(v) 248 | if v == json.null then 249 | return "null" 250 | else 251 | error("unexpected type '" .. type(v) .. "'") 252 | end 253 | end 254 | encode_map["function"] = encode_unexpected 255 | encode_map["userdata"] = encode_unexpected 256 | encode_map["thread"] = encode_unexpected 257 | 258 | function json.encode(v) 259 | statusVisited = {} 260 | statusBuilder = {} 261 | encode(v) 262 | return table_concat(statusBuilder) 263 | end 264 | 265 | json._encode_map = encode_map 266 | json._encode_string = encode_string 267 | 268 | -- json.decode -- 269 | 270 | local statusBuf 271 | local statusPos 272 | local statusTop 273 | local statusAry = {} 274 | local statusRef = {} 275 | 276 | local function find_line() 277 | local line = 1 278 | local pos = 1 279 | while true do 280 | local f, _, nl1, nl2 = string_find(statusBuf, "([\n\r])([\n\r]?)", pos) 281 | if not f then 282 | return line, statusPos - pos + 1 283 | end 284 | local newpos = f + ((nl1 == nl2 or nl2 == "") and 1 or 2) 285 | if newpos > statusPos then 286 | return line, statusPos - pos + 1 287 | end 288 | pos = newpos 289 | line = line + 1 290 | end 291 | end 292 | 293 | local function decode_error(msg) 294 | error(string_format("ERROR: %s at line %d col %d", msg, find_line()), 2) 295 | end 296 | 297 | local function get_word() 298 | return string_match(statusBuf, "^[^ \t\r\n%]},]*", statusPos) 299 | end 300 | 301 | local function next_byte() 302 | local pos = string_find(statusBuf, "[^ \t\r\n]", statusPos) 303 | if pos then 304 | statusPos = pos 305 | return string_byte(statusBuf, pos) 306 | end 307 | return -1 308 | end 309 | 310 | local function consume_byte(c) 311 | local _, pos = string_find(statusBuf, c, statusPos) 312 | if pos then 313 | statusPos = pos + 1 314 | return true 315 | end 316 | end 317 | 318 | local function expect_byte(c) 319 | local _, pos = string_find(statusBuf, c, statusPos) 320 | if not pos then 321 | decode_error(string_format("expected '%s'", string_sub(c, #c))) 322 | end 323 | statusPos = pos 324 | end 325 | 326 | local function decode_unicode_surrogate(s1, s2) 327 | return utf8_char(0x10000 + (tonumber(s1, 16) - 0xd800) * 0x400 + (tonumber(s2, 16) - 0xdc00)) 328 | end 329 | 330 | local function decode_unicode_escape(s) 331 | return utf8_char(tonumber(s, 16)) 332 | end 333 | 334 | local function decode_string() 335 | local has_unicode_escape = false 336 | local has_escape = false 337 | local i = statusPos + 1 338 | while true do 339 | i = string_find(statusBuf, '[%z\1-\31\\"]', i) 340 | if not i then 341 | decode_error "expected closing quote for string" 342 | end 343 | local char = string_byte(statusBuf, i) 344 | if char < 32 then 345 | statusPos = i 346 | decode_error "control character in string" 347 | end 348 | if 349 | char == 34 --[[ '"' ]] 350 | then 351 | local s = string_sub(statusBuf, statusPos + 1, i - 1) 352 | if has_unicode_escape then 353 | s = string_gsub( 354 | string_gsub(s, "\\u([dD][89aAbB]%x%x)\\u([dD][c-fC-F]%x%x)", decode_unicode_surrogate), 355 | "\\u(%x%x%x%x)", 356 | decode_unicode_escape 357 | ) 358 | end 359 | if has_escape then 360 | s = string_gsub(s, "\\.", decode_escape_map) 361 | end 362 | statusPos = i + 1 363 | return s 364 | end 365 | --assert(char == 92 --[[ "\\" ]]) 366 | local next_char = string_byte(statusBuf, i + 1) 367 | if 368 | next_char == 117 --[[ "u" ]] 369 | then 370 | if not string_match(statusBuf, "^%x%x%x%x", i + 2) then 371 | statusPos = i 372 | decode_error "invalid unicode escape in string" 373 | end 374 | has_unicode_escape = true 375 | i = i + 6 376 | else 377 | if not decode_escape_set[next_char] then 378 | statusPos = i 379 | decode_error("invalid escape char '" .. (next_char and string_char(next_char) or "") .. "' in string") 380 | end 381 | has_escape = true 382 | i = i + 2 383 | end 384 | end 385 | end 386 | 387 | local function decode_number() 388 | local num, c = string_match(statusBuf, "^([0-9]+%.?[0-9]*)([eE]?)", statusPos) 389 | if 390 | not num or string_byte(num, -1) == 0x2E --[[ "." ]] 391 | then 392 | decode_error("invalid number '" .. get_word() .. "'") 393 | end 394 | if c ~= "" then 395 | num = string_match(statusBuf, "^([^eE]*[eE][-+]?[0-9]+)[ \t\r\n%]},]", statusPos) 396 | if not num then 397 | decode_error("invalid number '" .. get_word() .. "'") 398 | end 399 | end 400 | statusPos = statusPos + #num 401 | return tonumber(num) 402 | end 403 | 404 | local function decode_number_zero() 405 | local num, c = string_match(statusBuf, "^(.%.?[0-9]*)([eE]?)", statusPos) 406 | if 407 | not num 408 | or string_byte(num, -1) == 0x2E --[[ "." ]] 409 | or string_match(statusBuf, "^.[0-9]+", statusPos) 410 | then 411 | decode_error("invalid number '" .. get_word() .. "'") 412 | end 413 | if c ~= "" then 414 | num = string_match(statusBuf, "^([^eE]*[eE][-+]?[0-9]+)[ \t\r\n%]},]", statusPos) 415 | if not num then 416 | decode_error("invalid number '" .. get_word() .. "'") 417 | end 418 | end 419 | statusPos = statusPos + #num 420 | return tonumber(num) 421 | end 422 | 423 | local function decode_number_negative() 424 | statusPos = statusPos + 1 425 | local c = string_byte(statusBuf, statusPos) 426 | if c then 427 | if c == 0x30 then 428 | return -decode_number_zero() 429 | elseif c > 0x30 and c < 0x3A then 430 | return -decode_number() 431 | end 432 | end 433 | decode_error("invalid number '" .. get_word() .. "'") 434 | end 435 | 436 | local function decode_true() 437 | if string_sub(statusBuf, statusPos, statusPos + 3) ~= "true" then 438 | decode_error("invalid literal '" .. get_word() .. "'") 439 | end 440 | statusPos = statusPos + 4 441 | return true 442 | end 443 | 444 | local function decode_false() 445 | if string_sub(statusBuf, statusPos, statusPos + 4) ~= "false" then 446 | decode_error("invalid literal '" .. get_word() .. "'") 447 | end 448 | statusPos = statusPos + 5 449 | return false 450 | end 451 | 452 | local function decode_null() 453 | if string_sub(statusBuf, statusPos, statusPos + 3) ~= "null" then 454 | decode_error("invalid literal '" .. get_word() .. "'") 455 | end 456 | statusPos = statusPos + 4 457 | return json.null 458 | end 459 | 460 | local function decode_array() 461 | statusPos = statusPos + 1 462 | if consume_byte "^[ \t\r\n]*%]" then 463 | return {} 464 | end 465 | local res = {} 466 | statusTop = statusTop + 1 467 | statusAry[statusTop] = true 468 | statusRef[statusTop] = res 469 | return res 470 | end 471 | 472 | local function decode_object() 473 | statusPos = statusPos + 1 474 | if consume_byte "^[ \t\r\n]*}" then 475 | return json.createEmptyObject() 476 | end 477 | local res = {} 478 | statusTop = statusTop + 1 479 | statusAry[statusTop] = false 480 | statusRef[statusTop] = res 481 | return res 482 | end 483 | 484 | local decode_uncompleted_map = { 485 | [string_byte '"'] = decode_string, 486 | [string_byte "0"] = decode_number_zero, 487 | [string_byte "1"] = decode_number, 488 | [string_byte "2"] = decode_number, 489 | [string_byte "3"] = decode_number, 490 | [string_byte "4"] = decode_number, 491 | [string_byte "5"] = decode_number, 492 | [string_byte "6"] = decode_number, 493 | [string_byte "7"] = decode_number, 494 | [string_byte "8"] = decode_number, 495 | [string_byte "9"] = decode_number, 496 | [string_byte "-"] = decode_number_negative, 497 | [string_byte "t"] = decode_true, 498 | [string_byte "f"] = decode_false, 499 | [string_byte "n"] = decode_null, 500 | [string_byte "["] = decode_array, 501 | [string_byte "{"] = decode_object, 502 | } 503 | local function unexpected_character() 504 | decode_error("unexpected character '" .. string_sub(statusBuf, statusPos, statusPos) .. "'") 505 | end 506 | local function unexpected_eol() 507 | decode_error "unexpected character ''" 508 | end 509 | 510 | local decode_map = {} 511 | for i = 0, 255 do 512 | decode_map[i] = decode_uncompleted_map[i] or unexpected_character 513 | end 514 | decode_map[-1] = unexpected_eol 515 | 516 | local function decode() 517 | return decode_map[next_byte()]() 518 | end 519 | 520 | local function decode_item() 521 | local top = statusTop 522 | local ref = statusRef[top] 523 | if statusAry[top] then 524 | ref[#ref + 1] = decode() 525 | else 526 | expect_byte '^[ \t\r\n]*"' 527 | local key = decode_string() 528 | expect_byte "^[ \t\r\n]*:" 529 | statusPos = statusPos + 1 530 | ref[key] = decode() 531 | end 532 | if top == statusTop then 533 | repeat 534 | local chr = next_byte() 535 | statusPos = statusPos + 1 536 | if 537 | chr == 44 --[[ "," ]] 538 | then 539 | return 540 | end 541 | if statusAry[statusTop] then 542 | if 543 | chr ~= 93 --[[ "]" ]] 544 | then 545 | decode_error "expected ']' or ','" 546 | end 547 | else 548 | if 549 | chr ~= 125 --[[ "}" ]] 550 | then 551 | decode_error "expected '}' or ','" 552 | end 553 | end 554 | statusTop = statusTop - 1 555 | until statusTop == 0 556 | end 557 | end 558 | 559 | function json.decode(str) 560 | if type(str) ~= "string" then 561 | error("expected argument of type string, got " .. type(str)) 562 | end 563 | statusBuf = str 564 | statusPos = 1 565 | statusTop = 0 566 | if str == "" then 567 | decode_error "empty string is not a valid JSON value" 568 | end 569 | local res = decode() 570 | while statusTop > 0 do 571 | decode_item() 572 | end 573 | if string_find(statusBuf, "[^ \t\r\n]", statusPos) then 574 | decode_error(string_format("trailing garbage '%s'", string_sub(statusBuf, statusPos))) 575 | end 576 | return res 577 | end 578 | 579 | return json 580 | --------------------------------------------------------------------------------