├── .gitignore ├── .ltex ├── ltex.dictionary.en-US.txt ├── ltex.dictionary.ru-RU.txt └── ltex.disabledRules.en-US.txt ├── README.md ├── ftplugin ├── help.lua ├── markdown.lua └── text.lua ├── init.lua ├── lazy-lock.json ├── lua ├── autocmd.lua ├── config │ ├── colorscheme │ │ ├── catppuccin.lua │ │ ├── everforest.lua │ │ ├── gruvbox-material.lua │ │ ├── init.lua │ │ ├── kanagawa-paper.lua │ │ ├── kanso.lua │ │ ├── mellifluous.lua │ │ ├── midnight.lua │ │ ├── monokai.lua │ │ ├── rose-pine.lua │ │ ├── serenity.lua │ │ ├── tokyonight.lua │ │ ├── tundra.lua │ │ └── vscode.lua │ ├── lsp │ │ ├── autocmd.lua │ │ ├── default.lua │ │ ├── diagnostics.lua │ │ ├── fix_inlay_hint_hl.lua │ │ ├── floats.lua │ │ ├── init.lua │ │ ├── mappings.lua │ │ └── servers │ │ │ ├── ast_grep.lua │ │ │ ├── cssls.lua │ │ │ ├── eslint.lua │ │ │ ├── gopls.lua │ │ │ ├── jsonls.lua │ │ │ ├── ltex.lua │ │ │ ├── lua_ls.lua │ │ │ ├── ruff_lsp.lua │ │ │ ├── rust_analyzer.lua │ │ │ ├── tailwindcss.lua │ │ │ ├── ts_ls.lua │ │ │ ├── volar.lua │ │ │ └── vtsls.lua │ └── plugins │ │ ├── aerial.lua │ │ ├── alpha.lua │ │ ├── autopairs.lua │ │ ├── bufferline.lua │ │ ├── clonewin.lua │ │ ├── cmp.lua │ │ ├── codeium-nvim.lua │ │ ├── codeium.lua │ │ ├── colorizer.lua │ │ ├── colorschemes.lua │ │ ├── comment.lua │ │ ├── conform.lua │ │ ├── databases.lua │ │ ├── devdocs.lua │ │ ├── dial.lua │ │ ├── dressing.lua │ │ ├── flash.lua │ │ ├── git-dev.lua │ │ ├── gitsigns.lua │ │ ├── glance.lua │ │ ├── go.lua │ │ ├── grug-far.lua │ │ ├── hardtime.lua │ │ ├── illuminate.lua │ │ ├── image.lua │ │ ├── incline.lua │ │ ├── init.lua │ │ ├── iron.lua │ │ ├── key-analizer.lua │ │ ├── langmapper.lua │ │ ├── lazydev.lua │ │ ├── lint.lua │ │ ├── live-rename.lua │ │ ├── lsp-fs-op.lua │ │ ├── lspconfig.lua │ │ ├── ltex-extra.lua │ │ ├── madol.lua │ │ ├── mason-lspconfig.lua │ │ ├── mason.lua │ │ ├── mdpreview.lua │ │ ├── molten.lua │ │ ├── neo-tree │ │ ├── init.lua │ │ └── mappings.lua │ │ ├── neocodium.lua │ │ ├── neogen.lua │ │ ├── neotest.lua │ │ ├── neowords.lua │ │ ├── notifier.lua │ │ ├── notify.lua │ │ ├── nvim-ts-autotag.lua │ │ ├── oil.lua │ │ ├── persistence.lua │ │ ├── promise.lua │ │ ├── range-highlight.lua │ │ ├── render-markdown.lua │ │ ├── scrolleof.lua │ │ ├── sibling-swap.lua │ │ ├── supermaven.lua │ │ ├── symbol-usage.lua │ │ ├── table-nvim.lua │ │ ├── tailwind-tools.lua │ │ ├── telescope.lua │ │ ├── template-string.lua │ │ ├── tfm.lua │ │ ├── toggleterm.lua │ │ ├── treesitter.lua │ │ ├── treesj.lua │ │ ├── trouble.lua │ │ ├── ts-context.lua │ │ ├── ts-error-translator.lua │ │ ├── tsc.lua │ │ ├── typescript-tools.lua │ │ ├── typr.lua │ │ ├── venv-selector.lua │ │ ├── vtsls.lua │ │ ├── wildfire.lua │ │ ├── workspace-diagnostic.lua │ │ └── zenmode.lua ├── filetype.lua ├── mappings.lua ├── modules │ ├── autoimport │ │ ├── code_action_api.lua │ │ └── init.lua │ ├── comment │ │ └── init.lua │ ├── devcontainer │ │ └── init.lua │ ├── dragndrop.lua │ ├── ext_hover.lua │ ├── fftt │ │ ├── fftt_test.lua │ │ ├── init.lua │ │ └── types.lua │ ├── foldtext.lua │ ├── git_watcher.lua │ ├── gpt │ │ ├── api.lua │ │ ├── gpt.lua │ │ ├── init.lua │ │ └── ui.lua │ ├── improve-visual-block.lua │ ├── key_listener.lua │ ├── lazygit │ │ ├── config.yml │ │ └── init.lua │ ├── markdown.lua │ ├── marks.lua │ ├── missnode.lua │ ├── mode_nr.lua │ ├── progress.lua │ ├── punto-switcher.lua │ ├── router.lua │ ├── status │ │ ├── autocmd.lua │ │ ├── components.lua │ │ └── init.lua │ ├── surround.lua │ ├── thincc.lua │ ├── toggler.lua │ └── watcher.lua ├── options.lua ├── plugins.lua ├── user_settings.lua ├── usercmd.lua └── utils.lua ├── snippets ├── javascript │ └── typescript.json └── package.json └── stylua.toml /.gitignore: -------------------------------------------------------------------------------- 1 | plugin 2 | *.DS_Store 3 | *tmp*.* 4 | .tmp 5 | todo.* 6 | tmp 7 | .colorscheme 8 | spell/ 9 | /sql/ 10 | -------------------------------------------------------------------------------- /.ltex/ltex.dictionary.en-US.txt: -------------------------------------------------------------------------------- 1 | Neovim 2 | gitcommit 3 | rigrep 4 | textDocument 5 | TODO 6 | textwidth 7 | semanticTokensProvider 8 | filetype 9 | Luasnip 10 | nvim-cmp 11 | bufnr 12 | treesitter 13 | Vite 14 | nvim 15 | TREESITTER 16 | useCallback 17 | AutoPreferSingle 18 | statusline 19 | autocommands 20 | luarocks 21 | colorcolumn 22 | thincc 23 | charset 24 | doctype 25 | Knowleges 26 | -------------------------------------------------------------------------------- /.ltex/ltex.dictionary.ru-RU.txt: -------------------------------------------------------------------------------- 1 | Вимеры 2 | -------------------------------------------------------------------------------- /.ltex/ltex.disabledRules.en-US.txt: -------------------------------------------------------------------------------- 1 | COMMA_PARENTHESIS_WHITESPACE 2 | UNLIKELY_OPENING_PUNCTUATION 3 | EN_QUOTES 4 | EN_UNPAIRED_BRACKETS 5 | ARROWS 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Neovim 0.11+ configuration 2 | 3 | Personal configuration for Neovim with a focus on web (vue3, js, ts) and lua-plugins development. 4 | 5 | ## Requirements 6 | 7 | ### Common requirements 8 | 9 | 1. [Neovim 0.11.+](https://github.com/neovim/neovim); 10 | 2. [rigrep](https://github.com/BurntSushi/ripgrep); 11 | 3. `git`; 12 | 4. `wget`/`curl`; 13 | 14 | ### Plugin dependencies 15 | 16 | 1. [fd](https://github.com/sharkdp/fd) for [telescope.nvim](https://github.com/nvim-telescope/telescope.nvim); 17 | 2. [NerdFonts](https://www.nerdfonts.com) for pretty icons; 18 | 3. [im-select](https://github.com/daipeihust/im-select) for [langmapper.nvim](https://github.com/Wansmer/langmapper.nvim); 19 | 4. [node](https://nodejs.org/en) for [markdown-preview.nvim](https://github.com/iamcco/markdown-preview.nvim); 20 | 21 | ## Installation 22 | 23 | Install Neovim and dependencies (including lsp, linters and formatters) with your package manager. 24 | [Homebrew](https://brew.sh) example: 25 | 26 | ```bash 27 | $ brew install neovim # or `brew install neovim --HEAD` to use nightly 28 | $ brew install ripgrep 29 | $ brew install fd 30 | $ brew install node 31 | ``` 32 | 33 | Clone the repo to `config` directory and run Neovim: 34 | 35 | ```bash 36 | $ git clone https://github.com/Wansmer/nvim-config ~/.config/nvim 37 | $ nvim 38 | ``` 39 | -------------------------------------------------------------------------------- /ftplugin/help.lua: -------------------------------------------------------------------------------- 1 | vim.treesitter.start() 2 | -------------------------------------------------------------------------------- /ftplugin/markdown.lua: -------------------------------------------------------------------------------- 1 | vim.opt_local.textwidth = 100 2 | -------------------------------------------------------------------------------- /ftplugin/text.lua: -------------------------------------------------------------------------------- 1 | vim.opt_local.textwidth = 80 2 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | vim.loader.enable() 2 | 3 | if vim.fn.has("nvim-0.12") == 1 then 4 | require("vim._extui").enable({}) 5 | else 6 | require("modules.router") 7 | end 8 | 9 | vim.keymap.set("", "", "") 10 | vim.g.mapleader = " " 11 | vim.g.maplocalleader = "[" 12 | vim.g.python3_host_prog = vim.fn.expand("~/.virtualenvs/neovim/bin/python3") 13 | 14 | local orig_getcharstr = vim.fn.getcharstr 15 | vim.fn.getcharstr = function() ---@diagnostic disable-line: duplicate-set-field 16 | local char = orig_getcharstr() 17 | local u = require("utils") 18 | local ok, lm = pcall(require, "langmapper.utils") 19 | if not ok or u.layout.is_en() then 20 | return char 21 | end 22 | 23 | return lm.translate_keycode(char, "default", "ru") 24 | end 25 | 26 | require("user_settings") 27 | require("options") 28 | require("plugins") 29 | 30 | require("config.colorscheme") 31 | require("mappings") 32 | require("autocmd") 33 | require("filetype") 34 | require("modules.thincc") 35 | require("modules.git_watcher") 36 | require("modules.progress") 37 | require("modules.autoimport").run() 38 | require("modules.fftt").setup() 39 | require("modules.marks").setup() 40 | require("modules.improve-visual-block").setup() 41 | require("modules.punto-switcher") 42 | require("modules.devcontainer").start() 43 | -------------------------------------------------------------------------------- /lua/config/colorscheme/catppuccin.lua: -------------------------------------------------------------------------------- 1 | vim.g.catppuccin_flavour = "mocha" -- latte, frappe, macchiato, mocha 2 | 3 | require("catppuccin").setup({ 4 | dim_inactive = { 5 | enabled = false, 6 | shade = "dark", 7 | percentage = 0.15, 8 | }, 9 | transparent_background = false, 10 | term_colors = false, 11 | compile = { 12 | enabled = true, 13 | path = vim.fn.stdpath("cache") .. "/catppuccin", 14 | }, 15 | styles = { 16 | comments = PREF.ui.italic_comment and { "italic" } or {}, 17 | conditionals = { "italic" }, 18 | loops = { "italic" }, 19 | functions = { "bold" }, 20 | keywords = { "italic" }, 21 | strings = {}, 22 | variables = {}, 23 | numbers = { "bold" }, 24 | booleans = { "bold" }, 25 | properties = {}, 26 | types = {}, 27 | operators = {}, 28 | }, 29 | integrations = { 30 | treesitter = true, 31 | native_lsp = { 32 | enabled = true, 33 | virtual_text = { 34 | errors = { "italic" }, 35 | hints = { "italic" }, 36 | warnings = { "italic" }, 37 | information = { "italic" }, 38 | }, 39 | underlines = { 40 | errors = { "underline" }, 41 | hints = { "underline" }, 42 | warnings = { "underline" }, 43 | information = { "underline" }, 44 | }, 45 | inlay_hints = { 46 | background = true, 47 | }, 48 | }, 49 | cmp = true, 50 | gitsigns = true, 51 | telescope = { 52 | enabled = true, 53 | style = "nvchad", 54 | }, 55 | neotree = true, 56 | indent_blankline = { 57 | enabled = true, 58 | colored_indent_levels = false, 59 | }, 60 | bufferline = true, 61 | markdown = true, 62 | notify = true, 63 | aerial = true, 64 | vimwiki = true, 65 | }, 66 | color_overrides = {}, 67 | highlight_overrides = { 68 | all = function(colors) 69 | return { 70 | WinBarNC = { link = "WinBar" }, 71 | NeoTreeWinSeparator = { fg = colors.base, bg = colors.base }, 72 | IblScope = { fg = colors.surface2 }, 73 | IndentLine = { fg = colors.surface0 }, 74 | IndentLineCurrent = { fg = colors.surface1 }, 75 | FloatBorder = { fg = colors.mantle, bg = colors.mantle }, 76 | FloatTitle = { fg = colors.mantle, bg = colors.lavender, bold = true }, 77 | } 78 | end, 79 | }, 80 | }) 81 | -------------------------------------------------------------------------------- /lua/config/colorscheme/everforest.lua: -------------------------------------------------------------------------------- 1 | require("everforest").setup({ 2 | -- Controls the "hardness" of the background. Options are "soft", "medium" or "hard". 3 | -- Default is "medium". 4 | background = "hard", 5 | -- How much of the background should be transparent. Options are 0, 1 or 2. 6 | -- Default is 0. 7 | -- 8 | -- 2 will have more UI components be transparent (e.g. status line 9 | -- background). 10 | transparent_background_level = 0, 11 | -- Whether italics should be used for keywords, builtin types and more. 12 | italics = false, 13 | -- Disable italic fonts for comments. Comments are in italics by default, set 14 | -- this to `true` to make them _not_ italic! 15 | disable_italic_comments = PREF.ui.italic_comment, 16 | }) 17 | -------------------------------------------------------------------------------- /lua/config/colorscheme/gruvbox-material.lua: -------------------------------------------------------------------------------- 1 | vim.g.gruvbox_material_background = "hard" -- 'hard', 'medium', 'soft' 2 | vim.g.gruvbox_material_disable_italic_comment = not PREF.ui.italic_comment 3 | vim.g.gruvbox_material_enable_bold = true 4 | vim.g.gruvbox_material_enable_italic = false 5 | vim.g.gruvbox_material_cursor = "auto" 6 | vim.g.gruvbox_material_transparent_background = 0 7 | 8 | vim.schedule(function() 9 | local h = vim.api.nvim_set_hl 10 | local get_hl = function(name) 11 | return vim.api.nvim_get_hl(0, { name = name }) 12 | end 13 | h(0, "WinBar", { link = "Normal" }) 14 | h(0, "WinBarNC", { link = "Normal" }) 15 | 16 | local nnc = get_hl("NeoTreeNormal") 17 | h(0, "NormalFloat", { link = "NeoTreeNormal" }) 18 | h(0, "FloatBorder", { bg = nnc.bg, fg = nnc.bg }) 19 | h(0, "NeoTreeWinSeparator", { bg = nnc.bg, fg = nnc.bg, force = true }) 20 | 21 | -- {{ Telescope 22 | h(0, "TelescopePromptBorder", { link = "FloatBorder" }) 23 | h(0, "TelescopePromptNormal", { bg = get_hl("FloatBorder").bg, fg = get_hl("Normal").fg }) 24 | h(0, "TelescopePromptTitle", { bg = get_hl("Orange").fg, bold = true }) 25 | 26 | h(0, "TelescopePreviewBorder", { link = "FloatBorder" }) 27 | h(0, "TelescopePreviewNormal", { bg = get_hl("FloatBorder").bg }) 28 | h(0, "TelescopePreviewTitle", { bg = get_hl("Green").fg, bold = true }) 29 | 30 | local cc = get_hl("ColorColumn") 31 | h(0, "TelescopeResultsBorder", { bg = cc.bg, fg = cc.bg }) 32 | h(0, "TelescopeResultsNormal", { bg = cc.bg }) 33 | h(0, "TelescopeResultsTitle", { bg = get_hl("Blue").fg, bold = true }) 34 | -- }} 35 | end) 36 | -------------------------------------------------------------------------------- /lua/config/colorscheme/init.lua: -------------------------------------------------------------------------------- 1 | ---Read name of colorscheme from `./.colorscheme` file. If file not found or empty, then use PREF.ui.colorscheme 2 | local function read_colorscheme() 3 | local fb_cs = PREF.ui.colorscheme -- colorscheme fallback 4 | local file = io.open(vim.fs.joinpath(vim.fn.stdpath("config")--[[@as string]], ".colorscheme"), "r") 5 | if file == nil then 6 | return fb_cs 7 | end 8 | 9 | local cs = file:read("*l") 10 | if cs == "" then 11 | return fb_cs 12 | end 13 | 14 | file:close() 15 | return cs 16 | end 17 | 18 | local colorscheme = read_colorscheme() 19 | 20 | -- Uses if one colorscheme could have different names but one config (e.g. nightfor, dayfox e.t.c) 21 | local source = { 22 | serenity = "serenity", 23 | catppuccin = "catppuccin", -- 5/5 24 | tundra = "tundra", -- 5/5 25 | kanagawa = "kanagawa", -- 5/5 26 | tokyonight = "tokyonight", -- 5/5 27 | ["gruvbox-material"] = "gruvbox-material", -- 4/5 28 | vscode = "vscode", -- 4/5 29 | everforest = "everforest", 30 | mellifluous = "mellifluous", 31 | ["monokai-pro"] = "monokai", 32 | ["rose-pine"] = "rose-pine", 33 | ["kanagawa-paper"] = "kanagawa-paper", 34 | midnight = "midnight", 35 | kanso = "kanso", 36 | } 37 | 38 | local config = source[colorscheme] 39 | 40 | if config then 41 | pcall(require, "config.colorscheme." .. config) 42 | end 43 | 44 | local present, _ = pcall(vim.cmd.colorscheme, colorscheme) 45 | 46 | if not present then 47 | vim.cmd.colorscheme("habamax") 48 | end 49 | 50 | ---Should be called after set colorscheme 51 | local function rehighlight() 52 | for _, type in pairs({ "Error", "Warn", "Hint", "Info" }) do 53 | local hl = "DiagnosticUnderline" .. type 54 | local colors = vim.api.nvim_get_hl(0, { name = hl }) 55 | vim.api.nvim_set_hl(0, hl, vim.tbl_extend("force", colors, { undercurl = true })) 56 | end 57 | vim.api.nvim_set_hl(0, "LspInlayHint", { link = "Comment" }) 58 | end 59 | 60 | rehighlight() 61 | vim.api.nvim_create_autocmd("ColorScheme", { 62 | callback = rehighlight, 63 | }) 64 | -------------------------------------------------------------------------------- /lua/config/colorscheme/kanagawa-paper.lua: -------------------------------------------------------------------------------- 1 | require("kanagawa-paper").setup({ 2 | undercurl = true, 3 | transparent = false, 4 | gutter = false, 5 | dimInactive = false, -- disabled when transparent 6 | terminalColors = true, 7 | commentStyle = { italic = true }, 8 | functionStyle = { italic = false }, 9 | keywordStyle = { italic = false, bold = false }, 10 | statementStyle = { italic = false, bold = false }, 11 | typeStyle = { italic = false }, 12 | colors = { theme = {}, palette = {} }, -- override default palette and theme colors 13 | overrides = function(c) -- override highlight groups 14 | local nnc = { fg = c.theme.ui.float.fg, bg = c.theme.ui.float.bg } 15 | return { 16 | FloatBorder = { bg = nnc.bg, fg = nnc.bg }, 17 | NeoTreeWinSeparator = { bg = nnc.bg, fg = nnc.bg, force = true }, 18 | TelescopePromptBorder = { link = "FloatBorder" }, 19 | TelescopePromptNormal = { link = "FloatBorder" }, 20 | NeoTreeTabActive = { bg = c.theme.ui.bg_p1, fg = c.theme.ui.special }, 21 | } 22 | end, 23 | }) 24 | -------------------------------------------------------------------------------- /lua/config/colorscheme/kanso.lua: -------------------------------------------------------------------------------- 1 | local kanso = require("kanso") 2 | require("kanso").setup({ 3 | theme = "ink", -- zen, ink, pearl 4 | background = { -- map the value of 'background' option to a theme 5 | dark = "ink", -- try "ink" ! 6 | light = "pearl", 7 | }, 8 | overrides = function(c) 9 | return { 10 | NeoTreeNormal = { bg = c.theme.ui.bg_p1 }, 11 | NeoTreeNormalNC = { bg = c.theme.ui.bg_p1 }, 12 | 13 | -- {{ Telescope 14 | TelescopePromptBorder = { bg = c.theme.ui.bg_p1, fg = c.theme.ui.bg_p1 }, 15 | TelescopePromptNormal = { bg = c.theme.ui.bg_p1 }, 16 | TelescopePromptCounter = { link = "Special" }, 17 | TelescopePromptTitle = { bg = c.palette.autumnYellow }, 18 | TelescopeResultsTitle = { bold = true, bg = c.palette.autumnGreen }, 19 | TelescopeResultsBorder = { bg = c.theme.ui.bg_p2, fg = c.theme.ui.bg_p2 }, 20 | TelescopeResultsNormal = { bg = c.theme.ui.bg_p2 }, 21 | -- TelescopeSelectionCaret = {}, 22 | -- TelescopeMatching = {}, 23 | TelescopePreviewBorder = { bg = c.palette.inkBlack0, fg = c.palette.inkBlack0 }, 24 | TelescopePreviewNormal = { bg = c.palette.inkBlack0 }, 25 | TelescopePreviewTitle = { bg = c.palette.lightBlue }, 26 | -- }} 27 | } 28 | end, 29 | }) 30 | -------------------------------------------------------------------------------- /lua/config/colorscheme/mellifluous.lua: -------------------------------------------------------------------------------- 1 | require("mellifluous").setup({ 2 | dim_inactive = false, 3 | color_set = "mountain", -- 'mellifluous', 'alduin', 'tender', 'mountain' 4 | highlight_overrides = { 5 | dark = function(hl, _) -- dark variant of the color set 6 | hl.set("WinBar", { link = "Normal" }) 7 | hl.set("WinBarNC", { link = "Normal" }) 8 | end, 9 | }, 10 | styles = { comments = { italic = true } }, 11 | transparent_background = { enabled = false }, 12 | flat_background = { 13 | line_numbers = true, 14 | floating_windows = false, 15 | file_tree = false, 16 | cursor_line_number = true, 17 | }, 18 | plugins = { 19 | cmp = true, 20 | gitsigns = true, 21 | indent_blankline = true, 22 | nvim_tree = { 23 | enabled = true, 24 | show_root = false, 25 | }, 26 | neo_tree = { 27 | enabled = true, 28 | }, 29 | telescope = { 30 | enabled = true, 31 | nvchad_like = true, 32 | }, 33 | startify = true, 34 | }, 35 | }) 36 | -------------------------------------------------------------------------------- /lua/config/colorscheme/midnight.lua: -------------------------------------------------------------------------------- 1 | require("midnight").setup({}) 2 | -------------------------------------------------------------------------------- /lua/config/colorscheme/monokai.lua: -------------------------------------------------------------------------------- 1 | require("monokai-pro").setup({ 2 | transparent_background = false, 3 | terminal_colors = true, 4 | devicons = false, -- highlight the icons of `nvim-web-devicons` 5 | styles = { 6 | comment = { italic = PREF.ui.italic_comment }, 7 | keyword = { italic = false }, -- any other keyword 8 | type = { italic = false }, -- (preferred) int, long, char, etc 9 | storageclass = { italic = false }, -- static, register, volatile, etc 10 | structure = { italic = false }, -- struct, union, enum, etc 11 | parameter = { italic = false }, -- parameter pass in function 12 | annotation = { italic = false }, 13 | tag_attribute = { italic = false }, -- attribute of tag in reactjs 14 | }, 15 | filter = "spectrum", -- classic | octagon | pro | machine | ristretto | spectrum 16 | -- Enable this will disable filter option 17 | day_night = { 18 | enable = false, -- turn off by default 19 | day_filter = "octagon", -- classic | octagon | pro | machine | ristretto | spectrum 20 | night_filter = "octagon", -- classic | octagon | pro | machine | ristretto | spectrum 21 | }, 22 | inc_search = "background", -- underline | background 23 | background_clear = {}, -- "float_win", "toggleterm", "telescope", "which-key", "renamer", "neo-tree" 24 | plugins = { 25 | bufferline = { 26 | underline_selected = false, 27 | underline_visible = false, 28 | }, 29 | indent_blankline = { 30 | context_highlight = "default", -- default | pro 31 | context_start_underline = false, 32 | }, 33 | }, 34 | ---@param c Colorscheme 35 | ---@diagnostic disable-next-line: unused-local 36 | override = function(c) 37 | return { 38 | FloatBorder = { link = "NormalFloat" }, 39 | WinbarNC = { link = "Winbar" }, 40 | TelescopePromptBorder = { bg = c.base.black, fg = c.base.black }, 41 | TelescopePromptNormal = { bg = c.base.black }, 42 | TelescopeResultsBorder = { bg = c.base.dimmed5, fg = c.base.dimmed5 }, 43 | TelescopeResultsNormal = { bg = c.base.dimmed5 }, 44 | TelescopePreviewBorder = { bg = c.base.dark, fg = c.base.dark }, 45 | TelescopePreviewNormal = { bg = c.base.dark }, 46 | } 47 | end, 48 | }) 49 | -------------------------------------------------------------------------------- /lua/config/colorscheme/rose-pine.lua: -------------------------------------------------------------------------------- 1 | require("rose-pine").setup({ 2 | --- @usage 'auto'|'main'|'moon'|'dawn' 3 | variant = "auto", 4 | --- @usage 'main'|'moon'|'dawn' 5 | dark_variant = "main", 6 | bold_vert_split = false, 7 | dim_nc_background = false, 8 | disable_background = false, 9 | disable_float_background = false, 10 | disable_italics = false, 11 | 12 | --- @usage string hex value or named color from rosepinetheme.com/palette 13 | groups = { 14 | background = "base", 15 | background_nc = "_experimental_nc", 16 | panel = "surface", 17 | panel_nc = "base", 18 | border = "highlight_med", 19 | comment = "muted", 20 | link = "iris", 21 | punctuation = "subtle", 22 | 23 | error = "love", 24 | hint = "iris", 25 | info = "foam", 26 | warn = "gold", 27 | 28 | headings = { 29 | h1 = "iris", 30 | h2 = "foam", 31 | h3 = "rose", 32 | h4 = "gold", 33 | h5 = "pine", 34 | h6 = "foam", 35 | }, 36 | -- or set all headings at once 37 | -- headings = 'subtle' 38 | }, 39 | 40 | -- Change specific vim highlight groups 41 | -- https://github.com/rose-pine/neovim/wiki/Recipes 42 | highlight_groups = { 43 | ColorColumn = { bg = "rose" }, 44 | 45 | -- Blend colours against the "base" background 46 | CursorLine = { bg = "foam", blend = 10 }, 47 | StatusLine = { fg = "love", bg = "love", blend = 10 }, 48 | 49 | -- By default each group adds to the existing config. 50 | -- If you only want to set what is written in this config exactly, 51 | -- you can set the inherit option: 52 | Search = { bg = "gold", inherit = false }, 53 | }, 54 | }) 55 | -------------------------------------------------------------------------------- /lua/config/colorscheme/serenity.lua: -------------------------------------------------------------------------------- 1 | require("serenity").setup() 2 | -------------------------------------------------------------------------------- /lua/config/colorscheme/tokyonight.lua: -------------------------------------------------------------------------------- 1 | require("tokyonight").setup({ 2 | style = "night", -- night, moon, storm 3 | transparent = false, 4 | terminal_colors = true, 5 | styles = { 6 | comments = { italic = PREF.ui.italic_comment }, 7 | keywords = { italic = true }, 8 | functions = {}, 9 | variables = {}, 10 | sidebars = "dark", 11 | floats = "dark", 12 | }, 13 | sidebars = { "qf", "help" }, 14 | dim_inactive = true, 15 | }) 16 | -------------------------------------------------------------------------------- /lua/config/colorscheme/tundra.lua: -------------------------------------------------------------------------------- 1 | require("nvim-tundra").setup({ 2 | transparent_background = false, 3 | dim_inactive_windows = { 4 | enabled = true, 5 | color = nil, 6 | }, 7 | editor = { 8 | search = {}, 9 | substitute = {}, 10 | }, 11 | syntax = { 12 | booleans = { bold = true, italic = true }, 13 | comments = { bold = true, italic = PREF.ui.italic_comment }, 14 | conditionals = {}, 15 | constants = { bold = true }, 16 | fields = {}, 17 | functions = {}, 18 | keywords = {}, 19 | loops = {}, 20 | numbers = { bold = true }, 21 | operators = { bold = true }, 22 | punctuation = {}, 23 | strings = {}, 24 | types = { italic = true }, 25 | }, 26 | diagnostics = { 27 | errors = {}, 28 | warnings = {}, 29 | information = {}, 30 | hints = {}, 31 | }, 32 | plugins = { 33 | lsp = true, 34 | treesitter = true, 35 | nvimtree = true, 36 | cmp = true, 37 | context = true, 38 | dbui = false, 39 | gitsigns = true, 40 | telescope = true, 41 | }, 42 | overwrite = { 43 | colors = {}, 44 | highlights = {}, 45 | }, 46 | }) 47 | -------------------------------------------------------------------------------- /lua/config/colorscheme/vscode.lua: -------------------------------------------------------------------------------- 1 | require("vscode").setup({ 2 | transparent = false, 3 | italic_comments = PREF.ui.italic_comment, 4 | disable_nvimtree_bg = true, 5 | color_overrides = {}, 6 | group_overrides = {}, 7 | }) 8 | -------------------------------------------------------------------------------- /lua/config/lsp/autocmd.lua: -------------------------------------------------------------------------------- 1 | --[[ LSP dependent autocommands ]] 2 | 3 | if vim.fn.has("nvim-0.10.0") == 1 then 4 | vim.api.nvim_create_autocmd("LspAttach", { 5 | desc = "Enable inlayHint feature", 6 | callback = function(args) 7 | local bufnr = args.buf 8 | local client = vim.lsp.get_client_by_id(args.data.client_id) 9 | if client and client:supports_method("textDocument/inlayHint", bufnr) then 10 | vim.lsp.inlay_hint.enable(PREF.lsp.show_inlay_hints, { bufnr = bufnr }) 11 | end 12 | end, 13 | }) 14 | end 15 | 16 | -- {{ Toggle diagnostic dependent of insert mode 17 | vim.api.nvim_create_autocmd("InsertEnter", { 18 | desc = "Hide diagnostic messages in insert mode", 19 | callback = function() 20 | vim.diagnostic.enable(false) 21 | end, 22 | }) 23 | 24 | vim.api.nvim_create_autocmd("InsertLeave", { 25 | desc = "Show diagnostic messages in normal mode", 26 | callback = function() 27 | vim.diagnostic.enable(true) 28 | end, 29 | }) 30 | -- }} 31 | -------------------------------------------------------------------------------- /lua/config/lsp/default.lua: -------------------------------------------------------------------------------- 1 | -- Default settings for each server 2 | local M = {} 3 | 4 | local set_keymaps = require("config.lsp.mappings").set_keymap 5 | 6 | ---Lsp attach callback 7 | ---@param client vim.lsp.Client 8 | ---@param bufnr integer 9 | M.on_attach = function(client, bufnr) 10 | -- Enable formatting for ranges 11 | if vim.fn.has("nvim-0.10.0") then 12 | vim.api.nvim_set_option_value("formatexpr", "v:lua.vim.lsp.formatexpr()", { buf = bufnr }) 13 | else 14 | ---@diagnostic disable-next-line: redundant-parameter 15 | vim.api.nvim_set_option_value("formatexpr", "v:lua.vim.lsp.formatexpr()", { buf = bufnr }) 16 | end 17 | 18 | local ok_wd, wd = pcall(require, "workspace-diagnostics") 19 | if ok_wd then 20 | wd.populate_workspace_diagnostics(client, bufnr) 21 | end 22 | 23 | -- Disable semantic tokens highlight 24 | if client.server_capabilities.semanticTokensProvider then 25 | -- Disable 26 | -- client.server_capabilities.semanticTokensProvider = nil 27 | -- Enable 28 | vim.lsp.semantic_tokens.start(bufnr, client.id) 29 | end 30 | 31 | if client.name == "ltex" then 32 | local ok, ltex_extra = pcall(require, "ltex_extra") 33 | if ok then 34 | ltex_extra.setup({ 35 | -- https://valentjn.github.io/ltex/supported-languages.html#natural-languages 36 | load_langs = { "en-US", "ru-RU" }, -- en-US as default 37 | -- boolean : whether to load dictionaries on startup 38 | init_check = true, 39 | -- string : relative or absolute path to store dictionaries 40 | path = vim.fn.stdpath("config") .. "/" .. ".ltex", 41 | -- string : "none", "trace", "debug", "info", "warn", "error", "fatal" 42 | log_level = "none", 43 | }) 44 | end 45 | end 46 | 47 | if client.name == "ruff_lsp" then 48 | client.server_capabilities.hoverProvider = false 49 | end 50 | 51 | local ok, sqls = pcall(require, "sqls") 52 | if ok then 53 | sqls.on_attach(client, bufnr) 54 | end 55 | 56 | set_keymaps(client, bufnr) 57 | end 58 | 59 | M.autostart = true 60 | 61 | M.single_file_support = true 62 | 63 | M.flags = { debounce_text_changes = 150 } 64 | 65 | -- nvim-cmp 66 | local cmp_ok, _ = pcall(require, "cmp_nvim_lsp") 67 | local ok_c, capabilities = pcall(require("cmp_nvim_lsp").default_capabilities) 68 | if cmp_ok and ok_c then 69 | -- Luasnip 70 | capabilities.textDocument.completion.completionItem.snippetSupport = true 71 | M.capabilities = capabilities 72 | end 73 | 74 | return M 75 | -------------------------------------------------------------------------------- /lua/config/lsp/diagnostics.lua: -------------------------------------------------------------------------------- 1 | local u = require("utils") 2 | local NS = vim.api.nvim_create_namespace("__part.diagnostics") 3 | 4 | local function set_float_hls() 5 | local fb = vim.api.nvim_get_hl(0, { name = "FloatBorder", link = false }) 6 | local ws = vim.api.nvim_get_hl(0, { name = "WinSeparator", link = false }) 7 | 8 | local set_hl = vim.api.nvim_set_hl 9 | 10 | set_hl(NS, "FloatBorder", { fg = ws.fg, bg = fb.bg }) 11 | -- Safe your eyes. Reading SCREAMING RED TEXT is bad 12 | set_hl(NS, "DiagnosticFloatingWarn", { link = "NormalFloat" }) 13 | set_hl(NS, "DiagnosticFloatingError", { link = "NormalFloat" }) 14 | set_hl(NS, "DiagnosticFloatingInfo", { link = "NormalFloat" }) 15 | set_hl(NS, "DiagnosticFloatingHint", { link = "NormalFloat" }) 16 | end 17 | 18 | local severitySigns = { 19 | [vim.diagnostic.severity.ERROR] = "", 20 | [vim.diagnostic.severity.WARN] = "", 21 | [vim.diagnostic.severity.HINT] = "", 22 | [vim.diagnostic.severity.INFO] = "", 23 | } 24 | 25 | ---@type vim.diagnostic.Opts 26 | local config = { 27 | virtual_text = PREF.lsp.virtual_text, 28 | signs = { 29 | text = severitySigns, 30 | }, 31 | underline = true, 32 | update_in_insert = false, 33 | severity_sort = true, 34 | float = { 35 | source = false, 36 | focusable = true, 37 | style = "minimum", 38 | -- border = PREF.ui.border, ---@type string|table 39 | prefix = function(d) 40 | local severity_name = u.capitalize(vim.diagnostic.severity[d.severity]) 41 | return severitySigns[d.severity] .. " ", "DiagnosticSign" .. severity_name 42 | end, 43 | format = function(d) 44 | return d.message .. " " 45 | end, 46 | suffix = function(d) 47 | return string.format("[%s: %s]", d.source, d.code), "Underlined" 48 | end, 49 | header = "", 50 | ---@type string|string[]|table 51 | border = { 52 | { "", "FloatBorder" }, 53 | { "", "FloatBorder" }, 54 | { "", "FloatBorder" }, 55 | { " ", "FloatBorder" }, 56 | { "", "FloatBorder" }, 57 | { "", "FloatBorder" }, 58 | { "", "FloatBorder" }, 59 | { " ", "FloatBorder" }, 60 | }, 61 | }, 62 | } 63 | 64 | local M = {} 65 | 66 | function M.toggle_diagnostics() 67 | vim.diagnostic.enable(vim.diagnostic.is_enabled()) 68 | end 69 | 70 | function M.apply() 71 | local orig_open_float = vim.diagnostic.open_float 72 | ---@diagnostic disable-next-line: duplicate-set-field 73 | vim.diagnostic.open_float = function(opts, ...) 74 | local bufnr, win = orig_open_float(opts, ...) 75 | if not win then 76 | return 77 | end 78 | 79 | vim.api.nvim_win_set_hl_ns(win--[[@as integer]], NS) 80 | 81 | vim.keymap.set("n", "K", function() 82 | local col = vim.api.nvim_win_get_cursor(0)[2] + 1 83 | local from, to, url = vim.api.nvim_get_current_line():find("%[(.-)%]") 84 | if from and col >= from and col <= to then 85 | url = "https://ya.ru/search?text=" .. u.encodeURL(url) 86 | vim.system({ "open", url }, nil, function(res) 87 | if res.code ~= 0 then 88 | vim.notify("Failed to open URL" .. url, vim.log.levels.ERROR) 89 | end 90 | end) 91 | end 92 | end, { buffer = bufnr, silent = true }) 93 | end 94 | 95 | vim.api.nvim_create_autocmd("ColorScheme", { 96 | callback = set_float_hls, 97 | }) 98 | 99 | set_float_hls() 100 | 101 | vim.diagnostic.config(config) 102 | 103 | local signs = { 104 | Error = config.signs.text[vim.diagnostic.severity.ERROR], 105 | Warn = config.signs.text[vim.diagnostic.severity.WARN], 106 | Hint = config.signs.text[vim.diagnostic.severity.HINT], 107 | Info = config.signs.text[vim.diagnostic.severity.INFO], 108 | } 109 | 110 | for type, icon in pairs(signs) do 111 | local hl = "DiagnosticSign" .. type 112 | vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = "" }) 113 | end 114 | end 115 | 116 | return M 117 | -------------------------------------------------------------------------------- /lua/config/lsp/fix_inlay_hint_hl.lua: -------------------------------------------------------------------------------- 1 | local u = require("utils") 2 | 3 | local store = {} 4 | 5 | local function set_hls() 6 | local vhl = vim.api.nvim_get_hl(0, { name = "Visual", link = false }) 7 | local ihl = vim.api.nvim_get_hl(0, { name = "LspInlayHint", link = false }) 8 | vim.api.nvim_set_hl(0, "VisualLspInlayHint", { bg = vhl.bg, fg = ihl.fg }) 9 | end 10 | set_hls() 11 | 12 | ---Set hl to virtual text list in place 13 | ---@param virt_text {[1]: string, [2]: string?}[] 14 | ---@param hl string 15 | local function set_virt_hl_value(virt_text, hl) 16 | for _, tuple in ipairs(virt_text) do 17 | tuple[2] = hl 18 | end 19 | end 20 | 21 | ---Update extmark 22 | ---@param ns integer 23 | ---@param mark_id integer 24 | ---@param opts {virt_text: {[1]: string, [2]: string?}[], hl: string, line: integer, col: integer, hl: string}} 25 | ---@return boolean, any 26 | local function update_marks(ns, mark_id, opts) 27 | set_virt_hl_value(opts.virt_text, opts.hl) 28 | -- Mark may be deleted by other script, e.g. default Inlay-hint handler 29 | return pcall(vim.api.nvim_buf_set_extmark, 0, ns, opts.line, opts.col, { 30 | id = mark_id, 31 | virt_text = opts.virt_text, 32 | virt_text_pos = "inline", 33 | }) 34 | end 35 | 36 | ---Check if position is in visual range 37 | ---@param range [number, number, number, number] 38 | ---@param pos [number, number] 39 | ---@param mode? 'char'|'line'|'block' 40 | ---@return boolean 41 | local function in_visual_range(range, pos, mode) 42 | if not (range and pos and mode) then 43 | return false 44 | end 45 | 46 | local sr, sc, er, ec = unpack(range) 47 | local mr, mc = unpack(pos) 48 | 49 | if sr <= mr and mr <= er then 50 | if mode == "line" then 51 | return true -- Common condition is enough for linewise mode 52 | end 53 | 54 | if mode == "block" then 55 | return sc < mc and mc < ec 56 | end 57 | 58 | if mode == "char" then 59 | if sr == er then 60 | return sc < mc and mc < ec 61 | end 62 | 63 | -- If visual range is multiline 64 | if sr == mr then 65 | return sc < mc 66 | elseif er == mr then 67 | return ec > mc 68 | else 69 | return true 70 | end 71 | end 72 | end 73 | 74 | return false 75 | end 76 | 77 | ---Restore extmarks for a given range or all if nil 78 | ---@param range? [number, number, number, number] 79 | local function restore_marks(range) 80 | local ihns = vim.api.nvim_get_namespaces()["nvim.lsp.inlayhint"] 81 | 82 | for id, data in pairs(store) do 83 | local mode = u.visual_mode_type() 84 | 85 | local to_restore = not (range and in_visual_range(range, { data.line, data.col }, mode)) 86 | if to_restore then 87 | set_virt_hl_value(data.virt_text, "LspInlayHint") 88 | data.hl = "LspInlayHint" 89 | update_marks(ihns, id, data) 90 | store[id] = nil 91 | end 92 | end 93 | end 94 | 95 | vim.api.nvim_create_autocmd({ "ModeChanged", "CursorMoved" }, { 96 | callback = function() 97 | local mode = vim.fn.strtrans(vim.fn.mode()):lower():gsub("%W", "") 98 | local ihns = vim.api.nvim_get_namespaces()["nvim.lsp.inlayhint"] 99 | if mode ~= "v" or not ihns then 100 | restore_marks() 101 | return 102 | end 103 | 104 | local range = { u.to_api_range(u.get_visual_range()) } 105 | local marks = vim.api.nvim_buf_get_extmarks(0, ihns, { range[1], 0 }, { range[3] + 1, 0 }, { details = true }) 106 | 107 | for _, m in ipairs(marks) do 108 | local id, linenr, col, opts = m[1], m[2], m[3], m[4] 109 | set_virt_hl_value(m[4].virt_text, "VisualLspInlayHint") 110 | 111 | if not store[m[1]] then 112 | local data = { line = linenr, col = col, virt_text = opts.virt_text, hl = "VisualLspInlayHint" } 113 | local ok, _ = update_marks(ihns, id, data) 114 | if ok then 115 | store[id] = data 116 | end 117 | end 118 | end 119 | 120 | restore_marks(range) 121 | end, 122 | }) 123 | 124 | vim.api.nvim_create_autocmd("ColorScheme", { 125 | callback = set_hls, 126 | }) 127 | -------------------------------------------------------------------------------- /lua/config/lsp/floats.lua: -------------------------------------------------------------------------------- 1 | ---WARNING: do not use, handlers and vim.lsp.with is deprecated 2 | 3 | ---Additional settings for lsp hover and signature_help 4 | ---Based on https://github.com/MariaSolOs/dotfiles/blob/bda5388e484497b8c88d9137c627c0f24ec295d7/.config/nvim/lua/lsp.lua#L193 5 | 6 | local ns = vim.api.nvim_create_namespace("__lsp_float__") 7 | 8 | local M = {} 9 | 10 | M.float_opts = { 11 | border = PREF.ui.border, 12 | max_height = math.floor(vim.o.lines * 0.5), 13 | max_width = math.floor(vim.o.columns * 0.4), 14 | } 15 | 16 | local function set_float_hl(buf, win) 17 | local hls = { 18 | ["|%S-|"] = "@text.reference", 19 | ["@%S+"] = "@parameter", 20 | ["^%s*(Parameters:)"] = "@text.title", 21 | ["^%s*(Return:)"] = "@text.title", 22 | ["^%s*(See also:)"] = "@text.title", 23 | ["{%S-}"] = "@parameter", 24 | } 25 | 26 | local ok, c = pcall(require, "serenity.colors") 27 | if ok then 28 | vim.api.nvim_set_hl(ns, "@text.reference", { fg = c.blue, underline = true }) 29 | vim.api.nvim_win_set_hl_ns(win, ns) 30 | end 31 | 32 | -- Extra highlights. 33 | for l, line in ipairs(vim.api.nvim_buf_get_lines(buf, 0, -1, false)) do 34 | for pattern, hl_group in pairs(hls) do 35 | local from = 1 ---@type integer? 36 | while from do 37 | local to 38 | from, to = line:find(pattern, from) 39 | if from then 40 | vim.api.nvim_buf_set_extmark(buf, ns, l - 1, from - 1, { 41 | end_col = to, 42 | hl_group = hl_group, 43 | }) 44 | end 45 | from = to and to + 1 or nil 46 | end 47 | end 48 | end 49 | end 50 | 51 | ---Opening help and links with 'K' and 'gx' 52 | ---@param buf integer Buffer id 53 | local function set_float_keymaps(buf) 54 | local function opener() 55 | -- Vim help links. 56 | ---@diagnostic disable-next-line: param-type-mismatch 57 | local tag = (vim.fn.expand("")):match("|(%S-)|") 58 | if tag then 59 | return vim.cmd.help(tag) 60 | end 61 | 62 | -- Markdown links. 63 | local col = vim.api.nvim_win_get_cursor(0)[2] + 1 64 | local from, to, url = vim.api.nvim_get_current_line():find("%[.-%]%((%S-)%)") 65 | 66 | if from and col >= from and col <= to then 67 | vim.system({ "open", url }, nil, function(res) 68 | if res.code ~= 0 then 69 | vim.notify("Failed to open URL" .. url, vim.log.levels.ERROR) 70 | end 71 | end) 72 | end 73 | end 74 | 75 | -- Add keymaps for opening links. 76 | vim.keymap.set("n", "K", opener, { buffer = buf, silent = true }) 77 | vim.keymap.set("n", "gx", opener, { buffer = buf, silent = true }) 78 | end 79 | 80 | ---LSP handler that adds extra inline highlights, keymaps, and window options. 81 | ---Code inspired from [noice](https://github.com/folke/noice.nvim). 82 | ---@param handler fun(err: any, result: any, ctx: any, config: any): integer, integer 83 | ---@param opts? table 84 | ---@return function 85 | local function on_float(handler, opts) 86 | return function(err, result, ctx, config) 87 | config = vim.tbl_deep_extend("force", config or {}, opts or {}) 88 | local buf, win = handler(err, result, ctx, vim.tbl_deep_extend("force", config, M.float_opts)) 89 | 90 | if not (buf and win) then 91 | return 92 | end 93 | 94 | -- Conceal everything. 95 | vim.wo[win].concealcursor = "n" 96 | vim.wo[win].wrap = false 97 | 98 | set_float_hl(buf, win) 99 | set_float_keymaps(buf) 100 | return buf, win 101 | end 102 | end 103 | 104 | ---Improves view of LSP hover and signature_help. 105 | function M.apply() 106 | local handlers = vim.lsp.handlers 107 | handlers["textDocument/hover"] = on_float(handlers.hover, { silent = true }) 108 | handlers["textDocument/signatureHelp"] = on_float(handlers.signature_help) 109 | end 110 | 111 | return M 112 | -------------------------------------------------------------------------------- /lua/config/lsp/init.lua: -------------------------------------------------------------------------------- 1 | local lsp = require("lspconfig") 2 | local mlsp = require("mason-lspconfig") 3 | local diagnostics = require("config.lsp.diagnostics") 4 | require("config.lsp.autocmd") 5 | require("config.lsp.fix_inlay_hint_hl") 6 | diagnostics.apply() 7 | 8 | -- Premerge user settings 9 | local function make_config(server_name) 10 | local path = "config.lsp.servers." 11 | local config = require("config.lsp.default") 12 | local present, user_config = pcall(require, path .. server_name) 13 | if present then 14 | config = vim.tbl_deep_extend("force", config, user_config) 15 | end 16 | return config 17 | end 18 | 19 | local servers = mlsp.get_installed_servers() 20 | 21 | for _, server_name in pairs(servers) do 22 | if PREF.lsp.active_servers[server_name] then 23 | local opts = make_config(server_name) 24 | lsp[server_name].setup(opts) 25 | end 26 | end 27 | 28 | ---@diagnostic disable-next-line: param-type-mismatch 29 | for _, group in ipairs(vim.fn.getcompletion("@lsp", "highlight")) do 30 | vim.api.nvim_set_hl(0, group, {}) 31 | end 32 | -------------------------------------------------------------------------------- /lua/config/lsp/mappings.lua: -------------------------------------------------------------------------------- 1 | local u = require("utils") 2 | local map = vim.keymap.set 3 | 4 | ---Add desc for keymap opts 5 | ---@param opts table Keymap opts 6 | ---@return function(str: string): table 7 | local function desc(opts) 8 | return function(str) 9 | opts.desc = str 10 | return opts 11 | end 12 | end 13 | 14 | local float_opts = { 15 | border = PREF.ui.border, 16 | max_width = 80, 17 | } 18 | 19 | local M = {} 20 | 21 | -- {{ Common lsp dependent toggler 22 | map("n", "li", function() 23 | vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = 0 }), { bufnr = 0 }) 24 | end, { desc = "Toggle inlayHint for current buffer" }) 25 | map("n", "ld", function() 26 | vim.diagnostic.enable(not vim.diagnostic.is_enabled({ bufnr = 0 }), { bufnr = 0 }) 27 | end, { desc = "Toggle diagnostic" }) 28 | 29 | local function toggle_ltex_lang() 30 | local client = vim.lsp.get_clients({ name = "ltex", bufnr = 0 })[1] 31 | if not client then 32 | return 33 | end 34 | local langs = u.tbl_add_reverse_lookup({ 35 | ["ru-RU"] = "en-US", 36 | }) 37 | local current_lang = client.config.settings.ltex.language 38 | local lang = langs[current_lang] 39 | vim.notify("Toggle ltex lang from " .. current_lang .. " to " .. lang, vim.log.levels.INFO, { title = "Ltex:" }) 40 | client.config.settings.ltex.language = lang 41 | vim.lsp.buf_notify(0, "workspace/didChangeConfiguration", { settings = client.config.settings }) 42 | end 43 | 44 | vim.keymap.set("n", "ll", toggle_ltex_lang, { desc = "Toggle ltex language" }) 45 | -- }} 46 | 47 | -- INFO: Moved out from M.set_keymap since it using third-party format plugin 48 | map("n", "gF", function() 49 | local ok, conform = pcall(require, "conform") 50 | if not ok then 51 | pcall(vim.lsp.buf.format) 52 | return 53 | end 54 | 55 | conform.format({ bufnr = 0, lsp_fallback = true }) 56 | end, { desc = "Format buffer" }) 57 | 58 | ---Setup mappings 59 | ---@param _ table Client 60 | ---@param bufnr integer 61 | M.set_keymap = function(_, bufnr) 62 | local d = desc({ buffer = bufnr, desc = "" }) 63 | 64 | -- Diagnostics 65 | map("n", "gl", function() 66 | vim.diagnostic.open_float(float_opts) 67 | end, d("Open diagnostic float on the line")) 68 | map("n", "]d", function() 69 | vim.diagnostic.jump({ count = 1, float = true }) 70 | end, d("Go to next diagnostic")) 71 | map("n", "[d", function() 72 | vim.diagnostic.jump({ count = -1, float = true }) 73 | end, d("Go to prev diagnostic")) 74 | 75 | -- Hover (symbol info) 76 | map("n", "K", function() 77 | vim.lsp.buf.hover(float_opts) 78 | end, d("Show symbol info")) 79 | map("n", "gK", require("modules.ext_hover").extended_hover, d("Show symbol info with definition")) 80 | 81 | -- Formatting 82 | -- INFO: Moved out from M.set_keymap since it using third-party format plugin 83 | 84 | -- Show code action 85 | map("n", "ga", vim.lsp.buf.code_action, d("Show available code action")) 86 | 87 | -- Jumps 88 | map("n", "gd", vim.lsp.buf.definition, d("Go to definition")) 89 | map("n", "go", vim.lsp.buf.type_definition, d("Go to type definition")) 90 | map("n", "gD", vim.lsp.buf.declaration, d("Go to declaration")) 91 | 92 | -- Lists 93 | map("n", "gi", vim.lsp.buf.implementation, d("List of implementation")) 94 | map("n", "gr", vim.lsp.buf.references, d("List of references")) 95 | 96 | -- Rename 97 | local ok_lr, lr = pcall(require, "live-rename") 98 | local renamer = ok_lr and lr.map({ 99 | insert = true, --[[ text = "" ]] 100 | }) or vim.lsp.buf.rename 101 | map("n", "gR", renamer, d("Rename symbol")) 102 | 103 | -- Signature help 104 | map("n", "gs", vim.lsp.buf.signature_help, d("Signature help")) 105 | map("i", "", vim.lsp.buf.signature_help, d("Signature help")) 106 | end 107 | 108 | return M 109 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/ast_grep.lua: -------------------------------------------------------------------------------- 1 | local nvim_lsp = require("lspconfig") 2 | 3 | return { 4 | cmd = { "sg", "lsp" }, 5 | filetypes = { "typescript" }, 6 | single_file_support = true, 7 | root_dir = nvim_lsp.util.root_pattern(".git", "sgconfig.yml"), 8 | } 9 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/cssls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | settings = { 3 | css = { validate = false }, 4 | scss = { validate = false }, 5 | less = { validate = false }, 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/eslint.lua: -------------------------------------------------------------------------------- 1 | local u = require("utils") 2 | 3 | ---Check if path exists in cwd 4 | ---@param path string 5 | ---@return boolean 6 | local function is_exist_in_cwd(path) 7 | return vim.uv.fs_stat(vim.fs.joinpath(vim.uv.cwd(), path)) ~= nil 8 | end 9 | 10 | ---Check if cwd contains config.eslint.js (new flat config) 11 | ---@return boolean 12 | local function is_flat_config_in_cwd() 13 | return vim 14 | .iter({ 15 | "eslint.config.js", 16 | "eslint.config.mjs", 17 | "eslint.config.cjs", 18 | "eslint.config.ts", 19 | "eslint.config.mts", 20 | "eslint.config.cts", 21 | }) 22 | :any(is_exist_in_cwd) 23 | end 24 | 25 | ---Check if cwd contains legacy config. 26 | ---@return boolean 27 | local function is_legacy_config_in_cwd() 28 | return vim 29 | .iter({ 30 | ".eslintrc", 31 | ".eslintrc.js", 32 | ".eslintrc.cjs", 33 | ".eslintrc.yaml", 34 | ".eslintrc.yml", 35 | ".eslintrc.json", 36 | }) 37 | :any(is_exist_in_cwd) 38 | end 39 | 40 | ---Check if flat config is used in cwd. If cwd contains legacy config, reuturned false. If not 41 | ---config detected, the 'ESLINT_USE_FLAT_CONFIG' value is used (for global config). 42 | ---@return boolean 43 | local function is_use_flat_config() 44 | if is_legacy_config_in_cwd() then 45 | return false 46 | end 47 | return is_flat_config_in_cwd() or u.to_bool(vim.env.ESLINT_USE_FLAT_CONFIG) 48 | end 49 | 50 | return { 51 | settings = { 52 | experimental = { 53 | useFlatConfig = nil, -- Deprecated in this place. Deleted to avoid collisions 54 | }, 55 | useFlatConfig = is_use_flat_config(), 56 | }, 57 | } 58 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/gopls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | settings = { 3 | gopls = { 4 | hints = { 5 | -- https://github.com/golang/tools/blob/master/gopls/doc/inlayHints.md 6 | assignVariableTypes = true, 7 | compositeLiteralFields = true, 8 | compositeLiteralTypes = true, 9 | constantValues = true, 10 | functionTypeParameters = true, 11 | parameterNames = true, 12 | rangeVariableTypes = true, 13 | }, 14 | }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/jsonls.lua: -------------------------------------------------------------------------------- 1 | local s_ok, schemastore = pcall(require, "schemastore") 2 | 3 | local settings = { 4 | json = { 5 | schemas = s_ok and schemastore.json.schemas() or {}, 6 | }, 7 | } 8 | 9 | return { 10 | settings = settings, 11 | setup = {}, 12 | } 13 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/ltex.lua: -------------------------------------------------------------------------------- 1 | -- https://valentjn.github.io/ltex/settings.html 2 | 3 | local ft = { 4 | "c", 5 | "clojure", 6 | "coffeescript", 7 | "cpp", 8 | "csharp", 9 | "dart", 10 | "elixir", 11 | "elm", 12 | "erlang", 13 | "fortran-modern", 14 | "fsharp", 15 | "gitcommit", 16 | "go", 17 | "groovy", 18 | "haskell", 19 | "html", 20 | "java", 21 | "javascript", 22 | "julia", 23 | "kotlin", 24 | "lisp", 25 | "lua", 26 | "markdown", 27 | "matlab", 28 | "org", 29 | "pandoc", 30 | "perl", 31 | "perl6", 32 | "php", 33 | "plaintex", 34 | "puppet", 35 | "python", 36 | "r", 37 | "ruby", 38 | "rust", 39 | "rust", 40 | "scala", 41 | "shellscript", 42 | "sql", 43 | "swift", 44 | "tex", 45 | "text", 46 | "toml", 47 | "typescript", 48 | "typescript", 49 | "typescriptreact", 50 | "vb", 51 | "verilog", 52 | "yaml", 53 | } 54 | 55 | return { 56 | filetypes = ft, 57 | settings = { 58 | ltex = { 59 | -- It's for checks comments in different languages 60 | -- https://github.com/valentjn/ltex-ls/blob/develop/src/main/kotlin/org/bsplines/ltexls/parsing/program/ProgramCommentRegexs.kt 61 | enabled = ft, 62 | checkFrequency = "save", 63 | language = "en-US", 64 | diagnosticSeverity = "information", 65 | setenceCacheSize = 5000, 66 | additionalRules = { 67 | enablePickyRules = true, 68 | }, 69 | }, 70 | }, 71 | } 72 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/lua_ls.lua: -------------------------------------------------------------------------------- 1 | -- https://github.com/luals/lua-language-server 2 | -- https://github.com/LuaLS/lua-language-server/blob/16b9ce9bafbf0f432ab7d1d063e2f18b1ed0c947/doc/en-us/config.md 3 | 4 | local settings = { 5 | Lua = { 6 | hint = { 7 | enable = true, 8 | arrayIndex = "Disable", 9 | }, 10 | diagnostics = { 11 | globals = { "vim", "USER_SETTINGS" }, 12 | disable = { "missing-fields" }, 13 | }, 14 | workspace = { 15 | library = { 16 | vim.fn.expand("$VIMRUNTIME/lua"), 17 | vim.fn.stdpath("config") .. "/lua", 18 | }, 19 | checkThirdParty = false, 20 | }, 21 | format = { 22 | enabled = false, 23 | }, 24 | codeLens = { 25 | enable = false, 26 | }, 27 | completion = { 28 | callSnippet = "Replace", 29 | }, 30 | }, 31 | } 32 | 33 | return { 34 | settings = settings, 35 | } 36 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/ruff_lsp.lua: -------------------------------------------------------------------------------- 1 | return { 2 | settings = { 3 | organizeImports = false, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/rust_analyzer.lua: -------------------------------------------------------------------------------- 1 | return { 2 | settings = { 3 | ["rust-analyzer"] = { 4 | diagnostics = { enable = true }, 5 | cargo = { features = "all" }, 6 | checkOnSave = true, 7 | check = { command = "clippy" }, 8 | inlayHints = { 9 | enabled = false, 10 | expressionAdjustmentHints = { enable = false }, -- do not enable 11 | bindingModeHints = { enable = false }, 12 | chainingHints = { enable = false }, -- do not enable 13 | closingBraceHints = { enable = false }, 14 | closureCaptureHints = { enable = false }, 15 | }, 16 | lens = { 17 | enable = true, 18 | methodReferences = true, 19 | references = true, 20 | implementations = false, 21 | }, 22 | }, 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/tailwindcss.lua: -------------------------------------------------------------------------------- 1 | return { 2 | settings = { 3 | tailwindCSS = { 4 | experimental = { 5 | classRegex = { 6 | { "cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]" }, 7 | { "cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)" }, 8 | }, 9 | }, 10 | }, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/ts_ls.lua: -------------------------------------------------------------------------------- 1 | -- https://github.com/typescript-language-server/typescript-language-server/ 2 | -- See docs/configuration.md 3 | return { 4 | -- autostart = not PREF.lsp.tom_enable, 5 | init_options = { 6 | hostInfo = "neovim", 7 | locale = "en", 8 | preferences = { 9 | providePrefixAndSuffixTextForRename = false, 10 | allowRenameOfImportPath = false, 11 | }, 12 | }, 13 | settings = { 14 | diagnostics = { 15 | ---@type number[] 16 | ignoredCodes = {}, 17 | }, 18 | -- https://www.reddit.com/r/neovim/comments/14e41rb/comment/jou4ljw/?utm_source=share&utm_medium=web2x&context=3 19 | typescript = { 20 | inlayHints = { 21 | includeInlayParameterNameHints = "all", 22 | includeInlayParameterNameHintsWhenArgumentMatchesName = false, 23 | includeInlayFunctionParameterTypeHints = false, 24 | includeInlayVariableTypeHints = false, 25 | includeInlayVariableTypeHintsWhenTypeMatchesName = false, 26 | includeInlayPropertyDeclarationTypeHints = true, 27 | includeInlayFunctionLikeReturnTypeHints = false, 28 | includeInlayEnumMemberValueHints = true, 29 | }, 30 | }, 31 | javascript = { 32 | inlayHints = { 33 | includeInlayParameterNameHints = "all", 34 | includeInlayParameterNameHintsWhenArgumentMatchesName = false, 35 | includeInlayFunctionParameterTypeHints = false, 36 | includeInlayVariableTypeHints = false, 37 | includeInlayVariableTypeHintsWhenTypeMatchesName = false, 38 | includeInlayPropertyDeclarationTypeHints = true, 39 | includeInlayFunctionLikeReturnTypeHints = false, 40 | includeInlayEnumMemberValueHints = true, 41 | }, 42 | }, 43 | }, 44 | } 45 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/volar.lua: -------------------------------------------------------------------------------- 1 | local util = require("lspconfig.util") 2 | local cssls = require("config.lsp.servers.cssls") 3 | 4 | local function get_typescript_server_path(root_dir) 5 | -- TODO: implement dynamic search of `typescript` 6 | local global_ts = "/opt/homebrew/lib/node_modules/typescript/lib" 7 | local found_ts = "" 8 | local function check_dir(path) 9 | found_ts = util.path.join(path, "node_modules", "typescript", "lib") 10 | if util.path.exists(found_ts) then 11 | return path 12 | end 13 | end 14 | if util.search_ancestors(root_dir, check_dir) then 15 | return found_ts 16 | else 17 | return global_ts 18 | end 19 | end 20 | 21 | local tom_fts = { 22 | "vue", 23 | "typescript", 24 | "javascript", 25 | "javascriptreact", 26 | "typescriptreact", 27 | "json", 28 | } 29 | 30 | local vue_fts = { 31 | "vue", 32 | } 33 | 34 | local is_take_over_mode = PREF.lsp.tom_enable 35 | 36 | local accepted_filetypes = is_take_over_mode and tom_fts or vue_fts 37 | 38 | return { 39 | filetypes = accepted_filetypes, 40 | single_file_support = false, 41 | -- https://github.com/vuejs/language-tools/blob/20d713b/packages/shared/src/types.ts 42 | init_options = { 43 | languageFeatures = { 44 | references = true, 45 | implementation = true, 46 | definition = true, 47 | typeDefinition = true, 48 | callHierarchy = true, 49 | hover = true, 50 | rename = true, 51 | renameFileRefactoring = true, 52 | signatureHelp = true, 53 | completion = { 54 | defaultAttrNameCase = "kebabCase", 55 | defaultTagNameCase = "kebabCase", 56 | }, 57 | inlayHints = true, 58 | diagnostics = true, 59 | codeLens = { 60 | showReferencesNotification = true, 61 | }, 62 | }, 63 | }, 64 | on_new_config = function(new_config, new_root_dir) 65 | new_config.init_options.typescript.tsdk = get_typescript_server_path(new_root_dir) 66 | end, 67 | settings = cssls.settings, 68 | } 69 | -------------------------------------------------------------------------------- /lua/config/lsp/servers/vtsls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | settings = { 3 | typescript = { 4 | inlayHints = { 5 | parameterNames = { enabled = "all" }, 6 | parameterTypes = { enabled = false }, 7 | variableTypes = { enabled = false }, 8 | propertyDeclarationTypes = { enabled = true }, 9 | functionLikeReturnTypes = { enabled = false }, 10 | enumMemberValues = { enabled = true }, 11 | }, 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /lua/config/plugins/aerial.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "stevearc/aerial.nvim", 3 | enabled = true, 4 | cond = not vim.g.vscode, 5 | event = "LspAttach", 6 | init = function() 7 | vim.keymap.set("n", "v", "AerialToggle") 8 | end, 9 | dependencies = { 10 | "nvim-treesitter/nvim-treesitter", 11 | "nvim-tree/nvim-web-devicons", 12 | }, 13 | config = function() 14 | -- vim.api.nvim_create_autocmd("WinEnter", { 15 | -- once = true, 16 | -- callback = function(event) 17 | -- local ft = vim.api.nvim_get_option_value("filetype", { buf = event.buf }) 18 | -- if ft == "aerial" then 19 | -- vim.api.nvim_feedkeys(vim.keycode("h"), "nit", true) 20 | -- local left_win = vim.api.nvim_get_current_win() 21 | -- -- vim.schedule(function() 22 | -- vim.api.nvim_feedkeys(vim.keycode("l"), "nit", true) 23 | -- -- end) 24 | -- print('WINDOW "LEFT" IS', left_win) 25 | -- end 26 | -- end, 27 | -- }) 28 | require("aerial").setup({ 29 | backends = { 30 | ["*"] = { "treesitter", "lsp", "markdown", "asciidoc", "man" }, 31 | markdown = { "treesitter", "markdown" }, 32 | }, 33 | layout = { 34 | width = 30, 35 | win_opts = { 36 | statuscolumn = " ", 37 | winhl = "Normal:NeoTreeNormal,WinBar:NeoTreeNormal", 38 | }, 39 | }, 40 | autojump = true, 41 | post_jump_cmd = "normal! zt", 42 | show_guides = true, 43 | }) 44 | end, 45 | } 46 | -------------------------------------------------------------------------------- /lua/config/plugins/autopairs.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "windwp/nvim-autopairs", 3 | enabled = true, 4 | cond = true, 5 | event = "InsertEnter", 6 | config = function() 7 | local autopairs = require("nvim-autopairs") 8 | local Rule = require("nvim-autopairs.rule") 9 | 10 | autopairs.setup({ 11 | fast_wrap = { map = "" }, 12 | disable_filetype = {}, 13 | disable_in_macro = false, 14 | disable_in_visualblock = false, 15 | ignored_next_char = [=[[%w%%%'%[%"%.]]=], 16 | enable_moveright = true, 17 | enable_afterquote = true, 18 | enable_check_bracket_line = true, 19 | enable_bracket_in_quote = true, 20 | break_undo = true, 21 | check_ts = true, 22 | map_cr = true, 23 | map_bs = true, 24 | map_c_h = true, 25 | map_c_w = false, -- to avoid breaking unix default behaviour 26 | }) 27 | 28 | autopairs.add_rules({ 29 | Rule(" ", " "):with_pair(function(opts) 30 | local pair = opts.line:sub(opts.col - 1, opts.col) 31 | return vim.tbl_contains({ "()", "[]", "{}" }, pair) 32 | end), 33 | Rule("|", "|", "rust"), 34 | }) 35 | end, 36 | } 37 | -------------------------------------------------------------------------------- /lua/config/plugins/bufferline.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "akinsho/bufferline.nvim", 3 | enabled = true, 4 | cond = not vim.g.vscode, 5 | -- version = "*", -- Using master while fix of `tbl_islist` is not added to release 6 | event = "VeryLazy", 7 | config = function() 8 | require("bufferline").setup({ 9 | options = { 10 | diagnostics = false, 11 | offsets = { 12 | { filetype = "neo-tree", text = "File Explorer" }, 13 | { filetype = "aerial", text = "Document Symbols" }, 14 | }, 15 | }, 16 | }) 17 | end, 18 | } 19 | -------------------------------------------------------------------------------- /lua/config/plugins/clonewin.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "Wansmer/clonewin.nvim", 3 | enabled = true, 4 | lazy = false, 5 | dev = true, 6 | cond = not vim.g.vscode, 7 | dir = "~/projects/code/personal/clonewin", 8 | config = function() 9 | require("clonewin.init").setup({ 10 | mappings = { 11 | [""] = "", 12 | [""] = "", 13 | [""] = "", 14 | [""] = "", 15 | [""] = "", 16 | }, 17 | }) 18 | end, 19 | } 20 | -------------------------------------------------------------------------------- /lua/config/plugins/codeium-nvim.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "Exafunction/codeium.nvim", 3 | enabled = false, 4 | event = { "BufReadPre" }, 5 | dependencies = { 6 | "nvim-lua/plenary.nvim", 7 | "hrsh7th/nvim-cmp", 8 | }, 9 | config = function() 10 | require("codeium").setup({ 11 | manager_path = nil, 12 | bin_path = vim.fn.stdpath("cache") .. "/codeium/bin", 13 | config_path = vim.fn.stdpath("cache") .. "/codeium/config.json", 14 | language_server_download_url = "https://github.com", 15 | api = { 16 | host = "server.codeium.com", 17 | port = "443", 18 | }, 19 | tools = {}, 20 | wrapper = nil, 21 | }) 22 | end, 23 | } 24 | -------------------------------------------------------------------------------- /lua/config/plugins/codeium.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "Exafunction/codeium.vim", 3 | event = "BufReadPre", 4 | enabled = false, 5 | config = function() 6 | vim.g.codeium_idle_delay = 250 7 | vim.g.codeium_disable_bindings = 1 8 | vim.g.codeium_no_map_tab = true 9 | vim.g.codeium_filetypes = { 10 | -- TODO: Or add trigger mapping to complete? 11 | ["neo-tree-popup"] = false, 12 | } 13 | local map = vim.keymap.set 14 | 15 | map("i", "", vim.fn["codeium#Accept"], { expr = true }) 16 | map("i", "", vim.fn["codeium#Complete"], { expr = true }) 17 | map("i", "", function() 18 | return vim.fn["codeium#CycleCompletions"](1) 19 | end, { expr = true }) 20 | map("i", "", function() 21 | return vim.fn["codeium#CycleCompletions"](-1) 22 | end, { expr = true }) 23 | -- TODO: conflict with cmp, find best map 24 | map("i", "", function() 25 | return vim.fn["codeium#Clear"]() 26 | end, { expr = true }) 27 | end, 28 | } 29 | -------------------------------------------------------------------------------- /lua/config/plugins/colorizer.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "catgoose/nvim-colorizer.lua", 3 | enabled = true, 4 | ft = { 5 | "vue", 6 | "javascript", 7 | "typescript", 8 | "javascriptreact", 9 | "typescriptreact", 10 | "lua", 11 | "css", 12 | "scss", 13 | }, 14 | config = function() 15 | require("colorizer").setup({ 16 | filetypes = { "css", "javascript", "javascriptreact", "lua", "scss", "typescript", "typescriptreact" }, 17 | user_default_options = { 18 | RGB = true, -- #RGB hex codes 19 | RRGGBB = true, -- #RRGGBB hex codes 20 | names = true, -- "Name" codes like Blue or blue 21 | RRGGBBAA = true, -- #RRGGBBAA hex codes 22 | AARRGGBB = true, -- 0xAARRGGBB hex codes 23 | rgb_fn = true, -- CSS rgb() and rgba() functions 24 | hsl_fn = true, -- CSS hsl() and hsla() functions 25 | css = true, -- Enable all CSS features: rgb_fn, hsl_fn, names, RGB, RRGGBB 26 | css_fn = true, -- Enable all CSS *functions*: rgb_fn, hsl_fn 27 | -- Available modes for `mode`: foreground, background, virtualtext 28 | mode = "virtualtext", -- Set the display mode. 29 | -- Available methods are false / true / "normal" / "lsp" / "both" 30 | -- True is same as normal 31 | tailwind = false, -- Enable tailwind colors 32 | -- parsers can contain values used in |user_default_options| 33 | sass = { 34 | enable = true, 35 | parsers = { "css" }, 36 | }, -- Enable sass colors 37 | virtualtext = "■", 38 | -- update color values even if buffer is not focused 39 | -- example use: cmp_menu, cmp_docs 40 | always_update = false, 41 | }, 42 | -- all the sub-options of filetypes apply to buftypes 43 | buftypes = {}, 44 | }) 45 | end, 46 | } 47 | -------------------------------------------------------------------------------- /lua/config/plugins/colorschemes.lua: -------------------------------------------------------------------------------- 1 | local function set_prior(c) 2 | c = type(c) == "table" and c or { c } 3 | c.priority = 1000 4 | return c 5 | end 6 | 7 | return vim.tbl_map(set_prior, { 8 | "yorickpeterse/nvim-grey", 9 | "Mofiqul/vscode.nvim", 10 | "dasupradyumna/midnight.nvim", 11 | "folke/tokyonight.nvim", 12 | "loctvl842/monokai-pro.nvim", 13 | "rebelot/kanagawa.nvim", 14 | "sainnhe/gruvbox-material", 15 | "sam4llis/nvim-tundra", 16 | "sho-87/kanagawa-paper.nvim", 17 | "webhooked/kanso.nvim", 18 | { 19 | "Wansmer/serenity.nvim", 20 | -- dev = false, 21 | -- dir = "~/projects/code/personal/serenity.nvim", 22 | name = "serenity", 23 | }, 24 | { "catppuccin/nvim", name = "catppuccin" }, 25 | { "neanias/everforest-nvim", version = false }, 26 | { "ramojus/mellifluous.nvim", dependencies = { "rktjmp/lush.nvim" } }, 27 | { "rose-pine/neovim", name = "rose-pine" }, 28 | }) 29 | -------------------------------------------------------------------------------- /lua/config/plugins/comment.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "numToStr/Comment.nvim", 3 | enabled = true, 4 | event = { "BufReadPre" }, 5 | dependencies = { 6 | { 7 | "JoosepAlviste/nvim-ts-context-commentstring", 8 | dependencies = { "nvim-treesitter/nvim-treesitter" }, 9 | }, 10 | }, 11 | config = function() 12 | -- to skip backwards compatibility routines and speed up loading 13 | vim.g.skip_ts_context_commentstring_module = true 14 | require("Comment").setup({ 15 | pre_hook = require("ts_context_commentstring.integrations.comment_nvim").create_pre_hook(), 16 | }) 17 | end, 18 | } 19 | -------------------------------------------------------------------------------- /lua/config/plugins/conform.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "stevearc/conform.nvim", 3 | enabled = true, 4 | cond = not vim.g.vscode, 5 | config = function() 6 | local js_formatter = { "prettier" } 7 | local sql = { 8 | "sqlfluff", 9 | "sql_formatter", 10 | stop_after_first = true, 11 | } 12 | 13 | require("conform").setup({ 14 | formatters_by_ft = { 15 | lua = { "stylua" }, 16 | javascript = js_formatter, 17 | javascriptreact = js_formatter, 18 | typescript = js_formatter, 19 | typescriptreact = js_formatter, 20 | vue = js_formatter, 21 | html = { "prettier" }, 22 | json = { "prettier" }, 23 | jsonc = { "prettier" }, 24 | markdown = { "prettier", "inject" }, 25 | toml = { "prettier" }, 26 | sh = { "shfmt" }, 27 | python = { "isort", "black" }, 28 | mysql = sql, 29 | sql = sql, 30 | psql = sql, 31 | pgsql = sql, 32 | }, 33 | }) 34 | end, 35 | } 36 | -------------------------------------------------------------------------------- /lua/config/plugins/databases.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { "nanotee/sqls.nvim" }, 3 | { 4 | "Wansmer/nvim-dbee", 5 | lazy = false, 6 | dir = "~/projects/code/personal/nvim-dbee", 7 | dev = true, 8 | dependencies = { "MunifTanjim/nui.nvim" }, 9 | build = function() 10 | require("dbee").install() 11 | end, 12 | config = function() 13 | local assets = vim.fs.joinpath(vim.fn.stdpath("config")--[[@as string]], "/sql") 14 | require("dbee").setup({ 15 | editor = { 16 | directory = assets, 17 | }, 18 | sources = { 19 | require("dbee.sources").FileSource:new(vim.fs.joinpath(assets, "persistence.json")), 20 | }, 21 | }) 22 | end, 23 | }, 24 | { 25 | "kristijanhusak/vim-dadbod-ui", 26 | dependencies = { 27 | { "tpope/vim-dadbod", lazy = true }, 28 | { 29 | "kristijanhusak/vim-dadbod-completion", 30 | ft = { "sql", "mysql", "plsql" }, 31 | lazy = true, 32 | }, 33 | }, 34 | cmd = { 35 | "DBUI", 36 | "DBUIToggle", 37 | "DBUIAddConnection", 38 | "DBUIFindBuffer", 39 | }, 40 | init = function() 41 | vim.g.db_ui_use_nerd_fonts = 1 42 | -- vim.g.dbs = {} 43 | end, 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /lua/config/plugins/devdocs.lua: -------------------------------------------------------------------------------- 1 | -- Don't forget to call `:DevdocsFetch` during the first installation. 2 | return { 3 | "luckasRanarison/nvim-devdocs", 4 | enabled = true, 5 | event = "VeryLazy", 6 | dependencies = { 7 | "nvim-lua/plenary.nvim", 8 | "nvim-telescope/telescope.nvim", 9 | "nvim-treesitter/nvim-treesitter", 10 | }, 11 | config = function() 12 | require("nvim-devdocs").setup({ 13 | ensure_installed = { 14 | "rust", 15 | "javascript", 16 | "vue~3", 17 | "go", 18 | "lua~5.3", 19 | "html", 20 | "css", 21 | }, 22 | }) 23 | end, 24 | } 25 | -------------------------------------------------------------------------------- /lua/config/plugins/dial.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "monaqa/dial.nvim", 3 | event = "BufReadPre", 4 | config = function() 5 | local map = vim.keymap.set 6 | local action = require("dial.map").manipulate 7 | 8 | map("n", "", function() 9 | action("increment", "normal") 10 | end) 11 | map("n", "", function() 12 | action("decrement", "normal") 13 | end) 14 | map("n", "g", function() 15 | action("increment", "gnormal") 16 | end) 17 | map("n", "g", function() 18 | action("decrement", "gnormal") 19 | end) 20 | map("v", "", function() 21 | action("increment", "visual") 22 | end) 23 | map("v", "", function() 24 | action("decrement", "visual") 25 | end) 26 | map("v", "g", function() 27 | action("increment", "gvisual") 28 | end) 29 | map("v", "g", function() 30 | action("decrement", "gvisual") 31 | end) 32 | end, 33 | } 34 | -------------------------------------------------------------------------------- /lua/config/plugins/flash.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/flash.nvim", 3 | enabled = true, 4 | event = "VeryLazy", 5 | keys = { 6 | { 7 | "", 8 | mode = { "c" }, 9 | function() 10 | require("flash").toggle() 11 | end, 12 | desc = "Toggle Flash Search", 13 | }, 14 | }, 15 | config = function() 16 | require("flash").setup({ 17 | search = { 18 | multi_window = false, 19 | exclude = { 20 | "notify", 21 | "cmp_menu", 22 | "noice", 23 | "flash_prompt", 24 | "neo-tree", 25 | function(win) 26 | -- exclude non-focusable windows 27 | return not vim.api.nvim_win_get_config(win).focusable 28 | end, 29 | }, 30 | }, 31 | modes = { 32 | search = { enabled = true }, 33 | char = { enabled = false }, 34 | }, 35 | }) 36 | end, 37 | } 38 | -------------------------------------------------------------------------------- /lua/config/plugins/git-dev.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "moyiz/git-dev.nvim", 3 | event = "VeryLazy", 4 | config = function() 5 | local gdev = require("git-dev") 6 | gdev.setup({ 7 | cd_type = "tab", 8 | opener = function(dir) 9 | local to_open = vim 10 | .iter({ "README.md", "readme.md", "README", "README.txt", "readme.txt" }) 11 | :map(function(f) 12 | return vim.fs.joinpath(dir, f) 13 | end) 14 | :find(vim.uv.fs_stat) 15 | 16 | local cmd = to_open and "e " .. to_open .. " | Neotree show" or "Neotree dir=" .. dir 17 | vim.cmd("tabnew | " .. cmd) 18 | end, 19 | }) 20 | 21 | vim.keymap.set("n", "gx", function() 22 | local url = vim.fn.expand("") 23 | if not url or url == "" then 24 | return 25 | end 26 | 27 | local gdev_path = vim.fn.stdpath("cache") .. "/git-dev" 28 | local is_gdev = vim.startswith(vim.fn.expand("%:p"), gdev_path) 29 | local opener = is_gdev and vim.bo.filetype == "markdown" and gdev.open or vim.ui.open 30 | opener(url) 31 | end) 32 | 33 | vim.keymap.set("n", "gX", function() 34 | local url = vim.fn.expand("") 35 | if not url or url == "" then 36 | return 37 | end 38 | 39 | vim.ui.select( 40 | { "Default opener (`vim.ui.open()`)", "GitDev (`git-dev.open()`)" }, 41 | { prompt = "Select opener" }, 42 | function(choice) 43 | local opener = choice == "GitDev (`git-dev.open()`)" and gdev.open or vim.ui.open 44 | opener(url) 45 | end 46 | ) 47 | end) 48 | end, 49 | } 50 | -------------------------------------------------------------------------------- /lua/config/plugins/gitsigns.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "lewis6991/gitsigns.nvim", 3 | event = "BufReadPost", 4 | enabled = true, 5 | config = function() 6 | local map = vim.keymap.set 7 | map("n", "gp", ":Gitsigns prev_hunk", { desc = "Plug Gitsigns: jump to prev hunk" }) 8 | map("n", "gn", ":Gitsigns next_hunk", { desc = "Plug Gitsigns: jump to next hunk" }) 9 | map("n", "gs", ":Gitsigns preview_hunk", { desc = "Plug Gitsigns: preview hunk" }) 10 | map("n", "gd", ":Gitsigns diffthis", { desc = "Plug Gitsigns: open diffmode" }) 11 | map("n", "ga", ":Gitsigns stage_hunk", { desc = "Plug Gitsigns: stage current hunk" }) 12 | map("n", "gr", ":Gitsigns reset_hunk", { desc = "Plug Gitsigns: reset current hunk" }) 13 | map("n", "gA", ":Gitsigns stage_buffer", { desc = "Plug Gitsigns: stage current buffer" }) 14 | map("n", "gR", ":Gitsigns reset_buffer", { desc = "Plug Gitsigns: reset current buffer" }) 15 | 16 | require("gitsigns").setup({ 17 | signs = { 18 | -- text = "│", 19 | add = { text = "┃" }, 20 | change = { text = "┃" }, 21 | delete = { text = "_" }, 22 | topdelete = { text = "‾" }, 23 | changedelete = { text = "~" }, 24 | untracked = { text = "┆" }, 25 | }, 26 | signcolumn = PREF.git.show_signcolumn, -- Toggle with `:Gitsigns toggle_signs` 27 | current_line_blame = PREF.git.show_blame, 28 | current_line_blame_opts = { 29 | virt_text = true, 30 | virt_text_pos = "eol", -- 'eol' | 'overlay' | 'right_align' 31 | delay = 500, 32 | }, 33 | }) 34 | end, 35 | } 36 | -------------------------------------------------------------------------------- /lua/config/plugins/glance.lua: -------------------------------------------------------------------------------- 1 | local map = vim.keymap.set 2 | 3 | vim.api.nvim_create_autocmd("LspAttach", { 4 | desc = "Set Glance.nvim mappings", 5 | callback = function(event) 6 | -- `defer_fn` here because must be set after `on_attach` lsp-config method 7 | vim.defer_fn(function() 8 | if vim.api.nvim_buf_is_valid(event.buf) then 9 | map("n", "gd", "Glance definitions", { 10 | buffer = event.buf, 11 | desc = "Glance definitions", 12 | }) 13 | map("n", "gi", "Glance implementations", { 14 | buffer = event.buf, 15 | desc = "Glance implementations", 16 | }) 17 | map("n", "gr", "Glance references", { 18 | buffer = event.buf, 19 | desc = "Glance references", 20 | }) 21 | vim.keymap.set("n", "go", "Glance type_definitions", { 22 | buffer = event.buf, 23 | desc = "Glance type definitions", 24 | }) 25 | end 26 | end, 100) 27 | end, 28 | }) 29 | 30 | return { 31 | "dnlhc/glance.nvim", 32 | enabled = true, 33 | event = "LspAttach", 34 | config = function() 35 | local actions = require("glance").actions 36 | 37 | require("glance").setup({ 38 | border = { 39 | enable = true, -- Show window borders. Only horizontal borders allowed 40 | top_char = "―", 41 | bottom_char = "―", 42 | }, 43 | preview_win_opts = { -- Configure preview window options 44 | cursorline = false, 45 | number = true, 46 | wrap = true, 47 | statuscolumn = " %=%l ", 48 | }, 49 | theme = { -- This feature might not work properly in nvim-0.7.2 50 | enable = true, -- Will generate colors for the plugin based on your current colorscheme 51 | mode = "brighten", -- 'brighten'|'darken'|'auto', 'auto' will set mode based on the brightness of your colorscheme 52 | }, 53 | mappings = { 54 | list = { 55 | ["j"] = actions.next, -- Bring the cursor to the next item in the list 56 | ["k"] = actions.previous, -- Bring the cursor to the previous item in the list 57 | [""] = actions.next, -- Bring the cursor to the next item in the list 58 | [""] = actions.previous, -- Bring the cursor to the previous item in the list 59 | [""] = actions.next, 60 | [""] = actions.previous, 61 | [""] = actions.next_location, -- Bring the cursor to the next location skipping groups in the list 62 | [""] = actions.previous_location, -- Bring the cursor to the previous location skipping groups in the list 63 | [""] = actions.preview_scroll_win(5), 64 | [""] = actions.preview_scroll_win(-5), 65 | [""] = actions.jump_vsplit, 66 | [""] = actions.jump_split, 67 | ["t"] = actions.jump_tab, 68 | [""] = actions.jump, 69 | ["o"] = actions.jump, 70 | ["l"] = actions.open_fold, 71 | ["h"] = actions.close_fold, 72 | [""] = actions.enter_win("preview"), -- Focus preview window 73 | ["q"] = actions.close, 74 | ["Q"] = actions.close, 75 | [""] = actions.close, 76 | [""] = actions.close, 77 | [""] = actions.quickfix, 78 | -- [''] = false -- disable a mapping 79 | }, 80 | preview = { 81 | ["Q"] = actions.close, 82 | [""] = actions.next_location, 83 | [""] = actions.previous_location, 84 | [""] = actions.enter_win("list"), -- Focus list window 85 | }, 86 | hooks = {}, 87 | }, 88 | winbar = { 89 | enable = true, -- Available strating from nvim-0.8+ 90 | }, 91 | }) 92 | end, 93 | } 94 | -------------------------------------------------------------------------------- /lua/config/plugins/go.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "ray-x/go.nvim", 3 | enabled = true, 4 | dependencies = { -- optional packages 5 | "ray-x/guihua.lua", 6 | "neovim/nvim-lspconfig", 7 | "nvim-treesitter/nvim-treesitter", 8 | }, 9 | config = function() 10 | require("go").setup({ 11 | diagnostic = false, -- Not change diagnostic config by this plugin 12 | lsp_inlay_hints = { enable = false }, -- Disable setting inlay hints through the plugin 13 | }) 14 | end, 15 | event = { "CmdlineEnter" }, 16 | ft = { "go", "gomod" }, 17 | build = ':lua require("go.install").update_all_sync()', -- if you need to install/update all binaries 18 | } 19 | -------------------------------------------------------------------------------- /lua/config/plugins/grug-far.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "MagicDuck/grug-far.nvim", 3 | enabled = true, 4 | keys = { 5 | { 6 | "r", 7 | function() 8 | require("grug-far").open() 9 | end, 10 | desc = "grug-far: open", 11 | }, 12 | { 13 | "R", 14 | function() 15 | require("grug-far").open({ prefills = { search = vim.fn.expand("") } }) 16 | end, 17 | desc = "grug-far: open", 18 | }, 19 | }, 20 | config = function() 21 | require("grug-far").setup({}) 22 | end, 23 | } 24 | -------------------------------------------------------------------------------- /lua/config/plugins/hardtime.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "m4xshen/hardtime.nvim", 3 | event = "VeryLazy", 4 | enabled = false, 5 | dependencies = { "MunifTanjim/nui.nvim", "nvim-lua/plenary.nvim" }, 6 | config = function() 7 | require("hardtime").setup({ 8 | disable_mouse = false, 9 | debug = false, 10 | restricted_keys = { 11 | [""] = {}, 12 | [""] = {}, 13 | }, 14 | }) 15 | end, 16 | } 17 | -------------------------------------------------------------------------------- /lua/config/plugins/illuminate.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "RRethy/vim-illuminate", 3 | event = "BufReadPost", 4 | enabled = true, 5 | config = function() 6 | require("illuminate").configure({ 7 | filetypes_denylist = { "alpha", "neo-tree", "toggleterm", "aerial" }, 8 | min_count_to_highlight = 2, 9 | }) 10 | 11 | if vim.g.colors_name ~= "serenity" then 12 | vim.api.nvim_set_hl(0, "IlluminatedWordText", { link = "Visual" }) 13 | vim.api.nvim_set_hl(0, "IlluminatedWordRead", { link = "Visual" }) 14 | vim.api.nvim_set_hl(0, "IlluminatedWordWrite", { link = "Visual" }) 15 | end 16 | end, 17 | } 18 | -------------------------------------------------------------------------------- /lua/config/plugins/image.lua: -------------------------------------------------------------------------------- 1 | -- Install magick: luarocks --local --lua-version=5.1 install magick 2 | return { 3 | "3rd/image.nvim", 4 | enabled = function() 5 | local uv = vim.fn.has("nvim-0.10") == 1 and vim.uv or vim.loop 6 | local is_exist = uv.fs_stat(vim.fn.expand("$HOME") .. "/.luarocks/share/lua/5.1/magick/init.lua") ~= nil 7 | 8 | local function info(reason) 9 | vim.notify( 10 | ('Dependency of `3rd/image.nvim` luarock `magick` problem: "%s".\nPlugin will not be load.'):format(reason), 11 | vim.log.levels.INFO, 12 | { title = "Image.nvim" } 13 | ) 14 | end 15 | 16 | if not is_exist then 17 | info("not found at $HOME/.luarocks/share/lua/5.1/magick/init.lua") 18 | else 19 | package.path = package.path .. ";" .. vim.fn.expand("$HOME") .. "/.luarocks/share/lua/5.1/?/init.lua;" 20 | package.path = package.path .. ";" .. vim.fn.expand("$HOME") .. "/.luarocks/share/lua/5.1/?.lua;" 21 | 22 | local ok, msg = pcall(require, "magick") 23 | if not ok then 24 | -- Check this issue: https://github.com/3rd/image.nvim/issues/18?ysclid=lqf4h2y9hh666904664#issuecomment-1774962882 25 | is_exist = false 26 | info(msg) 27 | end 28 | end 29 | return is_exist 30 | end, 31 | event = "VeryLazy", 32 | config = function() 33 | require("image").setup({ 34 | backend = "kitty", 35 | -- integrations = { markdown = { enabled = false } }, 36 | integrations = {}, 37 | max_width = 100, 38 | max_height_window_percentage = math.huge, 39 | max_width_window_percentage = math.huge, 40 | window_overlap_clear_enabled = true, 41 | window_overlap_clear_ft_ignore = { "cmp_menu", "cmp_docs", "" }, 42 | }) 43 | 44 | local function has_image(id) 45 | local images = require("image").get_images() 46 | for _, image in ipairs(images) do 47 | if image.id == id then 48 | return true, image 49 | end 50 | end 51 | return false, nil 52 | end 53 | 54 | vim.api.nvim_create_autocmd("BufEnter", { 55 | pattern = "*.png,*.jpg,*.jpeg,*.gif,*.webp,*.pdf", 56 | callback = function(event) 57 | local ok, api = pcall(require, "image") 58 | if not ok then 59 | return 60 | end 61 | 62 | local has, img = has_image(event.file) 63 | if has and img then 64 | vim.schedule(function() 65 | img:render() 66 | end) 67 | return 68 | end 69 | 70 | local win = vim.api.nvim_get_current_win() 71 | local buf = vim.api.nvim_create_buf(true, true) 72 | vim.api.nvim_win_set_buf(win, buf) 73 | vim.cmd("bw " .. event.buf) 74 | vim.api.nvim_buf_set_name(buf, event.file) 75 | 76 | local image = api.from_file(event.file, { id = event.file, buffer = buf, window = win }) 77 | if not image then 78 | return 79 | end 80 | vim.schedule(function() 81 | image:render() 82 | end) 83 | 84 | vim.api.nvim_create_autocmd({ "BufHidden", "BufDelete", "BufUnload", "WinClosed" }, { 85 | buffer = buf, 86 | callback = function() 87 | image:clear() 88 | end, 89 | }) 90 | end, 91 | }) 92 | end, 93 | } 94 | -------------------------------------------------------------------------------- /lua/config/plugins/incline.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "b0o/incline.nvim", 3 | enabled = false, 4 | event = "VeryLazy", 5 | config = function() 6 | require("incline").setup() 7 | end, 8 | } 9 | -------------------------------------------------------------------------------- /lua/config/plugins/init.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "nvim-lua/plenary.nvim", 4 | enabled = true, 5 | }, 6 | { 7 | "nvim-tree/nvim-web-devicons", 8 | enabled = true, 9 | }, 10 | { 11 | "echasnovski/mini.splitjoin", 12 | enabled = true, 13 | config = function() 14 | require("mini.splitjoin").setup() 15 | end, 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /lua/config/plugins/iron.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "Vigemus/iron.nvim", 3 | keys = { 4 | { "tr", vim.cmd.IronRepl, desc = "󱠤 Toggle REPL" }, 5 | { "rr", vim.cmd.IronRestart, desc = "󱠤 Restart REPL" }, 6 | { "u", mode = { "n", "x" }, desc = "󱠤 Send-to-REPL Operator" }, 7 | }, 8 | config = function() 9 | require("iron.core").setup({ 10 | keymaps = { 11 | send_line = "u", 12 | visual_send = "u", 13 | }, 14 | config = { 15 | repl_open_cmd = "horizontal bot 20 split", 16 | repl_definition = { 17 | python = { 18 | command = function() 19 | local ipythonAvailable = vim.fn.executable("ipython") == 1 20 | local binary = ipythonAvailable and "ipython" or "python3" 21 | return { binary } 22 | end, 23 | }, 24 | }, 25 | }, 26 | }) 27 | end, 28 | } 29 | -------------------------------------------------------------------------------- /lua/config/plugins/key-analizer.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "meznaric/key-analyzer.nvim", 3 | cmd = "KeyAnalyzer", 4 | config = function() 5 | require("key-analyzer").setup() 6 | end, 7 | } 8 | -------------------------------------------------------------------------------- /lua/config/plugins/langmapper.lua: -------------------------------------------------------------------------------- 1 | local DEV = false 2 | 3 | return { 4 | "Wansmer/langmapper.nvim", 5 | enabled = true, 6 | lazy = false, 7 | dir = DEV and "~/projects/code/personal/langmapper.nvim" or nil, 8 | dev = DEV, 9 | config = function() 10 | local lm = require("langmapper") 11 | lm.setup() 12 | lm.hack_get_keymap() 13 | end, 14 | } 15 | -------------------------------------------------------------------------------- /lua/config/plugins/lazydev.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/lazydev.nvim", 3 | ft = "lua", 4 | dependencies = { 5 | "neovim/nvim-lspconfig", 6 | { "Bilal2453/luvit-meta", lazy = true }, 7 | }, 8 | config = function() 9 | require("lazydev").setup({ 10 | library = { 11 | "luvit-meta/library", 12 | }, 13 | }) 14 | end, 15 | } 16 | -------------------------------------------------------------------------------- /lua/config/plugins/lint.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "mfussenegger/nvim-lint", 3 | enabled = true, 4 | event = { "VeryLazy" }, 5 | config = function() 6 | local lint = require("lint") 7 | ---@type "eslint_d"|"eslint" 8 | -- local js_linter = "eslint" 9 | 10 | local linters = lint.linters 11 | linters.sqlfluff.args = { "lint", "--format=json" } 12 | 13 | lint.linters_by_ft = { 14 | -- javascript = { js_linter }, 15 | -- javascriptreact = { { js_linter } }, 16 | -- typescript = { js_linter }, 17 | -- typescriptreact = { js_linter }, 18 | vue = { 19 | -- js_linter, 20 | "stylelint", 21 | }, 22 | html = { "tidy" }, 23 | css = { "stylelint" }, 24 | scss = { "stylelint" }, 25 | less = { "stylelint" }, 26 | yml = { "ansible-lint" }, 27 | sql = { "sqlfluff" }, 28 | mysql = { "sqlfluff" }, 29 | } 30 | 31 | vim.api.nvim_create_autocmd({ "BufWritePost", "BufReadPost", "InsertLeave" }, { 32 | callback = function() 33 | local ok, msg = pcall(lint.try_lint) 34 | -- if not ok then 35 | -- vim.notify(msg, vim.log.levels.WARN, { title = "Nvim-Lint" }) 36 | -- end 37 | end, 38 | }) 39 | end, 40 | } 41 | -------------------------------------------------------------------------------- /lua/config/plugins/live-rename.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "saecki/live-rename.nvim", 3 | dev = true, 4 | dir = "~/projects/code/hub/live-rename.nvim", 5 | enabled = true, 6 | event = { "LspAttach" }, 7 | config = function() 8 | require("live-rename").setup({ 9 | keys = { 10 | cancel = { 11 | { "i", "" }, 12 | { "i", "" }, 13 | }, 14 | }, 15 | }) 16 | end, 17 | } 18 | -------------------------------------------------------------------------------- /lua/config/plugins/lsp-fs-op.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "antosha417/nvim-lsp-file-operations", 3 | enabled = true, 4 | event = { "LspAttach" }, 5 | dependencies = { 6 | "nvim-lua/plenary.nvim", 7 | "nvim-neo-tree/neo-tree.nvim", 8 | }, 9 | config = function() 10 | require("lsp-file-operations").setup() 11 | end, 12 | } 13 | -------------------------------------------------------------------------------- /lua/config/plugins/lspconfig.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "neovim/nvim-lspconfig", 3 | enabled = true, 4 | event = { "BufReadPre" }, 5 | dependencies = { 6 | "b0o/SchemaStore.nvim", 7 | "hrsh7th/cmp-nvim-lsp", 8 | "mason.nvim", 9 | "williamboman/mason-lspconfig.nvim", 10 | }, 11 | config = function() 12 | require("config.lsp") 13 | end, 14 | } 15 | -------------------------------------------------------------------------------- /lua/config/plugins/ltex-extra.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "barreiroleo/ltex-extra.nvim", 3 | enabled = true, 4 | } 5 | -------------------------------------------------------------------------------- /lua/config/plugins/madol.lua: -------------------------------------------------------------------------------- 1 | -- https://gitlab.com/repetitivesin/madol.nvim/-/blob/main/snippet-index.md 2 | return { 3 | "https://gitlab.com/repetitivesin/madol.nvim", 4 | ft = { "markdown", "tex", "quarto" }, 5 | dependencies = { "L3MON4D3/LuaSnip", "nvim-treesitter/nvim-treesitter" }, 6 | config = function() 7 | require("madol").setup() 8 | local ls = require("luasnip") 9 | ls.config.setup({ 10 | enable_autosnippets = true, 11 | store_selection_keys = "", 12 | }) 13 | local map = vim.keymap.set 14 | 15 | map({ "s", "i" }, "", function() 16 | if ls.choice_active() then 17 | ls.change_choice(1) 18 | else 19 | return "" 20 | end 21 | end, { silent = true }) 22 | map({ "s", "i" }, "", function() 23 | if ls.choice_active() then 24 | ls.change_choice(-1) 25 | else 26 | return "" 27 | end 28 | end, { silent = true }) 29 | map({ "i", "s" }, "", function() 30 | ls.jump(1) 31 | end, { silent = true }) 32 | map({ "i", "s" }, "", function() 33 | ls.jump(-1) 34 | end, { silent = true }) 35 | end, 36 | } 37 | -------------------------------------------------------------------------------- /lua/config/plugins/mason-lspconfig.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "williamboman/mason-lspconfig.nvim", 3 | enabled = true, 4 | lazy = true, 5 | dependencies = { 6 | "williamboman/mason.nvim", 7 | "neovim/nvim-lspconfig", 8 | }, 9 | config = function() 10 | local ensure_installed = vim 11 | .iter(PREF.lsp.active_servers) 12 | :filter(function(_, v) 13 | return v 14 | end) 15 | :fold({}, function(acc, k, v) 16 | table.insert(acc, k) 17 | return acc 18 | end) 19 | 20 | require("mason-lspconfig").setup({ 21 | ensure_installed = ensure_installed, 22 | automatic_installation = true, 23 | }) 24 | end, 25 | } 26 | -------------------------------------------------------------------------------- /lua/config/plugins/mason.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "williamboman/mason.nvim", 3 | enabled = true, 4 | event = "UIEnter", 5 | config = function() 6 | require("mason").setup({ 7 | ui = { 8 | -- border = PREF.ui.border, 9 | height = 0.8, 10 | weight = 0.8, 11 | }, 12 | }) 13 | end, 14 | } 15 | -------------------------------------------------------------------------------- /lua/config/plugins/mdpreview.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "iamcco/markdown-preview.nvim", 3 | enabled = true, 4 | build = "cd app && npm install && git restore .", 5 | ft = { "markdown" }, 6 | config = function() 7 | local map = vim.keymap.set 8 | local TITLE = "md_preview" 9 | local cmd = "kitty @ launch --dont-take-focus --title " .. TITLE .. " --bias 45 awrit " 10 | 11 | local is_open = false 12 | -- Based on https://github.com/iamcco/markdown-preview.nvim/issues/363#issuecomment-2424574202 13 | vim.api.nvim_exec2( 14 | ([[ 15 | function MkdpBrowserFn(url) 16 | execute "silent ! %s" . a:url 17 | endfunction 18 | ]]):format(cmd), 19 | {} 20 | ) 21 | 22 | local function close_preview() 23 | vim.system({ 24 | "kitty", 25 | "@", 26 | "close-window", 27 | "--match=title:" .. TITLE, 28 | }) 29 | end 30 | 31 | local function open_preview() 32 | vim.cmd("MarkdownPreview") 33 | end 34 | 35 | local function toggle_preview() 36 | if is_open then 37 | close_preview() 38 | is_open = false 39 | else 40 | open_preview() 41 | is_open = true 42 | end 43 | end 44 | 45 | vim.g.mkdp_theme = "dark" 46 | vim.g.mkdp_filetypes = { "markdown" } 47 | vim.g.mkdp_browserfunc = "MkdpBrowserFn" 48 | 49 | vim.api.nvim_create_autocmd({ "BufDelete", "VimLeavePre" }, { 50 | pattern = "*", 51 | callback = close_preview, 52 | }) 53 | 54 | map("n", "p", toggle_preview, { silent = true }) 55 | map("n", "", function() 56 | vim 57 | .system({ "kitten", "@", "resize-window", "--match=id:" .. vim.fn.getenv("KITTY_WINDOW_ID"), "--increment=4" }) 58 | :wait() 59 | vim.cmd.redraw() 60 | end) 61 | map("n", "", function() 62 | vim.system({ "kitten", "@", "resize-window", "--match=id:" .. vim.env.KITTY_WINDOW_ID, "--increment=-4" }):wait() 63 | vim.cmd.redraw() 64 | end) 65 | end, 66 | } 67 | -------------------------------------------------------------------------------- /lua/config/plugins/neocodium.lua: -------------------------------------------------------------------------------- 1 | local DEV = false 2 | 3 | return { 4 | "Wansmer/neocodeium", 5 | enabled = true, 6 | cond = not vim.g.vscode, 7 | dir = DEV and "~/projects/code/personal/neocodeium" or nil, 8 | dev = DEV, 9 | event = "VeryLazy", 10 | config = function() 11 | local cdm = require("neocodeium") 12 | cdm.setup({ 13 | silent = true, 14 | show_label = false, 15 | filetypes = { 16 | DressingInput = false, 17 | TelescopePrompt = false, 18 | ["dap-repl"] = false, 19 | }, 20 | }) 21 | 22 | local map = vim.keymap.set 23 | 24 | map("i", "", cdm.accept) 25 | map("i", "", function() 26 | cdm.cycle_or_complete(1) 27 | end) 28 | map("i", "", function() 29 | cdm.cycle_or_complete(-1) 30 | end) 31 | 32 | map("i", "", cdm.clear) 33 | map("i", "", cdm.accept_word) 34 | map("i", "", cdm.accept_line) 35 | end, 36 | } 37 | -------------------------------------------------------------------------------- /lua/config/plugins/neogen.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "danymat/neogen", 3 | enabled = true, 4 | cmd = "Neogen", 5 | keys = { "a" }, 6 | config = function() 7 | vim.keymap.set("n", "a", ":Neogen") 8 | require("neogen").setup({ 9 | snippet_engine = "luasnip", 10 | languages = { 11 | lua = { 12 | template = { 13 | annotation_convention = "emmylua", 14 | }, 15 | }, 16 | }, 17 | }) 18 | end, 19 | } 20 | -------------------------------------------------------------------------------- /lua/config/plugins/neotest.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "nvim-neotest/neotest", 3 | enabled = true, 4 | lazy = true, 5 | dependencies = { 6 | "nvim-neotest/nvim-nio", 7 | "nvim-lua/plenary.nvim", 8 | "antoinemadec/FixCursorHold.nvim", 9 | "nvim-treesitter/nvim-treesitter", 10 | "marilari88/neotest-vitest", 11 | }, 12 | init = function() 13 | local map = vim.keymap.set 14 | map("n", "nt", function() 15 | require("neotest").run.run() 16 | end, { desc = "Run nearest test" }) 17 | map("n", "nf", function() 18 | require("neotest").run.run(vim.fn.expand("%")) 19 | end, { desc = "Run current file" }) 20 | map("n", "no", function() 21 | require("neotest").output.open({ enter = true }) 22 | end, { desc = "Open test output window" }) 23 | end, 24 | config = function() 25 | require("neotest").setup({ 26 | adapters = { 27 | require("neotest-vitest"), 28 | }, 29 | }) 30 | end, 31 | } 32 | -------------------------------------------------------------------------------- /lua/config/plugins/neowords.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "backdround/pattern-iterator.nvim", 4 | enabled = false, 5 | }, 6 | { 7 | "backdround/neowords.nvim", 8 | event = "BufRead", 9 | enabled = false, 10 | config = function() 11 | local u = require("utils") 12 | local neowords = require("neowords") 13 | local map = vim.keymap.set 14 | 15 | local p = neowords.pattern_presets 16 | local patterns = { p.snake_case, p.camel_case, p.upper_case, p.number, p.hex_color } 17 | local subword_hops = neowords.get_word_hops(unpack(patterns)) 18 | 19 | map({ "n", "x", "o" }, "w", subword_hops.forward_start) 20 | map({ "n", "x", "o" }, "e", subword_hops.forward_end) 21 | map({ "n", "x", "o" }, "b", subword_hops.backward_start) 22 | map({ "n", "x", "o" }, "ge", subword_hops.backward_end) 23 | 24 | local pit = require("pattern-iterator") 25 | local patt = vim.fn.join({ "\\v(", vim.fn.join(patterns, "\\v|"), "\\v)" }, "") 26 | 27 | --- Set visual selection to current word 28 | local function select_word() 29 | local it = pit.new_around(patt, {}) 30 | if not it then 31 | return 32 | end 33 | 34 | it:start_position():set_cursor() 35 | it:start_position():select_region_to(it:end_position()) 36 | end 37 | 38 | ---WARNING: this is not dot-repeatable by default. Not usable for ciw, diw without tune 39 | ---Run operatror on selected word 40 | ---@param operator string g, c, y, ~, g~, etc 41 | ---@return function 42 | local function action_on_selected(operator) 43 | return function() 44 | select_word() 45 | vim.api.nvim_feedkeys(operator, "ni", false) 46 | end 47 | end 48 | 49 | ---Replace selected word with new text 50 | ---@param lines? string[] 51 | local function replace_selected(lines) 52 | lines = lines or { "" } 53 | select_word() 54 | 55 | local sr, sc, er, ec = u.to_api_range(u.get_visual_range()) 56 | if ec == 1 then 57 | ec = 0 58 | end 59 | 60 | vim.api.nvim_buf_set_text(0, sr, sc, er, ec, lines) 61 | vim.api.nvim_feedkeys(vim.keycode(""), "nix", false) 62 | end 63 | 64 | local function ciw() 65 | action_on_selected("c")() 66 | 67 | vim.api.nvim_create_autocmd("ModeChanged", { 68 | pattern = "i:*", 69 | once = true, 70 | callback = function() 71 | local text = vim.fn.getreg(".") 72 | _G["__ciw__"] = vim.schedule_wrap(function() 73 | u.dot_repeat(true, replace_selected, vim.split(text, "\n")) 74 | end) 75 | 76 | vim.opt.operatorfunc = "v:lua." .. "__ciw__" 77 | vim.api.nvim_feedkeys(vim.v.count1 .. "g@l", "nix", true) 78 | end, 79 | }) 80 | end 81 | 82 | map("n", "ciw", ciw) 83 | map("n", "diw", function() 84 | u.dot_repeat(false, replace_selected) 85 | end) 86 | 87 | -- Use diW, ciW like default diw, ciw 88 | map("n", "ciW", "ciw") 89 | map("n", "diW", "diw") 90 | 91 | -- map("n", "yiw", action_on_selected("y")) 92 | map("n", "viw", select_word) 93 | end, 94 | }, 95 | } 96 | -------------------------------------------------------------------------------- /lua/config/plugins/notifier.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "vigoux/notifier.nvim", 3 | event = "VeryLazy", 4 | enabled = false, 5 | config = function() 6 | require("notifier").setup({ 7 | -- You configuration here 8 | }) 9 | end, 10 | } 11 | -------------------------------------------------------------------------------- /lua/config/plugins/notify.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "rcarriga/nvim-notify", 3 | -- event = "VeryLazy", 4 | lazy = false, 5 | priority = 1, 6 | enabled = true, 7 | config = function() 8 | local notify = require("notify") 9 | vim.notify = notify 10 | end, 11 | } 12 | -------------------------------------------------------------------------------- /lua/config/plugins/nvim-ts-autotag.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "windwp/nvim-ts-autotag", 3 | event = "BufEnter", 4 | enabled = true, 5 | dependencies = { "nvim-treesitter/nvim-treesitter" }, 6 | config = function() 7 | require("nvim-ts-autotag").setup() 8 | end, 9 | } 10 | -------------------------------------------------------------------------------- /lua/config/plugins/oil.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "stevearc/oil.nvim", 3 | enabled = true, 4 | cmd = "Oil", 5 | dependencies = { "nvim-tree/nvim-web-devicons" }, 6 | config = function() 7 | require("oil").setup({ 8 | keymaps = { 9 | ["g?"] = "actions.show_help", 10 | [""] = "actions.select", 11 | [""] = "actions.select_vsplit", 12 | [""] = "actions.select_split", 13 | [""] = "actions.preview", 14 | [""] = "actions.close", 15 | [""] = "actions.refresh", 16 | ["-"] = "actions.parent", 17 | ["_"] = "actions.open_cwd", 18 | ["`"] = "actions.cd", 19 | ["~"] = "actions.tcd", 20 | ["gs"] = "actions.change_sort", 21 | ["gx"] = "actions.open_external", 22 | ["g."] = "actions.toggle_hidden", 23 | ["g\\"] = "actions.toggle_trash", 24 | }, 25 | -- Set to false to disable all of the above keymaps 26 | use_default_keymaps = true, 27 | }) 28 | end, 29 | } 30 | -------------------------------------------------------------------------------- /lua/config/plugins/persistence.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/persistence.nvim", 3 | event = "BufReadPre", 4 | keys = { 5 | { 6 | "S", 7 | function() 8 | require("persistence").load() 9 | end, 10 | desc = "Restore Session", 11 | }, 12 | }, 13 | enabled = true, 14 | config = function() 15 | require("persistence").setup({}) 16 | end, 17 | } 18 | -------------------------------------------------------------------------------- /lua/config/plugins/promise.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "notomo/promise.nvim", 3 | enabled = true, 4 | lazy = true, 5 | } 6 | -------------------------------------------------------------------------------- /lua/config/plugins/range-highlight.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "winston0410/range-highlight.nvim", 3 | enabled = false, 4 | event = { "CmdlineEnter" }, 5 | dependencies = { "winston0410/cmd-parser.nvim" }, 6 | config = function() 7 | require("range-highlight").setup({}) 8 | end, 9 | } 10 | -------------------------------------------------------------------------------- /lua/config/plugins/render-markdown.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "MeanderingProgrammer/render-markdown.nvim", 3 | enabled = true, 4 | cond = not vim.g.vscode, 5 | dependencies = { "nvim-treesitter/nvim-treesitter" }, 6 | ft = { "markdown", "pandoc", "quarto" }, 7 | event = "BufReadPre", 8 | config = function() 9 | require("render-markdown").setup({ 10 | heading = { 11 | render_modes = true, 12 | sign = false, 13 | border = true, 14 | border_virtual = true, 15 | }, 16 | code = { 17 | -- render_modes = true, 18 | sign = false, 19 | language_name = true, 20 | border = "thin", 21 | above = "▄", 22 | below = "▀", 23 | }, 24 | file_types = { "markdown", "Avante" }, 25 | anti_conceal = { 26 | enabled = true, -- show raw md on line under curson 27 | }, 28 | completions = { lsp = { enabled = true } }, 29 | latex = { enabled = false }, 30 | }) 31 | end, 32 | } 33 | -------------------------------------------------------------------------------- /lua/config/plugins/scrolleof.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "Aasim-A/scrollEOF.nvim", 3 | enabled = true, 4 | event = { "CursorMoved", "WinScrolled" }, 5 | config = function() 6 | require("scrollEOF").setup({ 7 | floating = false, 8 | }) 9 | end, 10 | } 11 | -------------------------------------------------------------------------------- /lua/config/plugins/sibling-swap.lua: -------------------------------------------------------------------------------- 1 | local DEV = false 2 | 3 | return { 4 | "Wansmer/sibling-swap.nvim", 5 | dir = DEV and "~/projects/code/personal/sibling-swap.nvim" or nil, 6 | dev = DEV, 7 | enabled = true, 8 | keys = { 9 | "", 10 | "", 11 | }, 12 | dependencies = { 13 | "nvim-treesitter/nvim-treesitter", 14 | }, 15 | config = function() 16 | require("sibling-swap").setup({ 17 | highlight_node_at_cursor = true, 18 | use_default_keymaps = true, 19 | keymaps = { 20 | ["."] = "swap_with_right", 21 | [","] = "swap_with_left", 22 | [""] = "swap_with_right_with_opp", 23 | [""] = "swap_with_left_with_opp", 24 | }, 25 | fallback = { 26 | tsx = { 27 | string_fragment = { 28 | ---@type boolean|function 29 | enable = function(node) 30 | -- String should be single line 31 | local sr, _, er, _ = node:range() 32 | return sr == er 33 | end, 34 | action = function(node, side, _) 35 | local c = vim.api.nvim_win_get_cursor(0) 36 | local sr, sc, er, ec = node:range() 37 | local text = vim.treesitter.get_node_text(node, 0) 38 | local words = vim.split(text, " ", { trimempty = true }) 39 | local word_idx -- word under cursor 40 | local count = sc 41 | 42 | for i, word in ipairs(words) do 43 | count = count + #word + 1 44 | if count > c[2] then 45 | word_idx = i 46 | break 47 | end 48 | end 49 | 50 | if not word_idx then 51 | return 52 | end 53 | 54 | local sib_idx = side == "left" and word_idx - 1 or word_idx + 1 55 | if not words[sib_idx] then 56 | return 57 | end 58 | 59 | local sib = words[sib_idx] 60 | words[sib_idx], words[word_idx] = words[word_idx], sib 61 | 62 | pcall(vim.api.nvim_buf_set_text, 0, sr, sc, er, ec, { vim.fn.join(words, " ") }) 63 | pcall(vim.api.nvim_win_set_cursor, 0, { c[1], side == "left" and c[2] - #sib - 1 or c[2] + #sib + 1 }) 64 | end, 65 | }, 66 | }, 67 | }, 68 | }) 69 | end, 70 | } 71 | -------------------------------------------------------------------------------- /lua/config/plugins/supermaven.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "supermaven-inc/supermaven-nvim", 3 | enabled = false, 4 | event = "BufReadPre", 5 | config = function() 6 | require("supermaven-nvim").setup({ 7 | keymaps = { 8 | accept_suggestion = "", 9 | clear_suggestion = "", 10 | accept_word = "", 11 | }, 12 | }) 13 | end, 14 | } 15 | -------------------------------------------------------------------------------- /lua/config/plugins/symbol-usage.lua: -------------------------------------------------------------------------------- 1 | local DEV = false 2 | 3 | return { 4 | "Wansmer/symbol-usage.nvim", 5 | enabled = true, 6 | dir = DEV and "~/projects/code/personal/symbol-usage.nvim" or nil, 7 | dev = DEV, 8 | event = "BufReadPre", 9 | config = function() 10 | local hl = { link = "Comment" } 11 | 12 | local ok, c = pcall(require, "serenity.colors") 13 | if ok then 14 | hl = { fg = c.cursor_line_number, bold = false, italic = true } 15 | end 16 | 17 | require("symbol-usage").setup({ 18 | hl = hl, 19 | vt_position = "end_of_line", 20 | text_format = function(symbol) 21 | if symbol.references then 22 | local usage = symbol.references <= 1 and "usage" or "usages" 23 | local num = symbol.references == 0 and "no" or symbol.references 24 | return string.format(" 󰌹 %s %s", num, usage) 25 | else 26 | return "" 27 | end 28 | end, 29 | disable = { 30 | cond = { 31 | function() 32 | local path = vim.fn.expand("%:p") 33 | return path:find("/node_modules/") 34 | end, 35 | }, 36 | }, 37 | }) 38 | 39 | vim.keymap.set("n", "lu", function() 40 | require("symbol-usage").toggle() 41 | end) 42 | end, 43 | } 44 | -------------------------------------------------------------------------------- /lua/config/plugins/table-nvim.lua: -------------------------------------------------------------------------------- 1 | return { 2 | -- "SCJangra/table-nvim", 3 | "Wansmer/table-nvim", 4 | dir = "~/projects/code/personal/table-nvim", 5 | dev = true, 6 | ft = { "markdown", "ipynb" }, 7 | config = function() 8 | require("table-nvim").setup({ 9 | padd_column_separators = true, -- Insert a space around column separators. 10 | mappings = { -- next and prev work in Normal and Insert mode. All other mappings work in Normal mode. 11 | next = "", -- Go to next cell. 12 | prev = "", -- Go to previous cell. 13 | insert_row_up = "", -- Insert a row above the current row. 14 | insert_row_down = "", -- Insert a row below the current row. 15 | move_row_up = "", -- Move the current row up. 16 | move_row_down = "", -- Move the current row down. 17 | insert_column_left = "", -- Insert a column to the left of current column. 18 | insert_column_right = "", -- Insert a column to the right of current column. 19 | move_column_left = "", -- Move the current column to the left. 20 | move_column_right = "", -- Move the current column to the right. 21 | insert_table = "", -- Insert a new table. 22 | insert_table_alt = "", -- Insert a new table that is not surrounded by pipes. 23 | delete_column = "", -- Delete the column under cursor. 24 | }, 25 | }) 26 | end, 27 | } 28 | -------------------------------------------------------------------------------- /lua/config/plugins/tailwind-tools.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "luckasRanarison/tailwind-tools.nvim", 3 | event = "LspAttach", 4 | dependencies = { "nvim-treesitter/nvim-treesitter" }, 5 | config = function() 6 | require("tailwind-tools").setup({}) 7 | end, 8 | } 9 | -------------------------------------------------------------------------------- /lua/config/plugins/telescope.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "nvim-telescope/telescope.nvim", 3 | enabled = true, 4 | event = "VeryLazy", 5 | dependencies = { 6 | { "nvim-telescope/telescope-fzf-native.nvim", build = "make" }, 7 | { "nvim-telescope/telescope-live-grep-args.nvim" }, 8 | }, 9 | config = function() 10 | local telescope = require("telescope") 11 | local pickers = require("telescope.builtin") 12 | 13 | local map = vim.keymap.set 14 | -- Builtins pickers 15 | map("n", "f", pickers.find_files, { desc = "Telescope: Find files in (cwd>" }) 16 | -- map("n", "g", pickers.live_grep, { desc = "Telescope: live grep " }) 17 | map( 18 | "n", 19 | "g", 20 | telescope.extensions.live_grep_args.live_grep_args, 21 | { desc = "Telescope: live grep with args" } 22 | ) 23 | map("n", "b", pickers.buffers, { desc = "Telescope: show open buffers" }) 24 | -- map('n', 'd', pickers.diagnostics, { desc = 'Telescope: show diagnostics' }) 25 | map("n", "o", pickers.oldfiles, { desc = "Telescope: show recent using files" }) 26 | map("n", "", function() 27 | pickers.current_buffer_fuzzy_find({ default_text = vim.fn.expand("") }) 28 | end, { desc = "Telescope: fuzzy find word under cursor in current buffer" }) 29 | map("n", "w", function() 30 | pickers.live_grep({ default_text = vim.fn.expand("") }) 31 | end, { desc = "Telescope: live grep word under cursor (cwd>" }) 32 | map("n", "p", function() 33 | pickers.find_files({ default_text = vim.fn.expand("") }) 34 | end, { desc = "Telescope: find file under cursor (cwd)" }) 35 | map("n", "T", function() 36 | pickers.builtin({ include_extensions = true }) 37 | end) 38 | 39 | -- Plugin's pickers 40 | map("n", "n", ":Telescope notify", { desc = "Telescope: show notifications" }) 41 | 42 | -- WARNING: now works only with 'cwd' pickers, because no need know bufnr 43 | local switch_picker = function(picker_name) 44 | return function(prompt_bufnr) 45 | local cur_picker = require("telescope.actions.state").get_current_picker(prompt_bufnr) 46 | local text = cur_picker:_get_prompt() 47 | pickers[picker_name]({ 48 | default_text = text, 49 | }) 50 | end 51 | end 52 | 53 | local actions = require("telescope.actions") 54 | local lga_actions = require("telescope-live-grep-args.actions") 55 | telescope.setup({ 56 | defaults = { 57 | prompt_prefix = " ", 58 | selection_caret = " ", 59 | path_display = { "smart" }, 60 | layout_strategy = "horizontal", 61 | layout_config = { 62 | prompt_position = "bottom", 63 | vertical = { 64 | width = 0.8, 65 | height = 0.8, 66 | }, 67 | }, 68 | file_ignore_patterns = { ".git/", "node_modules/*" }, 69 | mappings = { 70 | i = { 71 | [""] = switch_picker("live_grep"), 72 | [""] = switch_picker("find_files"), 73 | [""] = actions.select_horizontal, 74 | [""] = false, -- Clear instead of preview scroll up 75 | [""] = function(prompt_bufnr) 76 | -- Use nvim-window-picker to choose the window by dynamically attaching a function 77 | local action_set = require("telescope.actions.set") 78 | local action_state = require("telescope.actions.state") 79 | 80 | local cur_picker = action_state.get_current_picker(prompt_bufnr) 81 | cur_picker.get_selection_window = function(picker, _) 82 | local picked_window_id = require("window-picker").pick_window() or vim.api.nvim_get_current_win() 83 | -- Unbind after using so next instance of the picker acts normally 84 | picker.get_selection_window = nil 85 | return picked_window_id 86 | end 87 | 88 | return action_set.edit(prompt_bufnr, "edit") 89 | end, 90 | [""] = function() 91 | vim.api.nvim_feedkeys(vim.keycode(""), "n", true) 92 | end, 93 | [""] = function() 94 | vim.api.nvim_feedkeys(vim.keycode(""), "n", true) 95 | end, 96 | }, 97 | }, 98 | }, 99 | extensions = { 100 | live_grep_args = { 101 | auto_quoting = true, -- enable/disable auto-quoting 102 | -- define mappings, e.g. 103 | mappings = { -- extend mappings 104 | i = { 105 | [""] = lga_actions.quote_prompt(), 106 | [""] = lga_actions.quote_prompt({ postfix = " --iglob " }), 107 | -- freeze the current list and start a fuzzy search in the frozen list 108 | [""] = actions.to_fuzzy_refine, 109 | }, 110 | }, 111 | }, 112 | }, 113 | }) 114 | 115 | telescope.load_extension("fzf") 116 | telescope.load_extension("live_grep_args") 117 | end, 118 | } 119 | -------------------------------------------------------------------------------- /lua/config/plugins/template-string.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "axelvc/template-string.nvim", 3 | enabled = true, 4 | event = "BufReadPre", 5 | config = function() 6 | require("template-string").setup({ 7 | filetypes = { 8 | "html", 9 | "typescript", 10 | "javascript", 11 | "typescriptreact", 12 | "javascriptreact", 13 | "python", 14 | "vue", 15 | }, -- filetypes where the plugin is active 16 | jsx_brackets = true, -- must add brackets to jsx attributes 17 | remove_template_string = false, -- remove backticks when there are no template string 18 | restore_quotes = { 19 | -- quotes used when "remove_template_string" option is enabled 20 | normal = [[']], 21 | jsx = [["]], 22 | }, 23 | }) 24 | end, 25 | } 26 | -------------------------------------------------------------------------------- /lua/config/plugins/tfm.lua: -------------------------------------------------------------------------------- 1 | local DEV = false 2 | 3 | return { 4 | "Wansmer/tfm.nvim", 5 | dir = DEV and "~/projects/code/personal/tfm.nvim" or nil, 6 | dev = DEV, 7 | branch = "refactor", 8 | enabled = true, 9 | event = "VeryLazy", 10 | config = function() 11 | require("tfm").setup({ 12 | file_manager = "yazi", 13 | follow_current_file = true, 14 | ui = { 15 | border = "double", 16 | height = 0.8, 17 | width = 0.8, 18 | x = 0.5, 19 | y = 0.5, 20 | }, 21 | on_open = function(win, buf) 22 | vim.keymap.set("t", "q", "close", { buffer = buf }) 23 | end, 24 | }) 25 | vim.keymap.set("n", "e", function() 26 | require("tfm").open() 27 | end) 28 | end, 29 | } 30 | -------------------------------------------------------------------------------- /lua/config/plugins/toggleterm.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "akinsho/toggleterm.nvim", 3 | enabled = true, 4 | keys = { "" }, 5 | cmd = { "ToggleTerm", "ToggleTermToggleAll" }, 6 | config = function() 7 | local toggleterm = require("toggleterm") 8 | 9 | local separator = vim.api.nvim_get_hl(0, { name = "VertSplit", link = false }) 10 | vim.api.nvim_set_hl(0, "TTBorder", { bg = "#0a0a0a", fg = separator.fg }) 11 | vim.api.nvim_set_hl(0, "TTNormal", { bg = "#0a0a0a" }) 12 | 13 | toggleterm.setup({ 14 | size = 23, 15 | open_mapping = [[]], 16 | hide_numbers = true, 17 | shade_filetypes = {}, 18 | start_in_insert = true, 19 | insert_mappings = true, 20 | persist_size = false, 21 | persist_mode = false, 22 | direction = "horizontal", -- 'float', 'horizontal', 'vertical', 'tab' 23 | close_on_exit = true, 24 | shell = vim.o.shell, 25 | -- highlights = {}, -- Not working 26 | float_opts = { 27 | border = { "", "", "", " ", " ", " ", " ", " " }, 28 | relative = "editor", 29 | width = vim.opt.columns:get(), 30 | height = 23, 31 | col = 0, 32 | row = vim.opt.lines:get(), 33 | style = "minimal", 34 | title = "Hello KITTY", 35 | title_pos = "left", 36 | noautocmd = true, 37 | }, 38 | on_open = function(term) 39 | vim.opt.winhighlight = "Normal:TTNormal,FloatBorder:TTBorder" 40 | local map = vim.keymap.set 41 | 42 | ---Resize the terminal 43 | ---@param mode boolean true is increase, false is decrease 44 | ---@param step number lines count to increase or decrease 45 | local function resize(mode, step) 46 | return function() 47 | local win_opts = vim.api.nvim_win_get_config(term.window) 48 | local cond = mode and (win_opts.height <= vim.opt.lines:get() - step) or (win_opts.height > step) 49 | if cond then 50 | win_opts.height = win_opts.height + (mode and step or (step * -1)) 51 | vim.api.nvim_win_set_config(term.window, win_opts) 52 | end 53 | end 54 | end 55 | 56 | map({ "t", "i", "n" }, "", resize(true, 5), { buffer = term.bufnr }) 57 | map({ "t", "i", "n" }, "", resize(false, 5), { buffer = term.bufnr }) 58 | map({ "t", "i", "n" }, "", resize(false, 5), { buffer = term.bufnr }) -- For wezterm, because it doesn't support and sent 59 | map({ "n" }, "gx", function() 60 | local path = vim.fn.expand("") 61 | if path == "" then 62 | return 63 | end 64 | 65 | -- check if file exists 66 | if vim.uv.fs_stat(vim.fn.fnamemodify(path, ":p")) then 67 | local cursor = vim.api.nvim_win_get_cursor(0) 68 | local line = vim.api.nvim_buf_get_lines(term.bufnr, cursor[1] - 1, cursor[1], false)[1] 69 | local row_col = string.match(line, path .. ":(%d+:%d+)") 70 | 71 | -- open in vsplit even if row_col is nil 72 | vim.cmd("vs " .. path) 73 | if row_col then 74 | row_col = vim.iter(vim.split(row_col, ":")):map(tonumber):totable() 75 | vim.api.nvim_win_set_cursor(0, row_col) 76 | end 77 | return 78 | end 79 | 80 | -- fallback to open with the system default handler (default gx behavior) 81 | -- see: h vim.ui.open() 82 | local ok, msg = pcall(vim.ui.open, path) 83 | if not ok then 84 | vim.notify(msg --[[@as string]], vim.log.levels.ERROR) 85 | end 86 | end, { buffer = term.bufnr }) 87 | end, 88 | on_close = function() 89 | local ok, nt = pcall(require, "neo-tree.sources.manager") 90 | if ok then 91 | nt.refresh("filesystem") 92 | end 93 | vim.cmd.stopinsert() 94 | end, 95 | }) 96 | end, 97 | } 98 | -------------------------------------------------------------------------------- /lua/config/plugins/treesitter.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "nvim-treesitter/nvim-treesitter", 3 | enabled = true, 4 | lazy = false, 5 | config = function() 6 | local map = vim.keymap.set 7 | map("n", "tp", "InspectTree", { nowait = true }) 8 | map("n", "tn", "TSNodeUnderCursor", { nowait = true }) 9 | map("n", "th", "TSHighlightCapturesUnderCursor", { nowait = true }) 10 | 11 | require("nvim-treesitter.configs").setup({ 12 | ensure_installed = { 13 | "bash", 14 | "c", 15 | "cpp", 16 | "css", 17 | "cuda", 18 | "dockerfile", 19 | "editorconfig", 20 | "git_config", 21 | "git_rebase", 22 | "gitattributes", 23 | "gitcommit", 24 | "gitignore", 25 | "go", 26 | "gomod", 27 | "gosum", 28 | "gotmpl", 29 | "html", 30 | "http", 31 | "javascript", 32 | "jsdoc", 33 | "json", 34 | "jsonc", 35 | "latex", 36 | "lua", 37 | "luadoc", 38 | "luap", -- luapatterns 39 | "markdown", 40 | "markdown_inline", 41 | "mermaid", -- experimental 42 | "nginx", 43 | "python", 44 | "regex", 45 | "rust", 46 | "scss", 47 | "sql", 48 | "ssh_config", 49 | "svelte", 50 | "terraform", 51 | "toml", 52 | "tsx", 53 | "typescript", 54 | "vim", 55 | "vimdoc", 56 | "yaml", 57 | }, 58 | sync_install = false, 59 | ignore_install = { "phpdoc", "comment" }, 60 | auto_install = true, 61 | highlight = { 62 | enable = true, 63 | additional_vim_regex_highlighting = false, 64 | }, 65 | 66 | -- WARNING: Делает лишний отступ во Vue 67 | indent = { 68 | enable = true, 69 | }, 70 | 71 | incremental_selection = { 72 | enable = true, 73 | keymaps = { 74 | init_selection = "", -- set to `false` to disable one of the mappings 75 | node_incremental = "", 76 | node_decremental = "", 77 | scope_incremental = false, 78 | }, 79 | }, 80 | 81 | query_linter = { 82 | enable = true, 83 | use_virtual_text = false, 84 | lint_events = { "BufWrite", "CursorHold" }, 85 | }, 86 | }) 87 | end, 88 | } 89 | -------------------------------------------------------------------------------- /lua/config/plugins/trouble.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/trouble.nvim", 3 | enabled = false, 4 | cmd = { "TroubleToggle", "Trouble" }, 5 | dependencies = { "nvim-tree/nvim-web-devicons" }, 6 | config = function() 7 | require("trouble").setup({}) 8 | 9 | vim.api.nvim_create_autocmd("QuickFixCmdPost", { 10 | callback = function() 11 | vim.cmd([[Trouble qflist open]]) 12 | end, 13 | }) 14 | 15 | vim.api.nvim_create_autocmd("FileType", { 16 | pattern = "qf", 17 | callback = vim.schedule_wrap(function(e) 18 | vim.api.nvim_buf_delete(e.buf, { force = true }) 19 | end), 20 | }) 21 | end, 22 | } 23 | -------------------------------------------------------------------------------- /lua/config/plugins/ts-context.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "nvim-treesitter/nvim-treesitter-context", 3 | event = "BufReadPre", 4 | enabled = true, 5 | config = function() 6 | require("treesitter-context").setup({ mode = "cursor", max_lines = 3 }) 7 | end, 8 | } 9 | -------------------------------------------------------------------------------- /lua/config/plugins/ts-error-translator.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "dmmulroy/ts-error-translator.nvim", 3 | enabled = true, 4 | ft = { "javascript", "typescript", "javascriptreact", "typescriptreact" }, 5 | config = function() 6 | require("ts-error-translator").setup({}) 7 | end, 8 | } 9 | -------------------------------------------------------------------------------- /lua/config/plugins/tsc.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "dmmulroy/tsc.nvim", 3 | enabled = true, 4 | event = "VeryLazy", 5 | config = function() 6 | require("tsc").setup({ enable_progress_notifications = true }) 7 | end, 8 | } 9 | -------------------------------------------------------------------------------- /lua/config/plugins/typescript-tools.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "pmizio/typescript-tools.nvim", 3 | enabled = false, 4 | dependencies = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" }, 5 | ft = { 6 | "javascript", 7 | "javascriptreact", 8 | "typescript", 9 | "typescriptreact", 10 | "typescript.tsx", 11 | }, 12 | config = function() 13 | local on_attach = require("config.lsp.default").on_attach 14 | require("typescript-tools").setup({ 15 | on_attach = on_attach, 16 | settings = { 17 | tsserver_file_preferences = { 18 | includeInlayParameterNameHints = "all", 19 | includeCompletionsForModuleExports = true, 20 | quotePreference = "auto", 21 | }, 22 | tsserver_format_options = { 23 | allowIncompleteCompletions = false, 24 | allowRenameOfImportPath = false, 25 | }, 26 | }, 27 | }) 28 | end, 29 | } 30 | -------------------------------------------------------------------------------- /lua/config/plugins/typr.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "nvzone/typr", 3 | dependencies = "nvzone/volt", 4 | cmd = { "Typr", "TyprStats" }, 5 | config = function() 6 | require("typr").setup() 7 | end, 8 | } 9 | -------------------------------------------------------------------------------- /lua/config/plugins/venv-selector.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "linux-cultist/venv-selector.nvim", 3 | branch = "regexp", 4 | ft = { "python" }, 5 | dependencies = { 6 | "neovim/nvim-lspconfig", 7 | "nvim-telescope/telescope.nvim", 8 | }, 9 | config = function() 10 | require("venv-selector").setup() 11 | end, 12 | } 13 | -------------------------------------------------------------------------------- /lua/config/plugins/vtsls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "yioneko/nvim-vtsls", 3 | enabled = true, 4 | event = "LspAttach", 5 | config = function() 6 | require("vtsls").config({}) 7 | end, 8 | } 9 | -------------------------------------------------------------------------------- /lua/config/plugins/wildfire.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "sustech-data/wildfire.nvim", 3 | enabled = false, 4 | event = "VeryLazy", 5 | dependencies = { "nvim-treesitter/nvim-treesitter" }, 6 | config = function() 7 | require("wildfire").setup() 8 | end, 9 | } 10 | -------------------------------------------------------------------------------- /lua/config/plugins/workspace-diagnostic.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "artemave/workspace-diagnostics.nvim", 3 | enabled = false, 4 | config = function() 5 | require("workspace-diagnostics").setup() 6 | end, 7 | } 8 | -------------------------------------------------------------------------------- /lua/config/plugins/zenmode.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/zen-mode.nvim", 3 | enabled = true, 4 | keys = { 5 | { 6 | "z", 7 | function() 8 | require("zen-mode").toggle({ 9 | window = { 10 | width = vim.api.nvim_get_option_value("tw", { buf = 0 }), 11 | }, 12 | }) 13 | end, 14 | }, 15 | }, 16 | config = function() 17 | require("zen-mode").setup({ 18 | on_open = function(win) 19 | local ft = vim.api.nvim_buf_get_option(0, "ft") 20 | -- For better writing 21 | if vim.tbl_contains({ "markdown", "text" }, ft) then 22 | for opt, val in pairs({ tw = 9999, linebreak = true, wrap = true }) do 23 | vim.opt_local[opt] = val 24 | end 25 | end 26 | end, 27 | on_close = function() 28 | local ft = vim.api.nvim_get_option_value("ft", { buf = 0 }) 29 | -- restore original options 30 | if vim.tbl_contains({ "markdown", "text" }, ft) then 31 | for _, opt in ipairs({ "tw", "linebreak", "wrap" }) do 32 | vim.opt_local[opt] = vim.filetype.get_option(ft, opt) 33 | end 34 | end 35 | end, 36 | }) 37 | end, 38 | } 39 | -------------------------------------------------------------------------------- /lua/filetype.lua: -------------------------------------------------------------------------------- 1 | --{{ Detect yaml.ansible 2 | local function is_ansible_root() 3 | local ansible_root = { "ansible.cfg", ".ansible-lint.yml", "inventory.ini", "inventory.yml" } 4 | return vim.fs.root(vim.uv.cwd()--[[@as string]], ansible_root) 5 | end 6 | 7 | local function match_pattern(path) 8 | local patterns = { ".*/tasks/.*%.ya?ml", ".*/playbooks/.*%.ya?ml", ".*playbook.*%.ya?ml" } 9 | return vim.iter(patterns):any(function(pattern) 10 | return path:match(pattern) 11 | end) 12 | end 13 | 14 | local function ansible_or_yaml(path) 15 | return (is_ansible_root() or match_pattern(path)) and "yaml.ansible" or "yaml" 16 | end 17 | 18 | vim.filetype.add({ 19 | extension = { 20 | ["yml"] = ansible_or_yaml, 21 | ["yaml"] = ansible_or_yaml, 22 | }, 23 | }) 24 | --}} 25 | 26 | --{{ Detect env 27 | vim.filetype.add({ 28 | pattern = { 29 | [".*%.env%..*"] = "sh", 30 | }, 31 | }) 32 | --}} 33 | -------------------------------------------------------------------------------- /lua/modules/autoimport/code_action_api.lua: -------------------------------------------------------------------------------- 1 | local util = require("vim.lsp.util") 2 | local ms = require("vim.lsp.protocol").Methods 3 | 4 | ---@param action lsp.Command|lsp.CodeAction 5 | ---@param client lsp.Client 6 | ---@param ctx lsp.HandlerContext 7 | local function apply_action(action, client, ctx) 8 | if action.edit then 9 | util.apply_workspace_edit(action.edit, client.offset_encoding) 10 | end 11 | if action.command then 12 | local command = type(action.command) == "table" and action.command or action 13 | client:_exec_cmd(command, ctx) 14 | end 15 | end 16 | 17 | ---@param choice {action: lsp.Command|lsp.CodeAction, ctx: lsp.HandlerContext} 18 | local function on_user_choice(choice) 19 | if not choice or not choice.action then 20 | return 21 | end 22 | -- textDocument/codeAction can return either Command[] or CodeAction[] 23 | -- 24 | -- CodeAction 25 | -- ... 26 | -- edit?: WorkspaceEdit -- <- must be applied before command 27 | -- command?: Command 28 | -- 29 | -- Command: 30 | -- title: string 31 | -- command: string 32 | -- arguments?: any[] 33 | -- 34 | ---@type lsp.Client 35 | local client = assert(vim.lsp.get_client_by_id(choice.ctx.client_id)) 36 | local action = choice.action 37 | local bufnr = assert(choice.ctx.bufnr, "Must have buffer number") 38 | 39 | local reg = client.dynamic_capabilities:get(ms.textDocument_codeAction, { bufnr = bufnr }) 40 | 41 | local supports_resolve = vim.tbl_get(reg or {}, "registerOptions", "resolveProvider") 42 | or client.supports_method(ms.codeAction_resolve) 43 | 44 | if not action.edit and client and supports_resolve then 45 | client.request(ms.codeAction_resolve, action, function(err, resolved_action) 46 | if err then 47 | if action.command then 48 | apply_action(action, client, choice.ctx) 49 | else 50 | vim.notify(err.code .. ": " .. err.message, vim.log.levels.ERROR) 51 | end 52 | else 53 | apply_action(resolved_action, client, choice.ctx) 54 | end 55 | end, bufnr) 56 | else 57 | apply_action(action, client, choice.ctx) 58 | end 59 | end 60 | -- }} 61 | 62 | return { 63 | apply_action = on_user_choice, 64 | } 65 | -------------------------------------------------------------------------------- /lua/modules/autoimport/init.lua: -------------------------------------------------------------------------------- 1 | local u = require("utils") 2 | local GROUP = vim.api.nvim_create_augroup("__autoimport__", { clear = true }) 3 | local apply_action = require("modules.autoimport.code_action_api").apply_action 4 | 5 | local M = {} 6 | 7 | M.servers = { 8 | ts_ls = { 9 | diagnostic_codes = { 2304, 2552 }, 10 | ft = { "typescript", "typescriptreact", "javascript", "javascriptreact" }, 11 | patterns = { "^Add import", "^Update import" }, 12 | }, 13 | ["typescript-tools"] = { 14 | diagnostic_codes = { 2304, 2552 }, 15 | ft = { "typescript", "typescriptreact", "javascript", "javascriptreact" }, 16 | patterns = { "^Add import", "^Update import" }, 17 | }, 18 | volar = { 19 | diagnostic_codes = { 2304 }, 20 | ft = { "vue", "javascript", "typescript" }, 21 | patterns = { "^Add import", "^Update import" }, 22 | }, 23 | rust_analyzer = { 24 | diagnostic_codes = { "E0425" }, 25 | ft = { "rust" }, 26 | patterns = { "^Import" }, 27 | }, 28 | } 29 | 30 | local function filter_diagnostics(bufnr, client_id, codes) 31 | return vim.tbl_filter(function(d) 32 | return vim.tbl_contains(codes, d.code) 33 | end, vim.lsp.diagnostic.get_line_diagnostics(bufnr, nil, nil, client_id)) 34 | end 35 | 36 | function M.autoimport(client, bufnr) 37 | local diagnostics = filter_diagnostics(bufnr, client.id, M.servers[client.name].diagnostic_codes) 38 | 39 | ---@param err? lsp.ResponseError 40 | ---@param result? (lsp.Command|lsp.CodeAction)[] 41 | ---@param ctx lsp.HandlerContext 42 | local function on_result(err, result, ctx) 43 | if err then 44 | vim.notify(err.message, vim.log.levels.WARN, { title = "Autoimport" }) 45 | return 46 | end 47 | 48 | if not result then 49 | vim.notify("No result", vim.log.levels.WARN, { title = "Autoimport" }) 50 | return 51 | end 52 | 53 | local filtered_actions = vim.tbl_filter(function(action) 54 | return u.some(M.servers[client.name].patterns, function(pat) 55 | -- vim.print(action) 56 | return action.title:match(pat) ~= nil 57 | end) 58 | end, result) 59 | 60 | -- TODO: bad solution. Find better 61 | table.sort(filtered_actions, function(a, b) 62 | return #a.title < #b.title 63 | end) 64 | 65 | -- TODO: remove after testing 66 | local action = filtered_actions[1] 67 | apply_action({ action = action, ctx = ctx }) 68 | -- for _, action in ipairs(filtered_actions) do 69 | -- apply_action({ action = action, ctx = ctx }) 70 | -- 71 | -- local actual_diagnostic = filter_diagnostics(bufnr, client.id, M.servers[client.name].diagnostic_codes) 72 | -- if #actual_diagnostic == 0 then 73 | -- break 74 | -- end 75 | -- end 76 | end 77 | 78 | -- Why cycle? Here is not really able to get all code actions in a single request. (Believe me, I tried) 79 | for _, d in ipairs(diagnostics) do 80 | local context = { 81 | triggerKind = vim.lsp.protocol.CodeActionTriggerKind.Automatic, 82 | diagnostics = { d }, 83 | } 84 | 85 | local params = { 86 | textDocument = { uri = vim.uri_from_bufnr(bufnr) }, 87 | range = { start = d.range.start, ["end"] = d.range.start }, 88 | context = context, 89 | } 90 | 91 | client.request("textDocument/codeAction", params, on_result, bufnr) 92 | end 93 | end 94 | 95 | function M.run() 96 | vim.api.nvim_create_autocmd("InsertLeave", { 97 | group = GROUP, 98 | desc = "Autoimport", 99 | callback = function(e) 100 | local clients = vim.lsp.get_clients({ bufnr = e.buf, method = "textDocument/codeAction" }) 101 | local client = vim.iter(clients):find(function(c) 102 | return M.servers[c.name] ~= nil 103 | end) 104 | if client then 105 | -- vim.defer_fn(function() 106 | -- end, 0) 107 | M.autoimport(client, e.buf) 108 | end 109 | end, 110 | }) 111 | end 112 | 113 | return M 114 | -------------------------------------------------------------------------------- /lua/modules/comment/init.lua: -------------------------------------------------------------------------------- 1 | local u = require("utils") 2 | 3 | local function get_comment_pattern() 4 | return vim.split(vim.bo.commentstring, "%s", { plain = true }) 5 | end 6 | 7 | local function comment(line) 8 | return vim.bo.commentstring:format(line) 9 | end 10 | 11 | local function uncomment(line) 12 | local patterns = get_comment_pattern() 13 | local pad, cut_line = u.split_padline(line, "left") 14 | 15 | if vim.startswith(cut_line, patterns[1]) then 16 | cut_line = cut_line:sub(#patterns[1] + 1) 17 | end 18 | 19 | if #patterns[2] ~= 0 and vim.endswith(cut_line, patterns[2]) then 20 | cut_line = cut_line:sub(1, -(#patterns[2] + 1)) 21 | end 22 | 23 | return pad .. cut_line 24 | end 25 | 26 | local function is_commented(line) 27 | line = vim.trim(line) 28 | local patterns = get_comment_pattern() 29 | local prefix, postfix = unpack(patterns) 30 | return vim.startswith(line, vim.trim(prefix)) and vim.endswith(line, vim.trim(postfix)) 31 | end 32 | 33 | local function min_indent(start, end_, lines) 34 | local min = vim.fn.indent(start) 35 | local i = 1 36 | while start <= end_ do 37 | if vim.trim(lines[i]) ~= "" then 38 | local indent = vim.fn.indent(start) 39 | min = min <= indent and min or indent 40 | end 41 | start = start + 1 42 | i = i + 1 43 | end 44 | return min 45 | end 46 | 47 | _G.__comment = function(method) 48 | local is_v = method == "visual" 49 | local patterns = get_comment_pattern() 50 | if not vim.tbl_isempty(patterns) then 51 | local sr, sc, er, ec = u.to_api_range(is_v and u.get_visual_range() or u.get_object_range()) 52 | 53 | local lines = vim.api.nvim_buf_get_lines(0, sr, er + 1, true) 54 | local mode = is_commented(lines[1]) and "uncomment" or "comment" 55 | local indent = mode == "comment" and min_indent(sr + 1, er + 1, lines) or 0 56 | 57 | local processed_lines = {} 58 | 59 | for i, line in ipairs(lines) do 60 | line = line:sub(indent + 1) 61 | line = mode == "comment" and comment(line) or uncomment(line) 62 | processed_lines[i] = (" "):rep(indent) .. line 63 | end 64 | 65 | vim.api.nvim_buf_set_lines(0, sr, er + 1, true, processed_lines) 66 | end 67 | end 68 | 69 | local function comment_repeat(motion) 70 | motion = motion or "" 71 | return function() 72 | vim.opt.operatorfunc = "v:lua.__comment" 73 | return "g@" .. motion 74 | end 75 | end 76 | 77 | return { 78 | toggle_line = comment_repeat(" "), 79 | toggle_object = comment_repeat(), 80 | toggle_visual = function() 81 | _G.__comment("visual") 82 | end, 83 | } 84 | -------------------------------------------------------------------------------- /lua/modules/devcontainer/init.lua: -------------------------------------------------------------------------------- 1 | -- WIP 2 | local M = {} 3 | M.__index = M 4 | 5 | function M.start() 6 | if not M:is_devcontainer_repo() then 7 | return 8 | end 9 | 10 | if vim.fn.executable("devcontainer") ~= 1 then 11 | vim.notify( 12 | "Dev Container CLI is not exetutable. Run `npm install -g @devcontainers/cli`", 13 | vim.log.levels.WARN, 14 | { title = "DevContainer" } 15 | ) 16 | return 17 | end 18 | 19 | vim.api.nvim_create_user_command("DevContainer", function(args) 20 | if args.args == "start" then 21 | local dc = setmetatable({ 22 | status = "starting", 23 | workspace_folder = vim.uv.cwd(), 24 | log_file = vim.fn.stdpath("cache") .. "/devcontainer.log", 25 | }, M) 26 | 27 | dc:setup() 28 | 29 | -- TODO: add 'stop', 'attach', `command`, `exec`, etc 30 | end 31 | end, { nargs = 1 }) 32 | 33 | vim.api.nvim_create_autocmd("UIEnter", { 34 | callback = function() 35 | vim.notify( 36 | "Folder contains a Dev Container configuration file. Run `:DevContainer start` to develop in a container", 37 | vim.log.levels.INFO, 38 | { title = "DevContainer" } 39 | ) 40 | end, 41 | }) 42 | end 43 | 44 | function M:is_devcontainer_repo() 45 | return vim.uv.fs_stat(".devcontainer/devcontainer.json") ~= nil 46 | end 47 | 48 | function M:setup() 49 | self:read_cfg() 50 | self:up() 51 | self:setup_listener() 52 | end 53 | 54 | function M:read_cfg() 55 | vim.system( 56 | { "devcontainer", "read-configuration", "--workspace-folder", self.workspace_folder }, 57 | { text = true }, 58 | function(res) 59 | if res.code ~= 0 then 60 | -- TODO: use logger 61 | print("Error to read devcontainer configuration:", res.stderr) 62 | self.status = "error" 63 | return 64 | end 65 | 66 | self.cfg = vim.json.decode(res.stdout) 67 | if self.cfg == nil then 68 | print("Error to decode devcontainer configuration:", res.stderr) 69 | return 70 | end 71 | end 72 | ) 73 | end 74 | 75 | function M:up() 76 | return vim.system( 77 | { "devcontainer", "up", "--workspace-folder", self.workspace_folder }, 78 | { text = true }, 79 | function(res) 80 | if res.code ~= 0 then 81 | print("Error to start devcontainer:", res.stderr) 82 | self.status = "error" 83 | return 84 | end 85 | 86 | vim.print(res.stdout) 87 | 88 | local container_info = vim.json.decode(res.stdout) 89 | if container_info == nil then 90 | print("Error to decode devcontainer info:", res.stderr) 91 | end 92 | 93 | vim.schedule(function() 94 | vim.api.nvim_exec_autocmds("User", { pattern = "DevContainerStarted" }) 95 | end) 96 | 97 | self.container_info = container_info 98 | self.status = "running" 99 | end 100 | ) 101 | end 102 | 103 | function M:setup_listener() 104 | vim.api.nvim_create_autocmd("User", { 105 | pattern = "DevContainerStarted", 106 | callback = function() 107 | vim.api.nvim_create_autocmd("TermOpen", { 108 | callback = function(e) 109 | local pid = e.match:match("(%d+):/bin/zsh") 110 | if pid then 111 | local chan = vim.iter(vim.api.nvim_list_chans()):find(function(c) 112 | local ok, pid_by_chan = pcall(vim.fn.jobpid, c.id) 113 | return c.mode == "terminal" and ok and pid_by_chan == tonumber(pid) 114 | end) 115 | 116 | local cmd = ("docker exec -w %s -it %s /bin/zsh\n\x0c"):format( 117 | self.container_info.remoteWorkspaceFolder, 118 | self.container_info.containerId 119 | ) 120 | 121 | vim.schedule(function() 122 | vim.api.nvim_chan_send(chan.id, cmd) 123 | end) 124 | end 125 | end, 126 | }) 127 | end, 128 | }) 129 | end 130 | 131 | -- Write log to file in cache directory 132 | function M:log() 133 | return vim.system( 134 | { "devcontainer", "logs", "--workspace-folder", self.workspace_folder, "--log-file", self.log_file }, 135 | { text = true } 136 | ) 137 | end 138 | 139 | return M 140 | -------------------------------------------------------------------------------- /lua/modules/dragndrop.lua: -------------------------------------------------------------------------------- 1 | -- Usage: 2 | -- 3 | -- local dnd = DragNDrop.new() 4 | -- dnd:run() 5 | -- 6 | -- vim.api.nvim_create_autocmd("User", { 7 | -- pattern = "DragStart", 8 | -- callback = function(event) 9 | -- vim.print("Data DragStart:", event.data) 10 | -- end, 11 | -- }) 12 | -- 13 | -- vim.api.nvim_create_autocmd("User", { 14 | -- pattern = "DragEnd", 15 | -- callback = function(event) 16 | -- vim.print("Data DragEnd:", event.data) 17 | -- end, 18 | -- }) 19 | 20 | local DragNDrop = {} 21 | DragNDrop.__index = DragNDrop 22 | 23 | function DragNDrop.new() 24 | return setmetatable({ 25 | is_drag = false, 26 | start = {}, 27 | end_ = {}, 28 | }, DragNDrop) 29 | end 30 | 31 | function DragNDrop:run() 32 | local ns = vim.api.nvim_create_namespace("__drag_n_drop__") 33 | vim.on_key(function(char) 34 | local key = vim.fn.keytrans(char) 35 | if key == "" and not self.is_drag then 36 | self:drag_start() 37 | end 38 | 39 | if key == "" and self.is_drag then 40 | self:drag_end() 41 | end 42 | end, ns) 43 | end 44 | 45 | function DragNDrop:drag_start() 46 | self.is_drag = true 47 | self.start = vim.fn.getmousepos() 48 | vim.api.nvim_exec_autocmds("User", { pattern = "DragStart", data = { start = self.start } }) 49 | end 50 | 51 | function DragNDrop:drag_end() 52 | self.is_drag = false 53 | vim.api.nvim_exec_autocmds( 54 | "User", 55 | { pattern = "DragEnd", data = { start = self.start, end_ = vim.fn.getmousepos() } } 56 | ) 57 | self.start = {} 58 | self.end_ = {} 59 | end 60 | -------------------------------------------------------------------------------- /lua/modules/ext_hover.lua: -------------------------------------------------------------------------------- 1 | ---Implements extended hover functionality 2 | ---(e.g. vscode like `editor.action.showDefinitionPreviewHover`) 3 | 4 | local u = require("utils") 5 | local Promise = require("promise") 6 | local ms = vim.lsp.protocol.Methods 7 | local M = { 8 | servers = { 9 | "ts_ls", 10 | "vtsls", 11 | "typescript-tools", 12 | "lua_ls", 13 | "pyright", 14 | "basedpyright", 15 | "gopls", 16 | }, 17 | } 18 | 19 | function M.extended_hover() 20 | local start_buf = vim.api.nvim_get_current_buf() 21 | 22 | local clients = vim.lsp.get_clients({ bufnr = start_buf }) 23 | local client ---@type vim.lsp.Client 24 | 25 | for _, c in ipairs(clients) do 26 | if 27 | vim.tbl_contains(M.servers, c.name) 28 | and c:supports_method(ms.textDocument_hover) 29 | and c:supports_method(ms.textDocument_definition) 30 | then 31 | client = c 32 | break 33 | end 34 | end 35 | 36 | if not client then 37 | return 38 | end 39 | 40 | local params = vim.lsp.util.make_position_params(0, "utf-8") 41 | 42 | -- HOVER 43 | local get_hover = function() 44 | return Promise.new(function(resolve) 45 | client:request(ms.textDocument_hover, params, function(err, result, ctx) 46 | if err or not result or vim.tbl_isempty(result) or ctx.bufnr ~= start_buf then 47 | vim.notify("Problem in hover request in ext_hover", vim.log.levels.INFO) 48 | return 49 | end 50 | 51 | local value = "" 52 | if vim.islist(result.contents) then 53 | -- E.g. `typescript-tools` in a `hover` structure has `{ { kind = "markdown", value = ... }, 'some string description }` 54 | for _, v in ipairs(result.contents) do 55 | value = value .. "\n" .. (v.value or type(v) == "string" and v or "") 56 | end 57 | else 58 | -- E.g. `vtsls` hasn't `.value`, `contents` just is a string 59 | value = type(result.contents) == "string" and result.contents or result.contents.value 60 | end 61 | 62 | if not value then 63 | return 64 | end 65 | 66 | local content = vim.split(value, "\n", { trimempty = true }) 67 | resolve(content) 68 | end, start_buf) 69 | end) 70 | end 71 | 72 | ---Wrap the lines in a markdown code block. If lines is empty, return an empty table 73 | ---@param path string 74 | ---@param lines string[] 75 | ---@return string[] 76 | local function wrap_md(path, lines) 77 | if vim.tbl_isempty(lines) then 78 | return lines 79 | end 80 | local ft = vim.filetype.match({ filename = path }) 81 | if not ft or ft == "" then 82 | ft = vim.fn.fnamemodify(path, ":e") 83 | end 84 | return vim.iter({ "```" .. ft, lines, "```" }):flatten():totable() 85 | end 86 | 87 | -- DEFINITION 88 | local get_definition = function() 89 | return Promise.new(function(resolve) 90 | client:request(ms.textDocument_definition, params, function(err, result, ctx) 91 | if err or not result or vim.tbl_isempty(result) or ctx.bufnr ~= start_buf then 92 | vim.notify("Problem in definition request in ext_hover", vim.log.levels.INFO) 93 | return 94 | end 95 | 96 | local def = result[1] 97 | 98 | local path = vim.uri_to_fname(def.targetUri or def.uri) -- e.g. pyright has no `targetUri` but `uri` 99 | local range = def.targetRange or def.range -- e.g. pyright has no `targetRange` but `range` 100 | local start_line = range.start.line + 1 101 | local end_line = range["end"].line + 1 102 | local lines = u.get_lines(path, start_line, end_line) 103 | lines = u.trim_indent(lines) 104 | 105 | resolve(wrap_md(path, lines)) 106 | end, start_buf) 107 | end) 108 | end 109 | 110 | Promise.all_settled({ get_hover(), get_definition() }):next(function(results) 111 | local lines = vim 112 | .iter(results) 113 | :filter(function(v) 114 | return v.status == "fulfilled" 115 | end) 116 | :map(function(v) 117 | return v.value 118 | end) 119 | :flatten() 120 | :totable() 121 | 122 | local max_width = math.floor(vim.o.columns * 0.4) 123 | -- TODO: handle empty table 124 | local longest_line = math.max(unpack(vim.iter(lines):map(string.len):totable())) 125 | if longest_line > max_width then 126 | longest_line = max_width 127 | end 128 | 129 | -- TODO: insert breaklines only if status is fulfilled 130 | table.insert(lines, #results[1].value + 1, (""):rep(longest_line)) 131 | vim.lsp.util.open_floating_preview(lines, "markdown", { 132 | border = PREF.ui.border, 133 | max_height = math.floor(vim.o.lines * 0.5), 134 | max_width = max_width, 135 | focus_id = "ext_hover", 136 | }) 137 | end) 138 | end 139 | 140 | return M 141 | -------------------------------------------------------------------------------- /lua/modules/fftt/fftt_test.lua: -------------------------------------------------------------------------------- 1 | -- to run execute `:PlenaryBustedFile lua/modules/fftt/fftt_test.lua` 2 | 3 | require("plenary.busted") 4 | 5 | local fftt = require("modules.fftt") 6 | fftt.setup() 7 | 8 | describe("`prepare_str()`:", function() 9 | it("correct substring in English in `right` direction", function() 10 | local s = "This is line" 11 | local res = fftt.prepare_str(s, "left", 5) 12 | assert.are_same("s line", res) 13 | end) 14 | 15 | it("correct substring in English in `right` direction", function() 16 | local s = "This is line" 17 | local res = fftt.prepare_str(s, "right", 5) 18 | assert.are_same(" sihT", res) 19 | end) 20 | 21 | it("correct substring in Russian in `left` direction", function() 22 | local s = "Это строка" 23 | local res = fftt.prepare_str(s, "left", 10) 24 | assert.are_same("рока", res) 25 | end) 26 | 27 | it("correct substring in Russian in `right` direction", function() 28 | local s = "Это строка" 29 | local res = fftt.prepare_str(s, "right", 10) 30 | assert.are.are_same("с отЭ", res) 31 | end) 32 | end) 33 | 34 | describe("`calc_ranges()`:", function() 35 | it("Found expected letters with English in `left` direction", function() 36 | local s = "This is line on English language" 37 | local res = fftt.calc_ranges(s, "left", 1) 38 | assert.are_same( 39 | { "i", "l", "o", "E", "a" }, 40 | vim 41 | .iter(res) 42 | :map(function(v) 43 | return v.char 44 | end) 45 | :totable() 46 | ) 47 | end) 48 | 49 | it("Found expected letters with Russian in `left` direction", function() 50 | local s = "Эта строка на русском языке сызнова" 51 | local res = fftt.calc_ranges(s, "left", 1) 52 | assert.are_same( 53 | { "с", "н", "у", "я", "в" }, 54 | vim 55 | .iter(res) 56 | :map(function(v) 57 | return v.char 58 | end) 59 | :totable() 60 | ) 61 | end) 62 | 63 | it("Found expected letters with English in `left` direction with big spaces", function() 64 | local s = "This is English line with big spaces" 65 | local res = fftt.calc_ranges(s, "left", 1) 66 | assert.are_same( 67 | { "i", "E", "e", "w", "b", "p" }, 68 | vim 69 | .iter(res) 70 | :map(function(v) 71 | return v.char 72 | end) 73 | :totable() 74 | ) 75 | end) 76 | 77 | it("Found expected letters with English in `right` direction", function() 78 | local s = "This is line on English language" 79 | 80 | local res = fftt.calc_ranges(s, "right", 31) 81 | assert.are_same( 82 | { "h", "o", "e", "s", "T" }, 83 | vim 84 | .iter(res) 85 | :map(function(v) 86 | return v.char 87 | end) 88 | :totable() 89 | ) 90 | end) 91 | 92 | it("Found expected letters with Russian in `right` direction", function() 93 | local s = "Эта строка на русском языке сызнова" 94 | local res = fftt.calc_ranges(s, "right", 63) 95 | assert.are_same( 96 | { "е", "м", "а", "т", "Э" }, 97 | vim 98 | .iter(res) 99 | :map(function(v) 100 | return v.char 101 | end) 102 | :totable() 103 | ) 104 | end) 105 | 106 | it("Found expected letters with English in `right` direction with big spaces", function() 107 | local s = "This is English line with big spaces" 108 | local res = fftt.calc_ranges(s, "right", 58) 109 | assert.are_same( 110 | { "g", "h", "n", "E", "s", "T" }, 111 | vim 112 | .iter(res) 113 | :map(function(v) 114 | return v.char 115 | end) 116 | :totable() 117 | ) 118 | end) 119 | end) 120 | -------------------------------------------------------------------------------- /lua/modules/fftt/types.lua: -------------------------------------------------------------------------------- 1 | ---@class WordRange 2 | ---@field offset Offset 3 | ---@field chars Char[] 4 | ---@field rare_char Char 5 | 6 | ---@class Char 7 | ---@field index number 8 | ---@field char string 9 | ---@field offset Offset 10 | ---@field frequency number? 11 | 12 | ---@class Offset 13 | ---@field start number 14 | ---@field ["end"] number 15 | 16 | ---@alias CharCounter table 17 | -------------------------------------------------------------------------------- /lua/modules/foldtext.lua: -------------------------------------------------------------------------------- 1 | ---@module Foldtext 2 | ---Based on https://www.reddit.com/r/neovim/comments/16sqyjz/finally_we_can_have_highlighted_folds/ 3 | ---Updated with vim.treesitter._fold.foldtext() 4 | 5 | local function parse_line(linenr) 6 | local bufnr = vim.api.nvim_get_current_buf() 7 | 8 | local line = vim.api.nvim_buf_get_lines(bufnr, linenr - 1, linenr, false)[1] 9 | if not line then 10 | return nil 11 | end 12 | 13 | local ok, parser = pcall(vim.treesitter.get_parser, bufnr) 14 | if not ok then 15 | return nil 16 | end 17 | 18 | local query = vim.treesitter.query.get(parser:lang(), "highlights") 19 | if not query then 20 | return nil 21 | end 22 | 23 | local tree = parser:parse({ linenr - 1, linenr })[1] 24 | 25 | local result = {} 26 | 27 | local line_pos = 0 28 | 29 | for id, node, metadata in query:iter_captures(tree:root(), 0, linenr - 1, linenr) do 30 | local name = query.captures[id] 31 | local start_row, start_col, end_row, end_col = node:range() 32 | 33 | local priority = tonumber(metadata.priority or vim.highlight.priorities.treesitter) 34 | 35 | if start_row == linenr - 1 and end_row == linenr - 1 then 36 | -- check for characters ignored by treesitter 37 | if start_col > line_pos then 38 | table.insert(result, { 39 | line:sub(line_pos + 1, start_col), 40 | { { "Folded", priority } }, 41 | range = { line_pos, start_col }, 42 | }) 43 | end 44 | line_pos = end_col 45 | 46 | local text = line:sub(start_col + 1, end_col) 47 | table.insert(result, { text, { { "@" .. name, priority } }, range = { start_col, end_col } }) 48 | end 49 | end 50 | 51 | local i = 1 52 | while i <= #result do 53 | -- find first capture that is not in current range and apply highlights on the way 54 | local j = i + 1 55 | while j <= #result and result[j].range[1] >= result[i].range[1] and result[j].range[2] <= result[i].range[2] do 56 | for k, v in ipairs(result[i][2]) do 57 | if not vim.tbl_contains(result[j][2], v) then 58 | table.insert(result[j][2], k, v) 59 | end 60 | end 61 | j = j + 1 62 | end 63 | 64 | -- remove the parent capture if it is split into children 65 | if j > i + 1 then 66 | table.remove(result, i) 67 | else 68 | -- highlights need to be sorted by priority, on equal prio, the deeper nested capture (earlier 69 | -- in list) should be considered higher prio 70 | if #result[i][2] > 1 then 71 | table.sort(result[i][2], function(a, b) 72 | return a[2] < b[2] 73 | end) 74 | end 75 | 76 | result[i][2] = vim.tbl_map(function(tbl) 77 | return tbl[1] 78 | end, result[i][2]) 79 | result[i] = { result[i][1], result[i][2] } 80 | 81 | i = i + 1 82 | end 83 | end 84 | 85 | return result 86 | end 87 | 88 | function HighlightedFoldtext() 89 | local result = parse_line(vim.v.foldstart) 90 | if not result then 91 | return vim.fn.foldtext() 92 | end 93 | 94 | local folded = { 95 | { " ", "FoldedIcon" }, 96 | { "+" .. vim.v.foldend - vim.v.foldstart .. " lines", "FoldedText" }, 97 | { " ", "FoldedIcon" }, 98 | } 99 | 100 | for _, item in ipairs(folded) do 101 | table.insert(result, item) 102 | end 103 | 104 | local result2 = parse_line(vim.v.foldend) 105 | if result2 and #result2 > 0 then 106 | local first = result2[1] 107 | result2[1] = { vim.trim(first[1]), first[2] } 108 | for _, item in ipairs(result2) do 109 | table.insert(result, item) 110 | end 111 | end 112 | 113 | return result 114 | end 115 | 116 | local function set_fold_hl() 117 | local nf = vim.api.nvim_get_hl(0, { name = "NormalFloat", link = false }) 118 | local comment = vim.api.nvim_get_hl(0, { name = "Comment", link = false }) 119 | vim.api.nvim_set_hl(0, "FoldedIcon", { fg = nf.bg }) 120 | vim.api.nvim_set_hl(0, "FoldedText", { bg = nf.bg, fg = comment.fg, italic = true }) 121 | end 122 | 123 | set_fold_hl() 124 | 125 | vim.api.nvim_create_autocmd("ColorScheme", { 126 | callback = set_fold_hl, 127 | }) 128 | 129 | return 'luaeval("HighlightedFoldtext")()' 130 | -------------------------------------------------------------------------------- /lua/modules/git_watcher.lua: -------------------------------------------------------------------------------- 1 | -- Temporary solution for checks if git is 'dirty' 2 | if vim.fn.has("nvim-0.10") ~= 1 then 3 | return 4 | end 5 | 6 | local function set_interval(callback, interval) 7 | local timer = vim.loop.new_timer() 8 | timer:start(0, interval, vim.schedule_wrap(callback)) 9 | return timer 10 | end 11 | 12 | local function update_git_status() 13 | vim.system({ "git", "status", "--porcelain" }, { text = true, timeout = 1000 }, function(res) 14 | if res.signal ~= 0 then 15 | return 16 | end 17 | local prev_dirty = vim.g.__git_dirty 18 | local new_dirty = vim.trim(res.stdout) ~= "" 19 | if prev_dirty ~= new_dirty then 20 | vim.g.__git_dirty = new_dirty 21 | end 22 | end) 23 | end 24 | 25 | local function update_git_branch() 26 | vim.system({ "git", "branch", "--show-current" }, { text = true, timeout = 1000 }, function(res) 27 | if res.signal ~= 0 then 28 | return 29 | end 30 | local prev_branch = vim.g.__git_branch 31 | local new_branch = vim.trim(res.stdout) 32 | if prev_branch ~= new_branch then 33 | vim.g.__git_branch = new_branch 34 | end 35 | end) 36 | end 37 | 38 | local function update_git() 39 | update_git_status() 40 | update_git_branch() 41 | end 42 | 43 | local interval_timer 44 | 45 | vim.api.nvim_create_autocmd("VimEnter", { 46 | callback = function() 47 | vim.g.__git_branch = "" 48 | vim.g.__git_dirty = false 49 | interval_timer = set_interval(update_git, 3000) 50 | end, 51 | }) 52 | 53 | vim.api.nvim_create_autocmd("VimLeavePre", { 54 | callback = function() 55 | if interval_timer then 56 | interval_timer:stop() 57 | end 58 | end, 59 | }) 60 | -------------------------------------------------------------------------------- /lua/modules/gpt/api.lua: -------------------------------------------------------------------------------- 1 | local curl = require("plenary.curl") 2 | 3 | local M = {} 4 | 5 | function M.fetch(messages, on_delta, on_complete) 6 | local url = "https://ai.fakeopen.com/v1/chat/completions" 7 | 8 | local headers = { 9 | Authorization = "Bearer pk-this-is-a-real-free-pool-token-for-everyone", 10 | Content_Type = "application/json", 11 | Origin = "https://chat.geekgpt.org", 12 | Referer = "https://chat.geekgpt.org", 13 | } 14 | 15 | curl.post(url, { 16 | headers = headers, 17 | body = vim.fn.json_encode({ 18 | model = "gpt-3.5-turbo", 19 | temperature = 1, 20 | messages = messages, 21 | stream = true, 22 | }), 23 | stream = vim.schedule_wrap(function(err, data, bla) 24 | if err or vim.startswith(data, '"error":') then 25 | error(data or err) 26 | return 27 | end 28 | 29 | local raw_message = string.gsub(data, "^data: ", "") 30 | 31 | if raw_message == "[DONE]" then 32 | on_complete() 33 | elseif string.len(data) > 6 then 34 | local ok, json = pcall(vim.fn.json_decode, string.sub(vim.trim(data), 6)) 35 | if not ok then 36 | return 37 | end 38 | on_delta(json) 39 | end 40 | end), 41 | }) 42 | end 43 | 44 | return M 45 | -------------------------------------------------------------------------------- /lua/modules/gpt/gpt.lua: -------------------------------------------------------------------------------- 1 | local u = require("utils") 2 | local api = require("modules.gpt.api") 3 | 4 | local USER = { "# User:" } 5 | local ASSISTANT = { "# Assistant:" } 6 | 7 | local GPT = {} 8 | GPT.__index = GPT 9 | 10 | function GPT.new(opts) 11 | return setmetatable({ 12 | opts = opts, 13 | messages = {}, 14 | layout = nil, 15 | }, GPT) 16 | end 17 | 18 | function GPT:run() 19 | self:open_win() 20 | end 21 | 22 | local function is_valid_response(r) 23 | return r and r.choices and r.choices[1] and r.choices[1].delta and r.choices[1].delta.content 24 | end 25 | 26 | function GPT:send_request() 27 | if not self.layout then 28 | self:open_win() 29 | end 30 | 31 | local res_buf = self.layout.result.buf 32 | local prompt_buf = self.layout.prompt.buf 33 | local count = vim.api.nvim_buf_line_count(res_buf) 34 | 35 | local request = vim.api.nvim_buf_get_lines(prompt_buf, 0, -1, false) 36 | self:add_message({ role = "user", content = vim.fn.join(request, "\n") }) 37 | vim.api.nvim_buf_set_lines(res_buf, count, count, false, u.concat(USER, request, { "" }, ASSISTANT, { "..." })) 38 | 39 | -- To replace placeholder (...) 40 | local cur_line = vim.api.nvim_buf_line_count(res_buf) - 1 41 | 42 | local content = "" 43 | local answer = { role = "assistant", content = "" } 44 | 45 | vim.api.nvim_set_current_win(self.layout.result.win) 46 | 47 | local on_delta = function(response) 48 | if not is_valid_response(response) then 49 | return 50 | end 51 | 52 | local delta = response.choices[1].delta.content 53 | answer.content = answer.content .. delta 54 | 55 | if delta == "\n" then 56 | vim.api.nvim_buf_set_lines(res_buf, cur_line, cur_line + 1, false, { content, "" }) 57 | cur_line = cur_line + 1 58 | content = "" 59 | elseif delta:match("\n") then 60 | for line in delta:gmatch("[^\n]+") do 61 | vim.api.nvim_buf_set_lines(res_buf, cur_line, cur_line + 1, false, { content .. line, "" }) 62 | cur_line = cur_line + 1 63 | content = "" 64 | end 65 | else 66 | content = content .. delta 67 | end 68 | 69 | vim.cmd.normal("G100|") 70 | end 71 | 72 | local on_complete = function() 73 | vim.api.nvim_buf_set_lines(res_buf, cur_line, cur_line + 1, false, { content, "" }) 74 | self:add_message(answer) 75 | vim.api.nvim_buf_set_lines(prompt_buf, 0, -1, false, {}) 76 | vim.api.nvim_set_current_win(self.layout.prompt.win) 77 | vim.cmd.startinsert() 78 | end 79 | 80 | api.fetch(self.messages, on_delta, on_complete) 81 | end 82 | 83 | function GPT:open_win() 84 | self.layout = require("modules.gpt.ui").get_layout() 85 | self:set_keymaps() 86 | self:print_messages() 87 | vim.cmd.startinsert() 88 | end 89 | 90 | function GPT:clear_messages() 91 | self.messages = {} 92 | self:print_messages() 93 | end 94 | 95 | function GPT:print_messages() 96 | local buf = self.layout.result.buf 97 | local count = vim.api.nvim_buf_line_count(buf) + 1 98 | 99 | if vim.tbl_isempty(self.messages) then 100 | vim.api.nvim_buf_set_lines(buf, 0, -1, false, {}) 101 | return 102 | end 103 | 104 | for _, message in ipairs(self.messages) do 105 | if message.role == "user" then 106 | vim.api.nvim_buf_set_lines(buf, count, count, false, u.concat(USER, vim.split(message.content, "\n"))) 107 | else 108 | vim.api.nvim_buf_set_lines(buf, count, count, false, u.concat(ASSISTANT, vim.split(message.content, "\n"))) 109 | end 110 | count = vim.api.nvim_buf_line_count(buf) + 1 111 | end 112 | end 113 | 114 | function GPT:set_keymaps() 115 | local layout = self.layout 116 | local close = function() 117 | vim.api.nvim_win_close(layout.result.win, true) 118 | vim.api.nvim_win_close(layout.prompt.win, true) 119 | vim.api.nvim_buf_delete(layout.result.buf, { force = true }) 120 | vim.api.nvim_buf_delete(layout.prompt.buf, { force = true }) 121 | vim.cmd.stopinsert() 122 | end 123 | 124 | vim.keymap.set("n", "q", close, { buffer = layout.prompt.buf }) 125 | vim.keymap.set("n", "q", close, { buffer = layout.result.buf }) 126 | 127 | vim.keymap.set({ "n", "i" }, "", close, { buffer = layout.prompt.buf }) 128 | vim.keymap.set({ "n", "i" }, "", close, { buffer = layout.result.buf }) 129 | 130 | vim.keymap.set("i", "", function() 131 | self:clear_messages() 132 | end, { buffer = layout.prompt.buf }) 133 | 134 | vim.keymap.set("n", "", function() 135 | self:send_request() 136 | end, { buffer = layout.prompt.buf }) 137 | end 138 | 139 | ---Add message to messages 140 | ---@param message {role: string, content: string} 141 | function GPT:add_message(message) 142 | table.insert(self.messages, message) 143 | end 144 | 145 | return GPT 146 | -------------------------------------------------------------------------------- /lua/modules/gpt/init.lua: -------------------------------------------------------------------------------- 1 | -- NOT WORKING NOW: ai.fakeopen.com is not active 2 | 3 | -- Knowleges and based on: https://github.com/CamdenClark/flyboy 4 | local M = {} 5 | M.__index = M 6 | 7 | local gpt = require("modules.gpt.gpt").new() 8 | 9 | function M:open() 10 | if not gpt then 11 | gpt = require("modules.gpt.gpt").new() 12 | end 13 | 14 | gpt:run() 15 | end 16 | 17 | return M 18 | -------------------------------------------------------------------------------- /lua/modules/gpt/ui.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.get_layout() 4 | local width = 100 5 | 6 | local prompt = { 7 | border = "single", 8 | height = 10, 9 | title = " Ask anything (md syntax): ", 10 | zindex = 51, -- should be above result window 11 | } 12 | 13 | local prompt_shift = prompt.border ~= "none" and 2 or 0 14 | 15 | local result = { 16 | height = (vim.opt.lines:get() - 10) - (prompt.height + prompt_shift), 17 | title = " Chat GPT: ", 18 | border = "none", 19 | zindex = 50, 20 | } 21 | 22 | local result_shift = result.border ~= "none" and 2 or 0 23 | result.height = result.height + result_shift 24 | 25 | result.row = math.floor((vim.opt.lines:get() - result.height - (prompt.height + prompt_shift)) / 2) 26 | prompt.row = result.height + 5 27 | 28 | prompt.width = width - prompt_shift 29 | result.width = width - result_shift 30 | 31 | local common_opts = { 32 | relative = "editor", 33 | border = "none", 34 | style = "minimal", 35 | width = width, 36 | col = math.floor((vim.opt.columns:get() - width) / 2), 37 | } 38 | 39 | local res_buf, res_win = M.open_win(false, vim.tbl_deep_extend("force", common_opts, result)) 40 | local prompt_buf, prompt_win = M.open_win(true, vim.tbl_deep_extend("force", common_opts, prompt)) 41 | 42 | vim.api.nvim_set_option_value("filetype", "markdown", { buf = res_buf }) 43 | vim.api.nvim_set_option_value("filetype", "markdown", { buf = prompt_buf }) 44 | 45 | vim.wo[res_win].wrap = true 46 | vim.wo[prompt_win].wrap = true 47 | 48 | vim.wo[res_win].statuscolumn = " " 49 | vim.wo[prompt_win].statuscolumn = " " 50 | 51 | vim.wo[res_win].winhl = 52 | "Normal:TelescopeResultsNormal,LineNr:TelescopeResultsNormal,WinBar:TelescopeResultsNormal,WinBarNC:TelescopeResultsNormal" 53 | vim.wo[prompt_win].winhl = 54 | "Normal:TelescopePromptNormal,LineNr:TelescopePromptNormal,WinBar:TelescopePromptNormal,WinBarNC:TelescopePromptNormal" 55 | 56 | vim.wo[prompt_win].winbar = " " 57 | vim.wo[res_win].scrolloff = 5 58 | 59 | return { 60 | prompt = { buf = prompt_buf, win = prompt_win }, 61 | result = { buf = res_buf, win = res_win }, 62 | } 63 | end 64 | 65 | function M.open_win(enter, opts) 66 | local buf = vim.api.nvim_create_buf(false, true) 67 | local win = vim.api.nvim_open_win(buf, enter, opts) 68 | return buf, win 69 | end 70 | 71 | return M 72 | -------------------------------------------------------------------------------- /lua/modules/improve-visual-block.lua: -------------------------------------------------------------------------------- 1 | -- Adding visual control for visual-block-mode 2 | -- WARNING: WIP 3 | 4 | local M = {} 5 | 6 | M.ns = vim.api.nvim_create_namespace("__parts.improve-visual-block__") 7 | M.text_changed_id = nil 8 | M.is_dollar = false 9 | M.is_append = false 10 | 11 | M.opts = { 12 | hls = { 13 | preview = "Comment", 14 | edited_text = "", -- Keep it empty if you want to use original hl while editing 15 | }, 16 | } 17 | 18 | function M.setup(opts) 19 | M.opts = not opts and M.opts or vim.tbl_deep_extend("force", M.opts, opts) 20 | 21 | vim.api.nvim_create_autocmd("ModeChanged", { 22 | pattern = "\22:i", 23 | callback = function() 24 | local v_start = vim.fn.getpos("'<") 25 | local v_end = vim.fn.getpos("'>") 26 | -- Must use the number of the displayed column, not a byte number, 27 | -- to work with multibyte characters. 28 | local col = vim.fn.charcol(".") - 1 29 | 30 | local line_count = v_end[2] - v_start[2] - 1 31 | 32 | M.text_changed_id = vim.api.nvim_create_autocmd("TextChangedI", { 33 | nested = true, 34 | callback = function() 35 | local ok, _ = pcall(vim.api.nvim_buf_clear_namespace, 0, M.ns, 0, -1) 36 | if not ok then 37 | return 38 | end 39 | 40 | local sr, sc, er, ec = unpack(_G.__last_insert_range) 41 | if ec < sc then 42 | return 43 | end 44 | 45 | local text = vim.api.nvim_buf_get_text(0, sr, sc, er, ec, {})[1] 46 | 47 | -- hl for place where really editing text 48 | vim.api.nvim_buf_set_extmark(0, M.ns, sr, sc, { 49 | end_col = ec, 50 | hl_group = M.opts.hls.edited_text, 51 | strict = false, 52 | }) 53 | 54 | -- hl and extmarks for preview 55 | for i = 0, line_count do 56 | local cur_line = i + v_start[2] + 1 57 | local line = vim.api.nvim_buf_get_lines(0, cur_line - 1, cur_line, false)[1] 58 | 59 | if not line then 60 | return 61 | end 62 | 63 | local spaces = "" 64 | local is_need_set_extmark = true 65 | 66 | if not M.is_append then 67 | is_need_set_extmark = col == 0 or not (line == "" or #line < col) 68 | end 69 | 70 | if is_need_set_extmark then 71 | if not M.is_dollar and #line < col then 72 | spaces = (" "):rep(col - #line) 73 | end 74 | 75 | if M.is_dollar then 76 | col = #line 77 | end 78 | 79 | vim.api.nvim_buf_set_extmark(0, M.ns, cur_line - 1, col, { 80 | virt_text = { { spaces, "NonText" }, { text, M.opts.hls.preview } }, 81 | virt_text_pos = "inline", 82 | strict = false, 83 | priority = 100, 84 | }) 85 | end 86 | end 87 | end, 88 | }) 89 | end, 90 | }) 91 | 92 | vim.on_key(function(key) 93 | if vim.api.nvim_get_mode().mode ~= "\22" then 94 | return 95 | end 96 | 97 | if key == "$" then 98 | M.is_dollar = true 99 | return 100 | end 101 | 102 | if key ~= "A" and M.is_dollar then 103 | M.is_dollar = false 104 | return 105 | end 106 | 107 | M.is_append = key == "A" 108 | end, M.ns) 109 | 110 | -- Clear after insert stop 111 | vim.api.nvim_create_autocmd("InsertLeave", { 112 | callback = function() 113 | -- TODO: Check, if already cleared 114 | pcall(vim.api.nvim_del_autocmd, M.text_changed_id) 115 | pcall(vim.api.nvim_buf_clear_namespace, 0, M.ns, 0, -1) 116 | M.is_dollar = false 117 | M.is_append = false 118 | end, 119 | }) 120 | end 121 | 122 | return M 123 | -------------------------------------------------------------------------------- /lua/modules/key_listener.lua: -------------------------------------------------------------------------------- 1 | local listener_ls = vim.api.nvim_create_namespace("key_listener") 2 | 3 | ---Deleting hlsearch when it already no needed 4 | local function toggle_hlsearch(char) 5 | local keys = { "", "n", "N", "*", "#", "?", "/" } 6 | local new_hlsearch = vim.tbl_contains(keys, char) and 1 or 0 7 | 8 | if vim.api.nvim_get_vvar("hlsearch") ~= new_hlsearch then 9 | vim.api.nvim_set_vvar("hlsearch", new_hlsearch) 10 | end 11 | end 12 | 13 | ---Handler for pressing keys. Added listeners for modes 14 | ---@param char string 15 | local function key_listener(char) 16 | local key = vim.fn.keytrans(char) 17 | local mode = vim.fn.mode() 18 | if mode == "n" then 19 | toggle_hlsearch(key) 20 | end 21 | end 22 | 23 | vim.on_key(key_listener, listener_ls) 24 | -------------------------------------------------------------------------------- /lua/modules/lazygit/config.yml: -------------------------------------------------------------------------------- 1 | customCommands: 2 | - key: "G" 3 | # TODO: check if this is a file under cursor. 4 | command: "echo '{{.SelectedFile.Name}}' > $HOME/.config/nvim/lua/modules/lazygit/tmp" 5 | description: "Write file(s) under cursor to the tmp file" 6 | context: "files" 7 | -------------------------------------------------------------------------------- /lua/modules/lazygit/init.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Attempt to use lazygit inside Neovim with file opening support. 3 | Opening implemented like in yazi, nnn and ranger: store file(s) name in tmp file and read it when 4 | file should be opened 5 | ]] 6 | 7 | local ok, t = pcall(require, "toggleterm.terminal") 8 | 9 | if not ok then 10 | return 11 | end 12 | 13 | local map = vim.keymap.set 14 | local hl = vim.api.nvim_set_hl 15 | 16 | local function size(max, value) 17 | return value > 1 and math.min(value, max) or math.floor(max * value) 18 | end 19 | 20 | local width = size(vim.opt.columns:get(), 0.8) 21 | local height = size(vim.opt.lines:get(), 0.8) 22 | local col = math.floor((vim.opt.columns:get() - width) / 2) 23 | local row = math.floor((vim.opt.lines:get() - height) / 2) 24 | 25 | local ns = vim.api.nvim_create_namespace("__parts.lazygit__") 26 | local lg_config = vim.fs.joinpath(vim.fn.stdpath("config")--[[@as string]], "lua/modules/lazygit", "config.yml") 27 | local tmp_path = vim.fs.joinpath(vim.fn.stdpath("config")--[[@as string]], "/lua/modules/lazygit/tmp") 28 | 29 | local lazygit = t.Terminal:new({ 30 | cmd = "lazygit -ucf " .. lg_config, 31 | dir = "git_dir", 32 | direction = "float", 33 | close_on_exit = true, 34 | float_opts = { 35 | relative = "editor", 36 | border = "double", 37 | style = "minimal", 38 | col = col, 39 | row = row, 40 | width = width, 41 | height = height, 42 | }, 43 | on_exit = vim.schedule_wrap(function() 44 | local files_ok, files = pcall(vim.fn.readfile, tmp_path) 45 | if not files_ok then 46 | return 47 | end 48 | vim.fn.delete(tmp_path) 49 | -- File is now a single file, but in the future it can be an array. 50 | for _, file in ipairs(files) do 51 | vim.cmd.edit(file) 52 | end 53 | end), 54 | on_open = function(term) 55 | local norm = vim.api.nvim_get_hl(0, { name = "Normal" }) 56 | local val = vim.tbl_deep_extend("force", norm, { bg = "#000000" }) 57 | hl(ns, "NormalFloat", val) 58 | hl(ns, "FloatBorder", val) 59 | vim.api.nvim_win_set_hl_ns(term.window, ns) 60 | 61 | map("t", "", "", { buffer = term.bufnr }) 62 | map("t", "o", function() 63 | vim.api.nvim_feedkeys(vim.keycode("G"), "n", true) 64 | vim.defer_fn(function() -- don't works with just `schedule` 65 | term:shutdown() 66 | term:close() 67 | end, 0) 68 | end, { buffer = term.bufnr }) 69 | end, 70 | }) 71 | 72 | vim.keymap.set({ "n", "i", "t" }, "", function() 73 | lazygit:toggle() 74 | end) 75 | -------------------------------------------------------------------------------- /lua/modules/marks.lua: -------------------------------------------------------------------------------- 1 | --[[ Small plugin to add visual control for marks in the current buffer ]] 2 | 3 | local ns = vim.api.nvim_create_namespace("__parks.marks__") 4 | local M = {} 5 | 6 | M.ns_extmark = nil 7 | 8 | M.opts = { 9 | dim_mark_lines = true, 10 | signcolumn = false, 11 | labels = true, 12 | hl = { 13 | dim = "Comment", 14 | col = "Constant", 15 | mark = "IncSearch", 16 | }, 17 | } 18 | 19 | function M.setup(opts) 20 | opts = vim.tbl_deep_extend("force", opts or {}, M.opts) 21 | 22 | vim.on_key(function(key, typed) 23 | if M.ns_extmark then 24 | vim.api.nvim_buf_clear_namespace(0, M.ns_extmark, 0, -1) 25 | M.ns_extmark = nil 26 | return 27 | end 28 | 29 | local is_pending = vim.fn.state("o") ~= "" 30 | if vim.fn.mode() ~= "n" or is_pending then 31 | return 32 | end 33 | 34 | if not vim.list_contains({ "'", "`" }, key) then 35 | return 36 | end 37 | 38 | M.ns_extmark = vim.api.nvim_create_namespace("__parts.marks.extmark__") 39 | local marks = vim.fn.getmarklist("%") 40 | 41 | for _, mark in ipairs(marks) do 42 | local linenr = mark.pos[2] - 1 43 | local col = mark.pos[3] 44 | 45 | if M.opts.signcolumn then 46 | vim.api.nvim_buf_set_extmark(0, M.ns_extmark, linenr, 0, { 47 | sign_text = (mark.mark):sub(2, 2), 48 | priority = 99, 49 | sign_hl_group = opts.hl.col, 50 | }) 51 | end 52 | 53 | if M.opts.dim_mark_lines then 54 | local dim_start = 0 55 | local dim_end = #(vim.api.nvim_buf_get_lines(0, 0, -1, false)[linenr + 1] or "") 56 | vim.api.nvim_buf_set_extmark(0, M.ns_extmark, linenr, dim_start, { 57 | end_col = dim_end, 58 | hl_group = M.opts.hl.dim, 59 | strict = false, 60 | }) 61 | end 62 | 63 | if opts.labels then 64 | vim.api.nvim_buf_set_extmark(0, M.ns_extmark, linenr, col - 1 < 0 and 0 or col - 1, { 65 | virt_text = { { mark.mark:sub(2, 2), opts.hl.mark } }, 66 | virt_text_pos = "overlay", 67 | strict = false, 68 | }) 69 | end 70 | 71 | vim.cmd.redraw() 72 | end 73 | end, ns) 74 | end 75 | 76 | return M 77 | -------------------------------------------------------------------------------- /lua/modules/missnode.lua: -------------------------------------------------------------------------------- 1 | ---NO READY TO USE 2 | 3 | ---Missing nodes adder 4 | ---USAGE EXAMPLE 5 | --- 6 | ---local missnode_adder = require('modules.missnode_adder') 7 | ---missnode_adder.setup({ --[[ settings ]] }) -- optional, work without setup with default 8 | ---vim.keymap.set('n', 'll', missnode_adder.insert_missing) 9 | --- 10 | ---vim.api.nvim_create_autocmd('FileType', { 11 | --- pattern = missnode_adder.get_langs(), 12 | --- callback = function() 13 | --- vim.api.nvim_create_autocmd('ModeChanged', { 14 | --- pattern = 'i:n', 15 | --- callback = missnode_adder.insert_missing, 16 | --- }) 17 | --- end, 18 | ---}) 19 | 20 | local M = {} -- module API 21 | local H = {} -- helpers 22 | local MissNodeAdder = {} -- functional 23 | MissNodeAdder.__index = MissNodeAdder 24 | 25 | local DEFAULT_OPTS = { 26 | langs = { 27 | rust = { 28 | missing_to_insert = { 29 | [";"] = { 30 | ---To decide whether to insert missing text or not, it is possible to check the node (sibling, parent, etc.). 31 | ---@type boolean|fun(node: TSNode): boolean 32 | enable = true, 33 | ---Text to insert. Needed when the type of the lost node is different from the text to be inserted. 34 | ---Can be a function that builds text (e.g., context-dependent). 35 | ---@type string|fun(node: TSNode): string 36 | text = ";", 37 | }, 38 | }, 39 | }, 40 | }, 41 | } 42 | 43 | M.opts = DEFAULT_OPTS 44 | 45 | local function _handle_node(opts, node) 46 | opts = opts.missing_to_insert[node:type()] 47 | local need_handle = opts and (type(opts.enable) == "boolean" and opts.enable or opts.enable(node)) 48 | 49 | if need_handle then 50 | local sr, sc, er, ec = node:range() 51 | local text = type(opts.text) == "string" and opts.text or opts.text(node) 52 | vim.api.nvim_buf_set_text(0, sr, sc, er, ec, { text }) 53 | end 54 | end 55 | 56 | function MissNodeAdder.new(lang, opts, root) 57 | return setmetatable({ root = root, opts = opts, lang = lang }, MissNodeAdder) 58 | end 59 | 60 | function MissNodeAdder:handle_tree() 61 | H.walk_tree(self.root, H.is_missing, H.bind(_handle_node, self.opts)) 62 | end 63 | 64 | -- API 65 | function M.get_langs() 66 | return vim.tbl_keys(M.opts.langs) 67 | end 68 | 69 | function M.insert_missing() 70 | local lang = vim.api.nvim_buf_get_option(0, "ft") 71 | local opts = M.opts.langs[lang] 72 | 73 | if not opts then 74 | return 75 | end 76 | 77 | local ok_p, parser = pcall(vim.treesitter.get_parser, 0, lang) 78 | if not ok_p then 79 | return 80 | end 81 | 82 | local tree = parser:trees()[1] 83 | local formatter = MissNodeAdder.new(lang, opts, tree:root()) 84 | 85 | formatter:handle_tree() 86 | end 87 | 88 | function M.setup(opts) 89 | M.opts = vim.tbl_deep_extend("force", M.opts, opts or {}) 90 | end 91 | 92 | -- HELPERS 93 | function H.bind(fn, first) 94 | return function(...) 95 | return fn(first, ...) 96 | end 97 | end 98 | 99 | function H.is_missing(node) 100 | return node:missing() 101 | end 102 | 103 | function H.walk_tree(node, fn_cond, handler) 104 | if fn_cond(node) then 105 | handler(node) 106 | end 107 | 108 | for child in node:iter_children() do 109 | H.walk_tree(child, fn_cond, handler) 110 | end 111 | end 112 | 113 | return M 114 | -------------------------------------------------------------------------------- /lua/modules/mode_nr.lua: -------------------------------------------------------------------------------- 1 | local PARTS_NAME = "__parts.mode_clnr__" 2 | local GR = vim.api.nvim_create_augroup(PARTS_NAME, { clear = true }) 3 | 4 | local M = {} 5 | 6 | ---Make options to override a color group. Take only foreground from %name group 7 | ---@param name string Name of base group 8 | ---@return vim.api.keyset.highlight 9 | function M.get_fg_from_hl(name) 10 | local fg = vim.api.nvim_get_hl(0, { name = name }).fg 11 | local bg = vim.api.nvim_get_hl(0, { name = "CursorLineNr" }).bg 12 | return { fg = fg, bg = bg, bold = true } 13 | end 14 | 15 | M.opts = { 16 | hls = { 17 | ["n"] = M.get_fg_from_hl("CursorLineNr"), 18 | ["i"] = M.get_fg_from_hl("String"), 19 | ["v"] = M.get_fg_from_hl("Statement"), 20 | ["r"] = M.get_fg_from_hl("Error"), 21 | }, 22 | } 23 | 24 | function M.setup(opts) 25 | M.opts = vim.tbl_deep_extend("force", M.opts, opts or {}) 26 | 27 | local mode_hl = "ModeCursorLine" 28 | local alias_pair = "CursorLineNr:" .. mode_hl 29 | 30 | vim.api.nvim_create_autocmd("WinLeave", { 31 | group = GR, 32 | callback = function() 33 | -- Do not change the color of the line number in an inactive window 34 | vim.wo.winhl = vim 35 | .iter(vim.split(vim.wo.winhl, ",")) 36 | :filter(function(pair) 37 | return pair ~= alias_pair 38 | end) 39 | :join(",") 40 | end, 41 | }) 42 | 43 | vim.api.nvim_create_autocmd("ModeChanged", { 44 | group = GR, 45 | callback = function() 46 | if not (vim.wo.number or vim.wo.relativenumber) then 47 | return 48 | end 49 | 50 | if not vim.wo.winhl:match(mode_hl) then 51 | vim.wo.winhl = (vim.wo.winhl == "" and "" or vim.wo.winhl .. ",") .. alias_pair 52 | end 53 | 54 | local mode = vim.fn.strtrans(vim.fn.mode()):lower():gsub("%W", "") 55 | local override = M.opts.hls[mode] or M.opts.hls.n 56 | 57 | vim.api.nvim_set_hl(0, mode_hl, override) 58 | end, 59 | }) 60 | end 61 | 62 | return M 63 | -------------------------------------------------------------------------------- /lua/modules/progress.lua: -------------------------------------------------------------------------------- 1 | -- Source: https://github.com/rockyzhang24/dotfiles/blob/master/.config/nvim/lua/rockyz/lsp/progress.lua 2 | -- Buffer number and window id for the floating window 3 | -- 4 | if vim.fn.has('nvim-0.10') ~= 1 then 5 | return 6 | end 7 | 8 | local bufnr 9 | local winid 10 | local spinner = { "⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷" } 11 | local idx = 0 12 | -- Progress is done or not 13 | local isDone = true 14 | 15 | -- Get the progress message for all clients. The format is 16 | -- "65%: [lua_ls] Loading Workspace: 123/1500 | [client2] xxx | [client3] xxx" 17 | local function get_lsp_progress_msg() 18 | -- Most code is grabbed from the source of vim.lsp.status() 19 | -- Ref: https://github.com/neovim/neovim/blob/master/runtime/lua/vim/lsp.lua 20 | local percentage = nil 21 | local all_messages = {} 22 | isDone = true 23 | for _, client in ipairs(vim.lsp.get_clients()) do 24 | local messages = {} 25 | for progress in client.progress do 26 | local value = progress.value 27 | if type(value) == "table" and value.kind then 28 | if value.kind ~= "end" then 29 | isDone = false 30 | end 31 | local message = value.message and (value.title .. ": " .. value.message) or value.title 32 | messages[#messages + 1] = message 33 | if value.percentage then 34 | percentage = math.max(percentage or 0, value.percentage) 35 | end 36 | end 37 | end 38 | if next(messages) ~= nil then 39 | table.insert(all_messages, "[" .. client.name .. "] " .. table.concat(messages, ", ")) 40 | end 41 | end 42 | local message = table.concat(all_messages, " | ") 43 | -- Show percentage 44 | if percentage then 45 | message = string.format("%3d%%: %s", percentage, message) 46 | end 47 | -- Show spinner 48 | idx = idx == #spinner * 4 and 1 or idx + 1 49 | message = spinner[math.ceil(idx / 4)] .. message 50 | return message 51 | end 52 | 53 | vim.api.nvim_create_autocmd({ "LspProgress" }, { 54 | pattern = "*", 55 | callback = function() 56 | -- The row position of the floating window. Just right above the status line. 57 | local win_row = vim.o.lines - vim.o.cmdheight - 4 58 | local message = get_lsp_progress_msg() 59 | if 60 | winid == nil 61 | or not vim.api.nvim_win_is_valid(winid) 62 | or vim.api.nvim_win_get_tabpage(winid) ~= vim.api.nvim_get_current_tabpage() 63 | then 64 | bufnr = vim.api.nvim_create_buf(false, true) 65 | winid = vim.api.nvim_open_win(bufnr, false, { 66 | relative = "editor", 67 | width = #message, 68 | height = 1, 69 | row = win_row, 70 | col = vim.o.columns - #message, 71 | style = "minimal", 72 | noautocmd = true, 73 | border = vim.g.border_style, 74 | }) 75 | else 76 | vim.api.nvim_win_set_config(winid, { 77 | relative = "editor", 78 | width = #message, 79 | row = win_row, 80 | col = vim.o.columns - #message, 81 | }) 82 | end 83 | vim.wo[winid].winhl = "Normal:Normal" 84 | vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, { message }) 85 | if isDone then 86 | if vim.api.nvim_win_is_valid(winid) then 87 | vim.api.nvim_win_close(winid, true) 88 | end 89 | if vim.api.nvim_buf_is_valid(bufnr) then 90 | vim.api.nvim_buf_delete(bufnr, { force = true }) 91 | end 92 | winid = nil 93 | idx = 0 94 | end 95 | end, 96 | }) 97 | -------------------------------------------------------------------------------- /lua/modules/punto-switcher.lua: -------------------------------------------------------------------------------- 1 | local u = require("utils") 2 | local ok, lm = pcall(require, "langmapper") 3 | if not ok then 4 | return 5 | end 6 | 7 | local lm_utils = require("langmapper.utils") 8 | 9 | local layouts = { 10 | ["com.apple.keylayout.ABC"] = "default", 11 | ["com.apple.keylayout.RussianWin"] = "ru", 12 | } 13 | 14 | _G.__last_insert_range = {} 15 | vim.api.nvim_create_autocmd({ "InsertEnter" }, { 16 | callback = function(e) 17 | local cur = vim.api.nvim_win_get_cursor(0) 18 | _G.__last_insert_range = { cur[1] - 1, cur[2], cur[1] - 1, cur[2] } 19 | end, 20 | }) 21 | 22 | vim.api.nvim_create_autocmd({ "TextChangedI" }, { 23 | callback = function(e) 24 | local cur = vim.api.nvim_win_get_cursor(0) 25 | -- Update range on new line 26 | if _G.__last_insert_range[1] ~= cur[1] - 1 then 27 | _G.__last_insert_range[1] = cur[1] - 1 28 | _G.__last_insert_range[2] = cur[2] 29 | _G.__last_insert_range[3] = cur[1] - 1 30 | end 31 | 32 | _G.__last_insert_range[4] = cur[2] 33 | end, 34 | }) 35 | 36 | vim.api.nvim_create_autocmd({ "InsertLeave", "WinLeave" }, { 37 | callback = function(e) 38 | _G.__last_insert_range = {} 39 | end, 40 | }) 41 | 42 | ---Switch recently inserted text or selected text to the opposite layout 43 | ---WARNING: While works for text on the same line and when cursor at the end of the selected text 44 | ---@param range number[] - start row, start col, end row, end col 45 | local function switch_range_layout(range) 46 | local sr, sc, er, ec = range[1], range[2], range[3], range[4] 47 | 48 | if sr ~= er or sc == ec then 49 | return 50 | end 51 | 52 | local from, to = u.layout.toggle() 53 | local text = vim.api.nvim_buf_get_text(0, sr, sc, er, ec, {})[1] 54 | local tr_text = lm_utils.translate_keycode(text, layouts[to], layouts[from]) 55 | local cursor = vim.api.nvim_win_get_cursor(0) 56 | 57 | -- 'ec' is not used because need to consider the length in bytes 58 | local ok_set_text, err = pcall(vim.api.nvim_buf_set_text, 0, sr, sc, er, sc + #text, { tr_text }) 59 | if not ok_set_text then 60 | vim.notify(err or "", vim.log.levels.WARN) 61 | return 62 | end 63 | 64 | if #text ~= #tr_text then 65 | local shift = vim.fn.mode() == "v" and -1 or 0 -- fix cursor position in visual mode 66 | vim.api.nvim_win_set_cursor(0, { cursor[1], sc + #tr_text + shift }) 67 | end 68 | end 69 | 70 | lm.map({ "i" }, "", function() 71 | switch_range_layout(_G.__last_insert_range) 72 | end) 73 | 74 | lm.map({ "i" }, "", function() 75 | local sr, sc, er, ec = unpack(_G.__last_insert_range) 76 | local text = vim.api.nvim_buf_get_text(0, sr, sc, er, ec, {})[1] 77 | local words = vim.split(text, "[%s%p]") 78 | switch_range_layout({ sr, ec - #words[#words], er, ec }) 79 | end) 80 | 81 | lm.map({ "v" }, "", function() 82 | local range = u.get_visual_range() 83 | switch_range_layout({ range[1] - 1, range[2], range[3] - 1, range[4] }) 84 | end) 85 | 86 | lm.map("c", "", function() 87 | local cmd = vim.fn.getcmdline() 88 | local from, to = u.layout.toggle() 89 | cmd = lm_utils.translate_keycode(cmd, layouts[to], layouts[from]) 90 | vim.fn.setcmdline(cmd) 91 | vim.cmd.redraw() 92 | end) 93 | -------------------------------------------------------------------------------- /lua/modules/router.lua: -------------------------------------------------------------------------------- 1 | -- No needed with require("vim._extui").enable({}) 2 | 3 | local u = require("utils") 4 | 5 | local buf_message = { 6 | abort = false, 7 | title = "These aren't the :buffers you're looking for", 8 | } 9 | 10 | local route_cmd = { 11 | mes = { 12 | abort = { "clear" }, 13 | title = "What’s this :mess my config just created", 14 | }, 15 | ls = buf_message, 16 | buffers = buf_message, 17 | files = buf_message, 18 | ["lua="] = { 19 | title = "Outro lado da :lua", 20 | abort = false, 21 | }, 22 | } 23 | 24 | local function open_split(cmd, title) 25 | local result = vim.split(vim.fn.execute(cmd), "\n") 26 | result = vim.tbl_filter(function(line) 27 | return line ~= "" 28 | end, result) 29 | 30 | local height = 30 31 | title = #result == 0 and "Wow! So clean!" or title 32 | 33 | local buf = vim.api.nvim_create_buf(false, true) 34 | 35 | local win = vim.api.nvim_open_win(buf, true, { 36 | relative = "editor", 37 | width = vim.opt.columns:get(), 38 | height = height <= 5 and 5 or height, 39 | col = 0, 40 | row = vim.opt.lines:get(), 41 | style = "minimal", 42 | border = "solid", 43 | title = title, 44 | title_pos = "left", 45 | noautocmd = true, 46 | }) 47 | 48 | vim.api.nvim_buf_set_lines(buf, 0, -1, true, result) 49 | vim.cmd.norm("G") 50 | vim.keymap.set("n", "q", function() 51 | vim.api.nvim_win_close(win, true) 52 | vim.api.nvim_buf_delete(buf, { force = true }) 53 | end, { buffer = buf }) 54 | end 55 | 56 | local function need_route(cmd) 57 | local start, end_ = cmd:find("^%d+") 58 | local cleared = vim.trim(cmd) 59 | local has, need, data 60 | 61 | if start and end_ then 62 | cleared = vim.trim(cmd:sub(end_ + 1)) 63 | end 64 | 65 | local commands = vim.tbl_keys(route_cmd) 66 | local key = "" 67 | 68 | has = u.some(commands, function(el) 69 | local found = vim.startswith(cleared, el) 70 | if found then 71 | key = el 72 | end 73 | return found 74 | end) 75 | 76 | if has then 77 | data = route_cmd[key] 78 | if data.abort then 79 | need = not u.some(data.abort, function(el) 80 | return cleared:match(el) 81 | end) 82 | else 83 | need = true 84 | end 85 | end 86 | 87 | return (has and need), data 88 | end 89 | 90 | vim.api.nvim_create_autocmd("CmdlineLeave", { 91 | callback = function() 92 | local event = vim.v.event 93 | if not event.abort and event.cmdtype == ":" then 94 | local cmd = vim.fn.getcmdline() 95 | local need, data = need_route(cmd) 96 | if need then 97 | vim.fn.setcmdline(cmd) -- to save history 98 | u.feedkeys("") -- abort current cmd 99 | open_split(cmd, data.title) -- execute cmd and redirect to new window 100 | end 101 | end 102 | end, 103 | }) 104 | -------------------------------------------------------------------------------- /lua/modules/status/autocmd.lua: -------------------------------------------------------------------------------- 1 | local group = vim.api.nvim_create_augroup("__status__", { clear = true }) 2 | 3 | local function set_hl() 4 | local statusline_hl = vim.api.nvim_get_hl(0, { name = "StatusLine" }) 5 | local string_hl = vim.api.nvim_get_hl(0, { name = "String" }) 6 | vim.api.nvim_set_hl(0, "TSStatusActive", { bg = statusline_hl.bg, fg = string_hl.fg }) 7 | vim.api.nvim_set_hl(0, "LSPStatusActive", { bg = statusline_hl.bg, fg = string_hl.fg }) 8 | vim.api.nvim_set_hl(0, "FormatterStatusActive", { bg = statusline_hl.bg, fg = string_hl.fg }) 9 | 10 | local clnr_hl = vim.api.nvim_get_hl(0, { name = "CursorLineNr" }) 11 | local diag_err_hl = vim.api.nvim_get_hl(0, { name = "DiagnosticError" }) 12 | local diag_hint_hl = vim.api.nvim_get_hl(0, { name = "DiagnosticHint" }) 13 | local diag_info_hl = vim.api.nvim_get_hl(0, { name = "DiagnosticInfo" }) 14 | vim.api.nvim_set_hl(0, "NormalStatus", { bg = clnr_hl.fg }) 15 | vim.api.nvim_set_hl(0, "InsertStatus", { bg = diag_info_hl.fg }) 16 | vim.api.nvim_set_hl(0, "VisualStatus", { bg = diag_hint_hl.fg }) 17 | vim.api.nvim_set_hl(0, "ReplaceStatus", { bg = diag_err_hl.fg }) 18 | vim.api.nvim_set_hl(0, "VisualRangeNr", { bg = clnr_hl.bg, fg = clnr_hl.fg, bold = false }) 19 | 20 | -- Git indicator 21 | vim.api.nvim_set_hl(0, "StatusGitClean", { fg = "#00af87", bg = statusline_hl.bg }) 22 | vim.api.nvim_set_hl(0, "StatusGitDirty", { fg = "#870000", bg = statusline_hl.bg }) 23 | end 24 | 25 | set_hl() 26 | vim.api.nvim_create_autocmd("ColorScheme", { 27 | desc = "Reload highlights when ColorScheme changed", 28 | group = group, 29 | callback = set_hl, 30 | }) 31 | 32 | vim.api.nvim_create_autocmd("User", { 33 | group = group, 34 | desc = "Hide statusline and command line in start dashboard", 35 | pattern = "AlphaReady", 36 | once = true, 37 | callback = function(event) 38 | local prev_status = vim.o.laststatus 39 | local prev_cmdheight = vim.o.cmdheight 40 | vim.o.laststatus = 0 41 | vim.o.cmdheight = 0 42 | vim.api.nvim_create_autocmd("BufUnload", { 43 | group = group, 44 | buffer = event.buf, 45 | once = true, 46 | callback = function() 47 | vim.o.laststatus = prev_status 48 | vim.o.cmdheight = prev_cmdheight 49 | end, 50 | }) 51 | end, 52 | }) 53 | -------------------------------------------------------------------------------- /lua/modules/status/init.lua: -------------------------------------------------------------------------------- 1 | require("modules.status.autocmd") 2 | local c = require("modules.status.components") 3 | 4 | local M = {} 5 | 6 | ---See :h 'statuscolumn' 7 | M.statuscolumn = { 8 | { "%s" }, 9 | { "%=", c.number }, 10 | { " ", c.foldcolumn, " " }, 11 | } 12 | 13 | ---See :h 'statusline' 14 | M.statusline = { 15 | { c.cur_mode }, 16 | { " ", c.branch, " " }, 17 | { " ", c.filename, "(#%n)" }, 18 | { " ", c.navic, " " }, 19 | { " ", c.win_info, " " }, 20 | { "%=" }, 21 | { c.lsp, " | ", c.formatters, " | ", c.treesitter }, 22 | { " ", "%6.(%l:%c%)", " " }, 23 | { " ", "%4.(%p%%%)", " " }, 24 | } 25 | 26 | ---Join statuscolumn|statusline sections to string 27 | ---@param sections table 28 | ---@return string 29 | function M.join_sections(sections) 30 | local res = "" 31 | for _, section in ipairs(sections) do 32 | for _, comp in ipairs(section) do 33 | res = type(comp) == "string" and res .. comp or res .. comp() 34 | end 35 | end 36 | return res 37 | end 38 | 39 | ---Build string for `statuscolumn` 40 | ---@return string 41 | function M.build_stc() 42 | return vim.v.virtnum ~= 0 and "" or M.join_sections(M.statuscolumn) 43 | end 44 | 45 | ---Return value for `statuscolumn` 46 | ---@return string 47 | function M.column() 48 | return '%{%v:lua.require("modules.status").build_stc()%}' 49 | end 50 | 51 | ---Build string for `statusline` 52 | ---@return string 53 | function M.build_stl() 54 | return M.join_sections(M.statusline) 55 | end 56 | 57 | ---Return value for `statusline` 58 | ---@return string 59 | function M.line() 60 | return '%{%v:lua.require("modules.status").build_stl()%}' 61 | end 62 | 63 | return M 64 | -------------------------------------------------------------------------------- /lua/modules/surround.lua: -------------------------------------------------------------------------------- 1 | local u = require("utils") 2 | 3 | local paired = { 4 | ['"'] = { '"', '"' }, 5 | ["'"] = { "'", "'" }, 6 | ["`"] = { "`", "`" }, 7 | ["["] = { "[", "]" }, 8 | ["{"] = { "{", "}" }, 9 | ["("] = { "(", ")" }, 10 | ["<"] = { "< ", " >" }, 11 | ["]"] = { "[ ", " ]" }, 12 | ["}"] = { "{ ", " }" }, 13 | [")"] = { "( ", " )" }, 14 | [">"] = { "< ", " >" }, 15 | ["*"] = { "*", "*" }, 16 | ["$"] = { "$", "$" }, 17 | } 18 | 19 | local function replace_non_blank(line, side, from, to) 20 | local pad_l, trim_line, pad_r = u.split_padline(line, side) 21 | 22 | if side == "left" and vim.startswith(trim_line, from) then 23 | trim_line = to .. trim_line:sub(#from + 1) 24 | end 25 | 26 | if side == "right" and vim.endswith(trim_line, from) then 27 | trim_line = trim_line:sub(1, -(#from + 1)) .. to 28 | end 29 | 30 | return vim.fn.join({ pad_l, trim_line, pad_r }, "") 31 | end 32 | 33 | local function get_char() 34 | local ok, char = pcall(vim.fn.getcharstr) 35 | local ok_lm, lm = pcall(require, "langmapper.utils") 36 | char = (ok and ok_lm) and lm.translate_keycode(char, "default", "ru") or char 37 | return ok and char or nil 38 | end 39 | 40 | local function change_surround(from, to) 41 | if paired[from] or from == "t" then 42 | vim.cmd.normal("va" .. from) 43 | local cursor = vim.api.nvim_win_get_cursor(0) 44 | local sr, sc, er, ec = u.to_api_range(u.get_visual_range()) 45 | local lines = vim.api.nvim_buf_get_text(0, sr, sc, er, ec, {}) 46 | local from_left, from_right, to_left, to_right 47 | 48 | if from == "t" then 49 | local function extract_tags(lines) 50 | local str = table.concat(lines, "\n") 51 | local tags = vim.iter(str:gmatch("<.->")) 52 | return tags:nth(1), tags:last() 53 | end 54 | 55 | from_left, from_right = extract_tags(lines) 56 | else 57 | from_left, from_right = unpack(paired[from]) 58 | end 59 | 60 | to_left = paired[to] and paired[to][1] or "" 61 | to_right = paired[to] and paired[to][2] or "" 62 | 63 | lines[1] = replace_non_blank(lines[1], "left", from_left, to_left) 64 | lines[#lines] = replace_non_blank(lines[#lines], "right", from_right, to_right) 65 | 66 | u.feedkeys("", "ni") 67 | vim.api.nvim_buf_set_text(0, sr, sc, er, ec, lines) 68 | vim.api.nvim_win_set_cursor(0, cursor) 69 | end 70 | end 71 | local Surround = {} 72 | Surround.replace_surround = change_surround 73 | Surround.remove_surround = change_surround 74 | Surround.add_surround = function(char, is_v) 75 | if paired[char] or char == "t" then 76 | local left, right 77 | if char == "t" then 78 | local tag = vim.fn.input("Tag: ") 79 | left, right = "<" .. tag .. ">", "" 80 | else 81 | left, right = unpack(paired[char]) 82 | end 83 | 84 | local cursor = vim.api.nvim_win_get_cursor(0) 85 | local sr, sc, er, ec = u.to_api_range(is_v and u.get_visual_range() or u.get_object_range()) 86 | local lines = vim.api.nvim_buf_get_text(0, sr, sc, er, ec, {}) 87 | 88 | lines[1] = left .. lines[1] 89 | lines[#lines] = lines[#lines] .. right 90 | 91 | vim.api.nvim_buf_set_text(0, sr, sc, er, ec, lines) 92 | vim.api.nvim_win_set_cursor(0, cursor) 93 | end 94 | end 95 | 96 | local function register_repeat(name, ...) 97 | local repeater = "__repeat_" .. name 98 | local args = { ... } 99 | _G[repeater] = function() 100 | Surround[name](unpack(args)) 101 | end 102 | vim.opt.operatorfunc = "v:lua." .. repeater 103 | end 104 | 105 | local function call_arg(arg) 106 | return type(arg) ~= "function" and arg or arg() 107 | end 108 | 109 | local function operatorfunc(name, feed, ...) 110 | local args = { ... } 111 | 112 | _G["__" .. name] = function() 113 | local final_args = vim.tbl_map(call_arg, args) 114 | Surround[name](unpack(final_args)) 115 | register_repeat(name, unpack(final_args)) 116 | end 117 | 118 | return function() 119 | vim.opt.operatorfunc = "v:lua.__" .. name 120 | u.feedkeys(feed, "ni") 121 | end 122 | end 123 | 124 | return { 125 | paired = paired, 126 | add = operatorfunc("add_surround", "g@", get_char), 127 | add_visual = function() 128 | Surround.add_surround(get_char(), true) 129 | u.feedkeys("", "ni") 130 | end, 131 | remove = operatorfunc("remove_surround", "g@ ", get_char, ""), 132 | replace = operatorfunc("replace_surround", "g@ ", get_char, get_char), 133 | surround = Surround, 134 | } 135 | -------------------------------------------------------------------------------- /lua/modules/thincc.lua: -------------------------------------------------------------------------------- 1 | -- Original idea and knowledge: 2 | -- https://github.com/lukas-reineke/virt-column.nvim 3 | -- https://github.com/xiyaowong/virtcolumn.nvim 4 | 5 | -- Lightly variant of setting thin colorcolumn with registry of buffers. 6 | -- If value of colorcolumn like a '+1,+2,+3', all values after first ',' will be ignored. 7 | 8 | local NS = vim.api.nvim_create_namespace("__parts.thincc__") 9 | local GR = vim.api.nvim_create_augroup("__parts.thincc__", { clear = true }) 10 | local disable_ft = { "alpha", "neo-tree", "toggleterm", "lazy", "lspinfo" } 11 | 12 | ---Registry for saving original value of colorcolumn of each buffer 13 | local registry = {} 14 | 15 | ---Using original color for ColorColumn 16 | local color = vim.api.nvim_get_hl(0, { name = "ColorColumn" }).bg 17 | vim.api.nvim_set_hl(0, "ThinCC", { fg = color, default = true }) 18 | vim.api.nvim_create_autocmd("ColorScheme", { 19 | desc = "Reload color for thincc if colorscheme is changed", 20 | group = GR, 21 | callback = function() 22 | color = vim.api.nvim_get_hl(0, { name = "ColorColumn" }).bg 23 | vim.api.nvim_set_hl(0, "ThinCC", { fg = color, default = true }) 24 | end, 25 | }) 26 | 27 | ---Calculating target col to set extmark 28 | ---@param win integer 29 | ---@param bufnr integer 30 | ---@return integer|nil 31 | local function calc_colorcolumn_place(win, bufnr) 32 | local tw = vim.bo[bufnr].textwidth 33 | local cc = vim.wo[win].colorcolumn 34 | 35 | if cc:match("^[+-]%d+") and tw ~= 0 then 36 | local shift = vim.tbl_map(vim.trim, vim.split(cc, ",", { plain = true }))[1] 37 | local col = tw + tonumber(shift) 38 | return col > 0 and col or nil 39 | end 40 | 41 | return tonumber(cc) 42 | end 43 | 44 | ---Get target col to set thin colorcolumn 45 | ---@param win integer Current win 46 | ---@param bufnr integer Current buffer 47 | ---@return integer|nil 48 | local function get_target_column(win, bufnr) 49 | if not registry[bufnr] then 50 | registry[bufnr] = { col = calc_colorcolumn_place(win, bufnr) } 51 | end 52 | return registry[bufnr].col 53 | end 54 | 55 | local function calc_inlayhint_len(mark) 56 | local len = 0 57 | 58 | for _, value in ipairs(mark or {}) do 59 | for _, text in ipairs(value[4].virt_text or {}) do 60 | len = len + #text[1] 61 | end 62 | end 63 | 64 | return len 65 | end 66 | 67 | ---Set or del extmark 68 | ---@param bufnr integer Current buffer 69 | ---@param line integer 70 | ---@param col integer 71 | local function update_exmark(bufnr, line, col) 72 | local line_text = vim.api.nvim_buf_get_lines(bufnr, line, line + 1, false)[1] 73 | if vim.fn.type(line_text) == vim.v.t_blob then 74 | return 75 | end 76 | 77 | local len = vim.fn.strdisplaywidth(line_text) 78 | 79 | -- Take into account the width of virtual text inlayHint during redrawing 80 | local ihns = vim.api.nvim_get_namespaces()["nvim.lsp.inlayhint"] 81 | if ihns then 82 | local mark = vim.api.nvim_buf_get_extmarks(bufnr, ihns, { line, 0 }, { line + 1, 0 }, { details = true }) 83 | len = len + calc_inlayhint_len(mark or {}) 84 | end 85 | 86 | if not (line_text and len >= col) then 87 | vim.api.nvim_buf_set_extmark(bufnr, NS, line, 0, { 88 | id = line + 1, 89 | virt_text = { { "▕", "ThinCC" } }, 90 | virt_text_pos = "overlay", 91 | virt_text_win_col = col - 1, 92 | hl_mode = "combine", 93 | priority = 0, 94 | }) 95 | else 96 | vim.api.nvim_buf_del_extmark(bufnr, NS, line + 1) 97 | end 98 | end 99 | 100 | ---Set thin colorcolumn to buffer 101 | local function set_thin_colorcolumn(win, bufnr, topline, botline) 102 | if vim.tbl_contains(disable_ft, vim.bo[bufnr].filetype) then 103 | return 104 | end 105 | 106 | if vim.api.nvim_buf_is_loaded(bufnr) then 107 | local col = get_target_column(win, bufnr) 108 | if col then 109 | vim.wo[win].colorcolumn = "" 110 | for line = topline, botline, 1 do 111 | update_exmark(bufnr, line, col) 112 | end 113 | end 114 | end 115 | end 116 | 117 | vim.api.nvim_set_decoration_provider(NS, { 118 | on_win = function(_, win, bufnr, topline, botline) 119 | set_thin_colorcolumn(win, bufnr, topline, botline) 120 | end, 121 | }) 122 | -------------------------------------------------------------------------------- /lua/modules/toggler.lua: -------------------------------------------------------------------------------- 1 | -- Original idea: https://github.com/nguyenvukhang/nvim-toggler 2 | 3 | -- Switch the word under cursor to the opposite value with saving case 4 | -- DEMO: true => true, True => False, tRuE => fAlSE 5 | -- (if the opposite word longer when current word, 6 | -- the tail of opposite will be the same case as the last char case of current) 7 | 8 | local u = require("utils") 9 | local M = {} 10 | 11 | ---Every key and value should be in lowercase 12 | local opposites = u.tbl_add_reverse_lookup({ 13 | ["top"] = "bottom", 14 | ["before"] = "after", 15 | ["start"] = "end", 16 | ["first"] = "last", 17 | ["next"] = "prev", 18 | ["vim"] = "emacs", 19 | ["true"] = "false", 20 | ["yes"] = "no", 21 | ["on"] = "off", 22 | ["left"] = "right", 23 | ["up"] = "down", 24 | ["split"] = "join", 25 | ["const"] = "let", 26 | ["open"] = "close", 27 | ["global"] = "local", 28 | ["increment"] = "decrement", 29 | ["production"] = "development", 30 | ["asc"] = "desc", 31 | ["право"] = "лево", 32 | ["вправо"] = "влево", 33 | ["cправа"] = "слева", 34 | ["правый"] = "левый", 35 | ["min"] = "max", 36 | ["div"] = "times", 37 | 38 | -- This will be work only with `vim.opt.iskeyword:append({ "!", "=", "<", ">" })` 39 | ["!="] = "==", 40 | ["!=="] = "===", 41 | ["<"] = ">", 42 | }) 43 | 44 | ---Convert string's chars to same case like base string 45 | ---If base string length less than target string, other chars will convert to case 46 | ---like last char in base string. 47 | ---@param base string Base string 48 | ---@param str string String to convert 49 | ---@return string 50 | local function to_same_register(base, str) 51 | local base_list = vim.split(base, "", { plain = true }) 52 | local target_list = vim.split(str, "", { plain = true }) 53 | 54 | for i, ch in ipairs(target_list) do 55 | local lower = u.is_lower(base_list[i] or base_list[#base_list]) 56 | target_list[i] = lower and string.lower(ch) or string.upper(ch) 57 | end 58 | 59 | return table.concat(target_list) 60 | end 61 | 62 | ---Toggle word () under cursor to opposite value. 63 | function M.toggle_word() 64 | -- To processed `==`, `!==` etc 65 | -- local ikw_orig = vim.opt.iskeyword:get() 66 | -- vim.opt.iskeyword:append({ "!", "=", "<", ">" }) 67 | 68 | -- Get text under cursor 69 | local text = vim.fn.expand("") 70 | 71 | -- Checking if the symbol under cursor is a part of received word 72 | -- (required to prevent wrong inserting, when cursor at punctuation and whitespace before the target word) 73 | local col = vim.api.nvim_win_get_cursor(0)[2] + 1 74 | local char = vim.api.nvim_get_current_line():sub(col, col) 75 | local contains = string.find(tostring(text), char, 1, true) and true or false 76 | 77 | if text and contains then 78 | local opp = opposites[string.lower(tostring(text))] 79 | 80 | if opp then 81 | vim.cmd('normal! "_ciw' .. to_same_register(tostring(text), opp)) 82 | end 83 | end 84 | 85 | -- Restore original value of `iskeyword` 86 | -- vim.opt.iskeyword = ikw_orig 87 | end 88 | 89 | return M 90 | -------------------------------------------------------------------------------- /lua/options.lua: -------------------------------------------------------------------------------- 1 | local textwidth = PREF.common.textwidth 2 | local tabwidth = PREF.common.tabwidth 3 | 4 | local function escape(str) 5 | local escape_chars = [[;,."|\]] 6 | return vim.fn.escape(str, escape_chars) 7 | end 8 | 9 | local en = [[`qwertyuiop[]asdfghjkl;'zxcvbnm]] 10 | local ru = [[ёйцукенгшщзхъфывапролджэячсмить]] 11 | local en_shift = [[~QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>]] 12 | local ru_shift = [[ËЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ]] 13 | local langmap = vim.fn.join({ 14 | escape(ru_shift) .. ";" .. escape(en_shift), 15 | escape(ru) .. ";" .. escape(en), 16 | }, ",") 17 | 18 | local options = { 19 | -- ========================================================================== 20 | -- Indents, spaces, tabulation 21 | -- ========================================================================== 22 | expandtab = true, 23 | cindent = true, 24 | smarttab = true, 25 | shiftwidth = tabwidth, 26 | tabstop = tabwidth, 27 | 28 | -- ========================================================================== 29 | -- UI 30 | -- ========================================================================== 31 | number = true, 32 | relativenumber = true, 33 | termguicolors = true, 34 | numberwidth = 3, 35 | showmode = false, 36 | showcmd = false, 37 | cmdheight = 1, 38 | pumheight = 10, 39 | showtabline = 0, 40 | cursorline = true, 41 | signcolumn = "yes", 42 | scrolloff = 3, 43 | sidescrolloff = 3, 44 | colorcolumn = tostring(textwidth), 45 | laststatus = 3, 46 | fillchars = { 47 | eob = " ", 48 | fold = " ", 49 | foldopen = "", 50 | foldclose = "", 51 | foldsep = " ", -- or "│" to use bar for show fold area 52 | }, 53 | title = false, 54 | statuscolumn = require("modules.status").column(), 55 | statusline = require("modules.status").line(), 56 | 57 | -- ========================================================================== 58 | -- Text 59 | -- ========================================================================== 60 | textwidth = PREF.common.textwidth, 61 | wrap = false, 62 | linebreak = true, 63 | 64 | -- ========================================================================== 65 | -- Search 66 | -- ========================================================================== 67 | ignorecase = true, 68 | smartcase = true, 69 | hlsearch = true, 70 | infercase = true, 71 | 72 | -- ========================================================================== 73 | -- Folding 74 | -- ========================================================================== 75 | foldcolumn = "1", 76 | foldlevel = 99, 77 | foldlevelstart = 99, 78 | foldenable = true, 79 | foldmethod = "expr", 80 | foldtext = require("modules.foldtext"), 81 | 82 | -- ========================================================================== 83 | -- Other 84 | -- ========================================================================== 85 | updatetime = 1000, 86 | undofile = true, 87 | splitright = true, 88 | splitbelow = true, 89 | mouse = "a", 90 | clipboard = "unnamedplus", 91 | backup = false, 92 | swapfile = false, 93 | completeopt = { "menuone", "noselect" }, 94 | winbar = " ", 95 | spell = false, 96 | spelllang = "en_us,ru_ru", 97 | whichwrap = vim.opt.whichwrap:append("<,>,[,],h,l"), 98 | shortmess = vim.opt.shortmess:append("c"), 99 | iskeyword = vim.opt.iskeyword:append("-"), 100 | langmap = langmap, 101 | smoothscroll = true, 102 | splitkeep = "screen", 103 | } 104 | 105 | for option_name, value in pairs(options) do 106 | -- To avoid errors on toggle nvim version 107 | local ok, _ = pcall(vim.api.nvim_get_option_info2, option_name, {}) 108 | if ok then 109 | vim.opt[option_name] = value 110 | else 111 | vim.notify("Option " .. option_name .. " is not supported", vim.log.levels.WARN) 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /lua/plugins.lua: -------------------------------------------------------------------------------- 1 | local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" 2 | local configs = "config.plugins" 3 | 4 | if not vim.loop.fs_stat(lazypath) then 5 | vim.fn.system({ 6 | "git", 7 | "clone", 8 | "--filter=blob:none", 9 | "https://github.com/folke/lazy.nvim.git", 10 | "--branch=stable", -- latest stable release 11 | lazypath, 12 | }) 13 | end 14 | 15 | vim.opt.runtimepath:prepend(lazypath) 16 | 17 | require("lazy").setup(configs, { 18 | defaults = { 19 | lazy = true, 20 | }, 21 | install = { 22 | colorscheme = { PREF.ui.colorscheme, "default", "habamax" }, 23 | }, 24 | change_detection = { notify = false }, 25 | ui = { border = "none" }, 26 | dev = { 27 | -- directory where you store your local plugin projects 28 | path = "~/projects/code/personal", 29 | ---@type string[] plugins that match these patterns will use your local versions instead of being fetched from GitHub 30 | patterns = {}, -- For example {"folke"} 31 | fallback = false, -- Fallback to git when local plugin doesn't exist 32 | }, 33 | performance = { 34 | rtp = { 35 | disabled_plugins = { 36 | "gzip", 37 | "tarPlugin", 38 | "tohtml", 39 | "tutor", 40 | "zipPlugin", 41 | }, 42 | }, 43 | }, 44 | }) 45 | -------------------------------------------------------------------------------- /lua/user_settings.lua: -------------------------------------------------------------------------------- 1 | local filter_clients = function(tbl) 2 | for k, v in pairs(tbl) do 3 | if not v then 4 | tbl[k] = nil 5 | end 6 | end 7 | return tbl 8 | end 9 | 10 | PREF = { 11 | common = { 12 | textwidth = 100, 13 | tabwidth = 2, 14 | }, 15 | 16 | lsp = { 17 | format_on_save = false, 18 | virtual_text = false, 19 | show_diagnostic = true, 20 | show_inlay_hints = true, 21 | -- Use take_over_mode for Vue projects or not 22 | tom_enable = false, 23 | -- List of servers to run 24 | -- Also applies to `ensure_installed` in `mason-lspconfig` 25 | active_servers = filter_clients({ 26 | vimls = false, 27 | csharp_ls = false, 28 | prismals = true, 29 | eslint = true, 30 | lua_ls = true, 31 | -- tsserver = false, 32 | ts_ls = false, -- looks like tsserver has been renamed 33 | vtsls = true, 34 | volar = false, 35 | jsonls = true, 36 | cssls = true, 37 | tailwindcss = true, 38 | html = true, 39 | emmet_ls = true, 40 | bashls = true, 41 | dockerls = true, 42 | docker_compose_language_service = true, 43 | ltex = false, 44 | marksman = true, 45 | rust_analyzer = false, 46 | sqlls = false, 47 | sqls = true, 48 | clangd = false, 49 | gopls = true, 50 | ansiblels = false, 51 | basedpyright = true, 52 | pyright = false, 53 | ruff = true, 54 | typos_lsp = true, 55 | svelte = true, 56 | }), 57 | }, 58 | 59 | ui = { 60 | ---(!) List of colorschemes lua/config/colorscheme/init.lua 61 | colorscheme = "serenity", -- If `.colorscheme` file exists, read name of colorscheme from it, otherwise use `PREF.ui.colorscheme 62 | border = { " ", " ", " ", " ", " ", " ", " ", " " }, 63 | italic_comment = true, 64 | }, 65 | 66 | git = { 67 | show_blame = false, 68 | show_signcolumn = true, 69 | }, 70 | } 71 | -------------------------------------------------------------------------------- /lua/usercmd.lua: -------------------------------------------------------------------------------- 1 | local function wp_scratch_buf(start, scratch, lhs) 2 | for _, buf in ipairs({ scratch, start }) do 3 | vim.keymap.set("n", lhs, function() 4 | vim.api.nvim_buf_delete(scratch, { force = true }) 5 | vim.keymap.del("n", lhs, { buffer = start }) 6 | end, { buffer = buf }) 7 | end 8 | end 9 | 10 | vim.api.nvim_create_user_command("DiffOrig", function() 11 | -- Get start buffer 12 | local start = vim.api.nvim_get_current_buf() 13 | 14 | -- `vnew` - Create empty vertical split window 15 | -- `set buftype=nofile` - Buffer is not related to a file, will not be written 16 | -- `0d_` - Remove an extra empty start row 17 | -- `diffthis` - Set diff mode to a new vertical split 18 | vim.cmd("vnew | set buftype=nofile | read ++edit # | 0d_ | diffthis") 19 | 20 | -- Get scratch buffer 21 | local scratch = vim.api.nvim_get_current_buf() 22 | 23 | -- `wincmd p` - Go to the start window 24 | -- `diffthis` - Set diff mode to a start window 25 | vim.cmd("wincmd p | diffthis") 26 | 27 | -- Map `q` for both buffers to exit diff view and delete scratch buffer 28 | wp_scratch_buf(start, scratch, "q") 29 | end, {}) 30 | 31 | vim.api.nvim_create_user_command("Gr", function(args) 32 | local start = vim.api.nvim_get_current_buf() 33 | local ft = vim.api.nvim_get_option_value("filetype", { buf = start }) 34 | 35 | vim.cmd( 36 | "vnew | set buftype=nofile | read ++edit # | set filetype=" 37 | .. ft 38 | .. " | 0d_ | g!/" 39 | .. args.args 40 | .. "/d | silent norm gg=G" 41 | ) 42 | 43 | local scratch = vim.api.nvim_get_current_buf() 44 | wp_scratch_buf(start, scratch, "q") 45 | end, { nargs = 1 }) 46 | -------------------------------------------------------------------------------- /snippets/javascript/typescript.json: -------------------------------------------------------------------------------- 1 | { 2 | "tsxArrowNamedExportWithProps": { 3 | "prefix": "tfp", 4 | "body": [ 5 | "import React from 'react'", 6 | "", 7 | "interface ${1:${TM_FILENAME_BASE}}Props {}", 8 | "", 9 | "export const ${1:${TM_FILENAME_BASE}} = (props: ${1:${TM_FILENAME_BASE}}Props) => {", 10 | " return (", 11 | "
${1:first}
", 12 | " )", 13 | "}" 14 | ], 15 | "description": "Creates a React Arrow Function Component with Props" 16 | }, 17 | "reactFunctionalComponent": { 18 | "prefix": "rfc", 19 | "body": [ 20 | "interface ${1:${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}}Props {}", 21 | "", 22 | "const ${1:${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}} = ({}: ${1:${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}}Props) => {", 23 | " return (", 24 | "
", 25 | " $0", 26 | "
", 27 | " );", 28 | "};", 29 | "", 30 | "export default ${1:${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}};" 31 | ], 32 | "description": "Create a React functional component" 33 | }, 34 | "tsNextApiRoutePost": { 35 | "prefix": "rpo", 36 | "body": [ 37 | "export const POST = async (request: Request) => {", 38 | " return Response.json({ ok: true });", 39 | "}" 40 | ], 41 | "description": "Creates a Next Route Handlers for POST method" 42 | }, 43 | "tsNextApiRoutePut": { 44 | "prefix": "rpu", 45 | "body": [ 46 | "export const PUT = async (request: Request) => {", 47 | " return Response.json({ ok: true });", 48 | "}" 49 | ], 50 | "description": "Creates a Next Route Handlers for PUT method" 51 | }, 52 | "tsNextApiRouteGet": { 53 | "prefix": "rpg", 54 | "body": [ 55 | "export const GET = async (request: Request) => {", 56 | " return Response.json({ ok: true });", 57 | "}" 58 | ], 59 | "description": "Creates a Next Route Handlers for GET method" 60 | }, 61 | "tsNextApiRouteDelete": { 62 | "prefix": "rpd", 63 | "body": [ 64 | "export const DELETE = async (request: Request) => {", 65 | " return Response.json({ ok: true });", 66 | "}" 67 | ], 68 | "description": "Creates a Next Route Handlers for DELETE method" 69 | }, 70 | "tsNextPage": { 71 | "prefix": "page", 72 | "body": [ 73 | "export default function ${TM_DIRECTORY/(.*\\/)?([^\\/]+)/${2:/capitalize}/}Page() {", 74 | " ${1}return (", 75 | "
${TM_DIRECTORY/(.*\\/)?([^\\/]+)/${2:/capitalize}/} Page
", 76 | " );", 77 | "}" 78 | ], 79 | "description": "Creates a Next Page templete component" 80 | }, 81 | "useState": { 82 | "prefix": "state", 83 | "body": [ 84 | "const [${1:first}, set${1/(.*)/${1:/capitalize}/}] = useState(${2})" 85 | ] 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /snippets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "custom-snippets", 3 | "contributes": { 4 | "snippets": [ 5 | { 6 | "language": [ 7 | "typescript", 8 | "typescriptreact" 9 | ], 10 | "path": "./javascript/typescript.json" 11 | } 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /stylua.toml: -------------------------------------------------------------------------------- 1 | # https://github.com/JohnnyMorganz/StyLua 2 | column_width = 120 3 | line_endings = "Unix" 4 | indent_type = "Spaces" 5 | indent_width = 2 6 | quote_style = "AutoPreferDouble" 7 | call_parentheses = "Always" 8 | collapse_simple_statement = "Never" 9 | --------------------------------------------------------------------------------