├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .stylua.toml ├── .styluaignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── after ├── ftplugin │ ├── c.vim │ ├── cpp.vim │ ├── dockerfile.vim │ ├── go.vim │ ├── json.vim │ ├── lua.vim │ ├── proto.vim │ ├── python.vim │ └── rust.vim └── queries │ ├── c │ └── highlights.scm │ ├── cpp │ └── highlights.scm │ └── lua │ └── highlights.scm ├── colors └── solarized.lua ├── init.lua ├── lsp ├── asm.lua ├── basedpyright.lua ├── clangd.lua ├── cmake.lua ├── luals.lua ├── ruff.lua ├── rust_analyzer.lua ├── tsls.lua └── zls.lua ├── lua └── private │ ├── dashboard.lua │ ├── grep.lua │ ├── jump.lua │ ├── keymap.lua │ └── pairs.lua ├── plugin ├── async.lua ├── completion.lua ├── events.lua └── package.lua ├── snippets ├── go.json ├── javascriptreact.json ├── rust.json ├── typescriptreact.json └── zig.json └── template ├── main_owner.c ├── main_owner.cpp ├── main_owner.go ├── main_owner.rs ├── nvim_temp.lua └── package_owner.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: glepnir 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | lint: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - name: Stylua 20 | uses: JohnnyMorganz/stylua-action@v1.1.2 21 | with: 22 | token: ${{ secrets.GITHUB_TOKEN }} 23 | args: --check . 24 | -------------------------------------------------------------------------------- /.stylua.toml: -------------------------------------------------------------------------------- 1 | column_width = 100 2 | line_endings = "Unix" 3 | indent_type = "Spaces" 4 | indent_width = 2 5 | quote_style = "AutoPreferSingle" 6 | call_parentheses = "Always" 7 | -------------------------------------------------------------------------------- /.styluaignore: -------------------------------------------------------------------------------- 1 | /template 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | MAINTAINER RaphaelHuan 3 | 4 | RUN apk add --virtual build-deps --update \ 5 | autoconf \ 6 | automake \ 7 | cmake \ 8 | ncurses ncurses-dev ncurses-libs ncurses-terminfo \ 9 | gcc \ 10 | g++ \ 11 | libtool \ 12 | libuv \ 13 | linux-headers \ 14 | lua5.3-dev \ 15 | m4 \ 16 | unzip \ 17 | make 18 | 19 | 20 | RUN apk add --update \ 21 | curl \ 22 | git \ 23 | python \ 24 | py-pip \ 25 | python-dev \ 26 | python3-dev \ 27 | python3 &&\ 28 | python3 -m ensurepip && \ 29 | rm -r /usr/lib/python*/ensurepip && \ 30 | pip3 install --upgrade pip setuptools && \ 31 | rm -r /root/.cache 32 | 33 | ENV CMAKE_EXTRA_FLAGS=-DENABLE_JEMALLOC=OFF 34 | WORKDIR /tmp 35 | 36 | RUN git clone https://github.com/neovim/libtermkey.git && \ 37 | cd libtermkey && \ 38 | make && \ 39 | make install && \ 40 | cd ../ && rm -rf libtermkey 41 | 42 | RUN git clone https://github.com/neovim/libvterm.git && \ 43 | cd libvterm && \ 44 | make && \ 45 | make install && \ 46 | cd ../ && rm -rf libvterm 47 | 48 | RUN git clone https://github.com/neovim/unibilium.git && \ 49 | cd unibilium && \ 50 | make && \ 51 | make install && \ 52 | cd ../ && rm -rf unibilium 53 | 54 | RUN curl -L https://github.com/neovim/neovim/archive/nightly.tar.gz | tar xz && \ 55 | cd neovim-nightly && \ 56 | make && \ 57 | make install && \ 58 | cd ../ && rm -rf neovim-nightly 59 | 60 | # # Install neovim python support 61 | RUN pip3 install neovim 62 | RUN pip2 install neovim 63 | 64 | RUN apk del build-deps &&\ 65 | rm -rf /var/cache/apk/* 66 | 67 | # # install all plugins 68 | RUN make install 69 | 70 | WORKDIR /root/.config/nvim 71 | 72 | COPY $HOME/.config/nvim /root/.config/nvim 73 | 74 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Raphael 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | rm -rf $(HOME)/.local/share/nvim/site/pack/strive 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Word 2 | 3 | **Text Editor just text editor Please dont't do no more** 4 | 5 | ![Image](https://github.com/user-attachments/assets/148e04c6-46ca-4289-9349-2b72b45534b0) 6 | -------------------------------------------------------------------------------- /after/ftplugin/c.vim: -------------------------------------------------------------------------------- 1 | if expand('%') !~ 'nvim' 2 | setl expandtab 3 | setl shiftwidth=4 4 | setl softtabstop=4 5 | setl tabstop=4 6 | endif 7 | 8 | inoreabbrev #i #include 9 | -------------------------------------------------------------------------------- /after/ftplugin/cpp.vim: -------------------------------------------------------------------------------- 1 | setl nocindent 2 | setl expandtab 3 | setl sw=4 4 | setl sts=4 5 | setl tabstop=4 6 | setl cinkeys-=: 7 | -------------------------------------------------------------------------------- /after/ftplugin/dockerfile.vim: -------------------------------------------------------------------------------- 1 | setl nocindent 2 | setl expandtab 3 | setl shiftwidth=2 4 | setl softtabstop=2 5 | setl tabstop=2 6 | -------------------------------------------------------------------------------- /after/ftplugin/go.vim: -------------------------------------------------------------------------------- 1 | setl commentstring=//%s 2 | setl noexpandtab 3 | setl shiftwidth=4 4 | setl softtabstop=4 5 | setl tabstop=4 6 | -------------------------------------------------------------------------------- /after/ftplugin/json.vim: -------------------------------------------------------------------------------- 1 | setl autoindent 2 | setl conceallevel=0 3 | setl expandtab 4 | setl foldmethod=syntax 5 | setl formatoptions=tcq2l 6 | setl shiftwidth=4 7 | setl softtabstop=4 8 | setl tabstop=8 9 | -------------------------------------------------------------------------------- /after/ftplugin/lua.vim: -------------------------------------------------------------------------------- 1 | " From https://github.com/tpope/tpope/blob/master/.vimrc 2 | setlocal includeexpr=substitute(v:fname,'\\.','/','g').'.lua' 3 | setlocal comments-=:-- comments+=:---,:-- 4 | 5 | inoreabbrev lo local 6 | inoreabbrev lf local function() 7 | inoreabbrev fu function() end 8 | inoreabbrev fo (''):format() 9 | -------------------------------------------------------------------------------- /after/ftplugin/proto.vim: -------------------------------------------------------------------------------- 1 | setl cindent 2 | setl expandtab 3 | setl sw=2 4 | -------------------------------------------------------------------------------- /after/ftplugin/python.vim: -------------------------------------------------------------------------------- 1 | setl expandtab 2 | setl autoindent 3 | setl smartindent 4 | setl smarttab 5 | setl sw=4 6 | setl softtabstop=4 7 | setl tabstop=4 8 | -------------------------------------------------------------------------------- /after/ftplugin/rust.vim: -------------------------------------------------------------------------------- 1 | setl nocindent 2 | setl expandtab 3 | setl commentstring=//%s 4 | setl shiftwidth=4 5 | setl softtabstop=4 6 | setl smartindent 7 | setl tabstop=4 8 | -------------------------------------------------------------------------------- /after/queries/c/highlights.scm: -------------------------------------------------------------------------------- 1 | ; extends 2 | 3 | ((identifier) @constant 4 | (#lua-match? @constant "^k[A-Z]")) 5 | 6 | ((identifier) @constant 7 | (#match? @constant "^FOR_ALL.*")) 8 | -------------------------------------------------------------------------------- /after/queries/cpp/highlights.scm: -------------------------------------------------------------------------------- 1 | ; extends 2 | 3 | ((call_expression 4 | function: (identifier) @function) 5 | (#lua-match? @function "^%u")) 6 | -------------------------------------------------------------------------------- /after/queries/lua/highlights.scm: -------------------------------------------------------------------------------- 1 | ; extends 2 | 3 | (table_constructor 4 | [ 5 | "{" 6 | "}" 7 | ] @punctuation.bracket) 8 | 9 | -------------------------------------------------------------------------------- /colors/solarized.lua: -------------------------------------------------------------------------------- 1 | -- orange #cb4b16 2 | -- violet #6c71c4 3 | local colors = { 4 | base04 = '#00202b', 5 | base03 = '#002838', 6 | -- base03 = '#002937', 7 | base02 = '#073642', 8 | base01 = '#586e75', 9 | base00 = '#657b83', 10 | base0 = '#839496', 11 | base1 = '#93a1a1', 12 | base2 = '#eee8d5', 13 | base3 = '#fdf6e3', 14 | yellow = '#b58900', 15 | orange = '#b86114', 16 | red = '#d75f5f', 17 | violet = '#887ec8', 18 | blue = '#268bd2', 19 | cyan = '#2aa198', 20 | green = '#84a800', 21 | magenta = '#d33682', 22 | -- Custom modifications 23 | fg = '#b6b6b6', -- Brighter foreground 24 | } 25 | 26 | vim.g.colors_name = 'solarized' 27 | 28 | local function shl(group, properties) 29 | vim.api.nvim_set_hl(0, group, properties) 30 | end 31 | 32 | local function load_solarized() 33 | -- General editor highlights 34 | shl('Normal', { fg = colors.fg, bg = colors.base03 }) 35 | shl('EndOfBuffer', { fg = colors.base03 }) 36 | shl('CursorLine', { bg = colors.base02 }) 37 | shl('CursorLineNr', { fg = colors.base1, bg = colors.base02 }) 38 | shl('LineNr', { fg = colors.base01 }) 39 | shl('Comment', { fg = colors.base01, italic = true }) 40 | shl('String', { fg = colors.cyan }) 41 | shl('Function', { fg = colors.blue }) 42 | shl('Keyword', { fg = colors.green, bold = true }) 43 | shl('Constant', { fg = colors.violet }) 44 | shl('Identifier', { fg = colors.blue }) 45 | shl('Statement', { fg = colors.green }) 46 | shl('Number', { link = 'Constant' }) 47 | shl('PreProc', { fg = colors.orange }) 48 | shl('Type', { fg = colors.yellow }) 49 | shl('Special', { fg = colors.orange }) 50 | shl('Operator', { fg = colors.base0 }) 51 | shl('Underlined', { fg = colors.violet, underline = true }) 52 | shl('Todo', { fg = colors.magenta, bold = true }) 53 | shl('Error', { fg = colors.red, bg = colors.base03, bold = true }) 54 | shl('WarningMsg', { fg = colors.orange }) 55 | shl('IncSearch', { fg = colors.base03, bg = colors.orange }) 56 | shl('Search', { fg = colors.base03, bg = colors.yellow }) 57 | shl('Visual', { fg = colors.base01, bg = colors.base03, reverse = true }) 58 | shl('Pmenu', { fg = colors.base0, bg = colors.base04 }) 59 | shl('PmenuMatch', { fg = colors.cyan, bg = colors.base04, bold = true }) 60 | shl('PmenuMatchSel', { fg = colors.cyan, bg = colors.base00, bold = true }) 61 | shl('PmenuSel', { fg = colors.base3, bg = colors.base00 }) 62 | shl('PmenuSbar', { bg = colors.base1 }) 63 | shl('PmenuThumb', { bg = colors.base01 }) 64 | shl('MatchParen', { bg = colors.base02 }) 65 | shl('WinBar', { bg = colors.base02 }) 66 | shl('NormalFloat', { bg = colors.base04 }) 67 | shl('FloatBorder', { fg = colors.blue }) 68 | shl('Title', { fg = colors.yellow }) 69 | shl('WinSeparator', { fg = colors.base00 }) 70 | shl('StatusLine', { bg = colors.base1, fg = colors.base02 }) 71 | shl('StatusLineNC', { bg = colors.base00, fg = colors.base02 }) 72 | shl('ModeMsg', { fg = colors.cyan }) 73 | shl('ColorColumn', { bg = colors.base02 }) 74 | shl('Title', { fg = colors.orange }) 75 | shl('WildMenu', { fg = colors.base2, bg = colors.base02, reverse = true }) 76 | shl('Folded', { bg = colors.base04, fg = colors.base0 }) 77 | shl('ErrorMsg', { fg = colors.red }) 78 | shl('ComplMatchIns', { fg = colors.base01 }) 79 | shl('Directory', { fg = colors.cyan }) 80 | shl('QuickFixLine', { bold = true }) 81 | shl('qfFileName', { fg = colors.blue }) 82 | shl('qfSeparator', { fg = colors.base01 }) 83 | shl('qfLineNr', { link = 'LineNr' }) 84 | shl('qfText', { link = 'Normal' }) 85 | 86 | -- Treesitter highlights 87 | shl('@function', { fg = colors.blue }) 88 | shl('@function.builtin', { fg = colors.blue }) 89 | shl('@variable', { fg = colors.fg }) 90 | shl('@variable.builtin', { fg = colors.fg }) 91 | shl('@keyword', { fg = colors.green }) 92 | shl('@keyword.import', { link = 'PreProc' }) 93 | shl('@string', { fg = colors.cyan }) 94 | shl('@string.escape', { fg = colors.cyan }) 95 | shl('@string.regexp', { fg = colors.cyan }) 96 | shl('@comment', { fg = colors.base01, italic = true }) 97 | shl('@type', { fg = colors.yellow }) 98 | shl('@type.builtin', { link = '@type' }) 99 | shl('@constant', { link = 'Constant' }) 100 | shl('@constant.builtin', { link = 'Constant' }) 101 | shl('@constant.macro', { link = 'Constant' }) 102 | shl('@constructor', { link = 'Function' }) 103 | shl('@parameter', { fg = colors.base0 }) 104 | shl('@class', { fg = colors.yellow }) 105 | shl('@method', { fg = colors.blue }) 106 | shl('@property', { link = '@variable' }) 107 | -- shl('@field', { fg = colors.base0 }) 108 | shl('@interface', { fg = colors.yellow }) 109 | shl('@namespace', { fg = colors.base0 }) 110 | shl('@punctuation', { fg = colors.base0 }) 111 | shl('@operator', { link = 'Operator' }) 112 | shl('@attribute', { fg = colors.yellow }) 113 | shl('@boolean', { link = 'Constant' }) 114 | shl('@number', { link = 'Number' }) 115 | shl('@tag', { fg = colors.green }) 116 | shl('@tag.attribute', { fg = colors.base0 }) 117 | shl('@tag.delimiter', { fg = colors.base0 }) 118 | 119 | -- Diagnostics 120 | shl('DiagnosticError', { fg = colors.red }) 121 | shl('DiagnosticWarn', { fg = colors.yellow }) 122 | shl('DiagnosticInfo', { fg = colors.blue }) 123 | shl('DiagnosticHint', { fg = colors.cyan }) 124 | shl('DiagnosticUnderlineError', { undercurl = true, sp = colors.red }) 125 | shl('DiagnosticUnderlineWarn', { undercurl = true, sp = colors.yellow }) 126 | shl('DiagnosticUnderlineInfo', { undercurl = true, sp = colors.blue }) 127 | shl('DiagnosticUnderlineHint', { undercurl = true, sp = colors.cyan }) 128 | 129 | -- LSP 130 | shl('LspReferenceText', { bg = colors.base02 }) 131 | shl('LspReferenceRead', { bg = colors.base02 }) 132 | shl('LspReferenceWrite', { bg = colors.base02 }) 133 | 134 | -- Indentmini 135 | shl('IndentLine', { link = 'Comment' }) 136 | shl('IndentLineCurrent', { fg = '#084352' }) 137 | 138 | -- GitSigns 139 | shl('GitSignsAdd', { fg = colors.green, bg = colors.base03 }) 140 | shl('GitSignsChange', { fg = colors.yellow, bg = colors.base03 }) 141 | shl('GitSignsDelete', { fg = colors.red, bg = colors.base03 }) 142 | shl('DashboardHeader', { fg = colors.green }) 143 | shl('ModeLineMode', { bold = true }) 144 | shl('ModeLinefileinfo', { bold = true }) 145 | end 146 | 147 | load_solarized() 148 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | local g = vim.g 2 | vim.loader.enable() 3 | g.mapleader = vim.keycode('') 4 | vim.g.language = { 5 | 'c', 6 | 'cpp', 7 | 'rust', 8 | 'zig', 9 | 'lua', 10 | 'go', 11 | 'python', 12 | 'proto', 13 | 'typescript', 14 | 'javascript', 15 | 'tsx', 16 | 'css', 17 | 'scss', 18 | 'diff', 19 | 'dockerfile', 20 | 'gomod', 21 | 'gosum', 22 | 'gowork', 23 | 'graphql', 24 | 'html', 25 | 'sql', 26 | 'markdown', 27 | 'markdown_inline', 28 | 'json', 29 | 'jsonc', 30 | 'vimdoc', 31 | 'vim', 32 | 'cmake', 33 | } 34 | 35 | g.loaded_gzip = 1 36 | g.loaded_tar = 1 37 | g.loaded_tarPlugin = 1 38 | g.loaded_zip = 1 39 | g.loaded_zipPlugin = 1 40 | g.loaded_getscript = 1 41 | g.loaded_getscriptPlugin = 1 42 | g.loaded_vimball = 1 43 | g.loaded_vimballPlugin = 1 44 | g.loaded_matchit = 1 45 | g.loaded_2html_plugin = 1 46 | g.loaded_rrhelper = 1 47 | g.loaded_netrwPlugin = 1 48 | g.loaded_matchparen = 1 49 | 50 | local o = vim.o 51 | o.hidden = true 52 | o.magic = true 53 | o.virtualedit = 'block' 54 | o.clipboard = 'unnamedplus' 55 | o.wildignorecase = true 56 | o.swapfile = false 57 | 58 | o.timeout = true 59 | o.ttimeout = true 60 | o.timeoutlen = 500 61 | o.ttimeoutlen = 10 62 | o.updatetime = 100 63 | o.ignorecase = true 64 | o.smartcase = true 65 | o.cursorline = true 66 | 67 | o.showmode = false 68 | o.shortmess = 'aoOTIcF' 69 | o.scrolloff = 2 70 | o.sidescrolloff = 5 71 | o.ruler = false 72 | o.showtabline = 0 73 | o.showcmd = false 74 | 75 | o.pumheight = 15 76 | o.pummaxwidth = 30 77 | 78 | o.list = true 79 | --eol:¬ 80 | o.listchars = 'tab:» ,nbsp:+,trail:·,extends:→,precedes:←,' 81 | o.fillchars = 'trunc:…' 82 | o.foldtext = '' 83 | o.foldlevelstart = 99 84 | 85 | -- o.undofile = true 86 | o.linebreak = true 87 | o.smoothscroll = true 88 | 89 | o.smarttab = true 90 | o.expandtab = true 91 | o.autoindent = true 92 | o.tabstop = 2 93 | o.sw = 2 94 | 95 | o.wrap = false 96 | o.number = true 97 | o.signcolumn = 'yes' 98 | 99 | o.textwidth = 80 100 | o.colorcolumn = '+0' 101 | o.winborder = 'rounded' 102 | 103 | o.cot = 'menu,menuone,noinsert,fuzzy,popup' 104 | o.cia = 'kind,abbr,menu' 105 | 106 | vim.cmd.colorscheme('solarized') 107 | vim.g.health = { style = 'float' } 108 | -------------------------------------------------------------------------------- /lsp/asm.lua: -------------------------------------------------------------------------------- 1 | ---@brief 2 | --- 3 | --- https://github.com/bergercookie/asm-lsp 4 | --- 5 | --- Language Server for NASM/GAS/GO Assembly 6 | --- 7 | --- `asm-lsp` can be installed via cargo: 8 | --- cargo install asm-lsp 9 | return { 10 | cmd = { 'asm-lsp' }, 11 | filetypes = { 'asm', 'vmasm' }, 12 | root_markers = { '.asm-lsp.toml', '.git' }, 13 | } 14 | -------------------------------------------------------------------------------- /lsp/basedpyright.lua: -------------------------------------------------------------------------------- 1 | local function set_python_path(path) 2 | local clients = vim.lsp.get_clients({ 3 | bufnr = vim.api.nvim_get_current_buf(), 4 | name = 'basedpyright', 5 | }) 6 | for _, client in ipairs(clients) do 7 | if client.settings then 8 | client.settings.python = 9 | vim.tbl_deep_extend('force', client.settings.python or {}, { pythonPath = path }) 10 | else 11 | client.config.settings = 12 | vim.tbl_deep_extend('force', client.config.settings, { python = { pythonPath = path } }) 13 | end 14 | client.notify('workspace/didChangeConfiguration', { settings = nil }) 15 | end 16 | end 17 | 18 | return { 19 | cmd = { 'basedpyright-langserver', '--stdio' }, 20 | filetypes = { 'python' }, 21 | root_markers = { 22 | 'pyproject.toml', 23 | 'setup.py', 24 | 'setup.cfg', 25 | 'requirements.txt', 26 | 'Pipfile', 27 | 'pyrightconfig.json', 28 | '.git', 29 | }, 30 | settings = { 31 | basedpyright = { 32 | analysis = { 33 | autoSearchPaths = true, 34 | useLibraryCodeForTypes = true, 35 | diagnosticMode = 'openFilesOnly', 36 | }, 37 | }, 38 | }, 39 | on_attach = function(client, bufnr) 40 | vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightOrganizeImports', function() 41 | client:exec_cmd({ 42 | command = 'basedpyright.organizeimports', 43 | arguments = { vim.uri_from_bufnr(bufnr) }, 44 | }) 45 | end, { 46 | desc = 'Organize Imports', 47 | }) 48 | 49 | vim.api.nvim_buf_create_user_command(0, 'LspPyrightSetPythonPath', set_python_path, { 50 | desc = 'Reconfigure basedpyright with the provided python path', 51 | nargs = 1, 52 | complete = 'file', 53 | }) 54 | end, 55 | } 56 | -------------------------------------------------------------------------------- /lsp/clangd.lua: -------------------------------------------------------------------------------- 1 | --- Implements the off-spec textDocument/switchSourceHeader method. 2 | --- @param buf integer 3 | local function switch_source_header(client, buf) 4 | client:request( 5 | 'textDocument/switchSourceHeader', 6 | vim.lsp.util.make_text_document_params(buf), 7 | function(err, result) 8 | if err then 9 | vim.notify(err.message, vim.log.levels.ERROR) 10 | return 11 | end 12 | if not result then 13 | vim.notify('Corresponding file could not be determined', vim.log.levels.WARN) 14 | return 15 | end 16 | vim.cmd.edit(vim.uri_to_fname(result)) 17 | end 18 | ) 19 | end 20 | 21 | return { 22 | cmd = { 'clangd', '--log=verbose' }, 23 | filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda', 'proto' }, 24 | root_markers = { 25 | '.clangd', 26 | '.clang-tidy', 27 | '.clang-format', 28 | 'compile_commands.json', 29 | 'compile_flags.txt', 30 | 'configure.ac', -- GNU Autotools. 31 | }, 32 | capabilities = { 33 | textDocument = { 34 | completion = { 35 | editsNearCursor = true, 36 | }, 37 | }, 38 | -- Off-spec, but clangd and vim.lsp support UTF-8, which is more efficient. 39 | offsetEncoding = { 'utf-8', 'utf-16' }, 40 | }, 41 | 42 | -- Assumes at most one clangd client is attached to a buffer. 43 | on_attach = function(client, buf) 44 | vim.api.nvim_buf_create_user_command(buf, 'ClangdSwitchSourceHeader', function() 45 | switch_source_header(client, buf) 46 | end, { 47 | bar = true, 48 | desc = 'clangd: Switch Between Source and Header File', 49 | }) 50 | vim.keymap.set('n', 'grs', 'ClangdSwitchSourceHeader', { 51 | buffer = buf, 52 | desc = 'clangd: Switch Between Source and Header File', 53 | }) 54 | 55 | vim.api.nvim_create_autocmd('LspDetach', { 56 | group = vim.api.nvim_create_augroup('conf_lsp_attach_detach', { clear = false }), 57 | buffer = buf, 58 | callback = function(args) 59 | if args.data.client_id == client.id then 60 | vim.keymap.del('n', 'grs', { buffer = buf }) 61 | vim.api.nvim_buf_del_user_command(buf, 'ClangdSwitchSourceHeader') 62 | return true -- Delete this autocmd. 63 | end 64 | end, 65 | }) 66 | end, 67 | } --[[@as vim.lsp.Config]] 68 | -------------------------------------------------------------------------------- /lsp/cmake.lua: -------------------------------------------------------------------------------- 1 | --- https://github.com/regen100/cmake-language-server 2 | --- 3 | return { 4 | cmd = { 'cmake-language-server' }, 5 | filetypes = { 'cmake' }, 6 | root_markers = { 'CMakePresets.json', 'CTestConfig.cmake', '.git', 'build', 'cmake' }, 7 | init_options = { 8 | buildDirectory = 'build', 9 | }, 10 | } --[[@as vim.lsp.Config]] 11 | -------------------------------------------------------------------------------- /lsp/luals.lua: -------------------------------------------------------------------------------- 1 | return { 2 | cmd = { 'lua-language-server' }, 3 | filetypes = { 'lua' }, 4 | root_markers = { 5 | '.luarc.json', 6 | '.luarc.jsonc', 7 | '.luacheckrc', 8 | '.stylua.toml', 9 | 'stylua.toml', 10 | 'selene.toml', 11 | 'selene.yml', 12 | '.git', 13 | }, 14 | on_init = function(client) 15 | if client.workspace_folders then 16 | local path = client.workspace_folders[1].name 17 | if 18 | path ~= vim.fn.stdpath('config') 19 | and (vim.uv.fs_stat(path .. '/.luarc.json') or vim.uv.fs_stat(path .. '/.luarc.jsonc')) 20 | then 21 | return 22 | end 23 | end 24 | 25 | client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, { 26 | runtime = { 27 | version = 'LuaJIT', 28 | }, 29 | workspace = { 30 | checkThirdParty = false, 31 | library = { 32 | vim.env.VIMRUNTIME, 33 | }, 34 | }, 35 | }) 36 | end, 37 | settings = { 38 | Lua = {}, 39 | }, 40 | } 41 | -------------------------------------------------------------------------------- /lsp/ruff.lua: -------------------------------------------------------------------------------- 1 | --- Refer to the [documentation](https://docs.astral.sh/ruff/editors/) for more details. 2 | return { 3 | cmd = { 'ruff', 'server' }, 4 | filetypes = { 'python' }, 5 | root_markers = { 'pyproject.toml', 'ruff.toml', '.ruff.toml', '.git' }, 6 | } 7 | -------------------------------------------------------------------------------- /lsp/rust_analyzer.lua: -------------------------------------------------------------------------------- 1 | return { 2 | cmd = { 'rust-analyzer' }, 3 | filetypes = { 'rust' }, 4 | root_markers = { 5 | 'Cargo.toml', 6 | 'Cargo.lock', 7 | 'rust-project.json', 8 | }, 9 | before_init = function(init_params, _) 10 | if vim.system({ 'cargo', 'clippy', '--version' }):wait().code == 0 then 11 | init_params.initializationOptions = vim.tbl_extend( 12 | 'force', 13 | init_params.initializationOptions --[[@as table?]] 14 | or {}, 15 | { check = { command = 'clippy' } } 16 | ) 17 | end 18 | end, 19 | } --[[@as vim.lsp.Config]] 20 | -------------------------------------------------------------------------------- /lsp/tsls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | init_options = { hostInfo = 'neovim' }, 3 | cmd = { 'typescript-language-server', '--stdio' }, 4 | filetypes = { 5 | 'javascript', 6 | 'javascriptreact', 7 | 'javascript.jsx', 8 | 'typescript', 9 | 'typescriptreact', 10 | 'typescript.tsx', 11 | }, 12 | root_markers = { 'tsconfig.json', 'jsconfig.json', 'package.json', '.git' }, 13 | } 14 | -------------------------------------------------------------------------------- /lsp/zls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | cmd = { 'zls' }, 3 | filetypes = { 'zig', 'zir' }, 4 | root_markers = { 5 | 'build.zig', 6 | 'zls.json', 7 | }, 8 | } --[[@as vim.lsp.Config]] 9 | -------------------------------------------------------------------------------- /lua/private/dashboard.lua: -------------------------------------------------------------------------------- 1 | local group = vim.api.nvim_create_augroup('Dashboard', { clear = true }) 2 | 3 | local M = {} 4 | 5 | local config = { 6 | lambda_art = { 7 | '⠀⠀⠀⢀⣠⣴⣶⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀', 8 | '⠀⠀⣴⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀', 9 | '⠀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀', 10 | '⠘⣿⣿⣿⣿⡟⠉⢿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀', 11 | '⠀⠈⠛⠛⠋⠀⠀⠈⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀', 12 | '⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀', 13 | '⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀', 14 | '⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀', 15 | '⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀', 16 | '⠀⠀⠀⠀⢀⣼⣿⣿⣿⣿⡿⢿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀', 17 | '⠀⠀⠀⢠⣾⣿⣿⣿⣿⡟⠁⠘⣿⣿⣿⣿⣷⠀⠀⠀⣀⡀⠀⠀', 18 | '⠀⠀⣠⣿⣿⣿⣿⣿⠏⠀⠀⠀⢻⣿⣿⣿⣿⡆⣰⣿⣿⣿⣷⡀', 19 | '⠀⣴⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠁', 20 | '⠰⣿⣿⣿⣿⡿⠁⠀⠀⠀⠀⠀⠀⠘⢿⣿⣿⣿⣿⣿⣿⡟⠁⠀', 21 | '⠀⠙⠻⠿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠿⠟⠛⠁⠀⠀⠀', 22 | }, 23 | 24 | shortcuts = { 25 | { key = 'f', desc = 'Open File', action = 'FzfLua files' }, 26 | { key = 'o', desc = 'Recent Files', action = 'FzfLua oldfiles' }, 27 | { key = 'd', desc = 'Dotfiles', action = 'FzfLua files cwd=$HOME/.config' }, 28 | { key = 'e', desc = 'New File', action = 'enew' }, 29 | { key = 'u', desc = 'Update Plugins', action = 'Strive update' }, 30 | { key = 'q', desc = 'Quit', action = 'qa' }, 31 | }, 32 | 33 | highlights = { 34 | lambda = 'DashboardLambda', 35 | key = 'DashboardKey', 36 | desc = 'DashboardDesc', 37 | date = 'DashboardDate', 38 | footer = 'DashboardFooter', 39 | }, 40 | 41 | layout = { 42 | top_offset = 8, 43 | date_top_offset = 3, 44 | plugin_info_offset = 5, 45 | shortcuts_top_offset = 3, 46 | }, 47 | } 48 | 49 | local function calculate_positions() 50 | local screen_width = vim.o.columns 51 | 52 | local lambda_display_width = 0 53 | for _, line in ipairs(config.lambda_art) do 54 | lambda_display_width = math.max(lambda_display_width, vim.fn.strdisplaywidth(line)) 55 | end 56 | 57 | local max_right_display_width = 0 58 | 59 | local sample_plugin = 'load 999/999 plugins in 9999.999ms' 60 | max_right_display_width = math.max(max_right_display_width, vim.fn.strdisplaywidth(sample_plugin)) 61 | 62 | local gap = 2 63 | 64 | local total_display_width = lambda_display_width + gap + max_right_display_width 65 | 66 | local start_pos = math.max(1, math.floor((screen_width - total_display_width) / 2)) 67 | 68 | return { 69 | lambda_left_margin = start_pos, 70 | right_section_left = start_pos + lambda_display_width + gap, 71 | } 72 | end 73 | 74 | local function setup_highlights() 75 | local highlights = { 76 | DashboardLambda = { fg = '#7aa2f7', bold = true }, 77 | DashboardKey = { fg = '#f7768e', bold = true }, 78 | DashboardDesc = { fg = '#9ece6a' }, 79 | DashboardDate = { fg = '#e0af68', bold = true }, 80 | DashboardFooter = { fg = '#565f89', italic = true }, 81 | } 82 | 83 | for g, opts in pairs(highlights) do 84 | vim.api.nvim_set_hl(0, g, opts) 85 | end 86 | end 87 | 88 | local function get_datetime() 89 | local datetime = os.date('*t') 90 | local weekdays = { 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' } 91 | local months = 92 | { 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec' } 93 | 94 | local weekday = weekdays[datetime.wday] 95 | local year = datetime.year 96 | local month = months[datetime.month] 97 | local day = datetime.day 98 | local hour = string.format('%02d', datetime.hour) 99 | local min = string.format('%02d', datetime.min) 100 | 101 | return string.format('%s %d %s %d %s:%s', weekday, year, month, day, hour, min) 102 | end 103 | 104 | local function create_dashboard_buffer() 105 | local buf = vim.api.nvim_get_current_buf() 106 | vim.bo[buf].bufhidden = 'wipe' 107 | vim.bo[buf].buftype = 'nofile' 108 | vim.bo[buf].buflisted = false 109 | vim.bo[buf].modifiable = false 110 | return buf 111 | end 112 | 113 | local function render_dashboard(buf) 114 | local lines = {} 115 | local highlights_to_apply = {} 116 | 117 | local pos = calculate_positions() 118 | 119 | for _ = 1, config.layout.top_offset do 120 | table.insert(lines, '') 121 | end 122 | 123 | local lambda_lines = #config.lambda_art 124 | local date_line_idx = config.layout.top_offset + config.layout.date_top_offset 125 | local plugin_info_line_idx = config.layout.top_offset + config.layout.plugin_info_offset 126 | local shortcuts_start_idx = plugin_info_line_idx + config.layout.shortcuts_top_offset 127 | 128 | local total_lines = math.max( 129 | config.layout.top_offset + lambda_lines, 130 | shortcuts_start_idx + #config.shortcuts, 131 | plugin_info_line_idx + 1 132 | ) 133 | 134 | for _ = #lines + 1, total_lines do 135 | table.insert(lines, '') 136 | end 137 | 138 | for i, lambda_line in ipairs(config.lambda_art) do 139 | local line_idx = config.layout.top_offset + i 140 | if line_idx <= #lines then 141 | local new_line = string.rep(' ', pos.lambda_left_margin - 1) .. lambda_line 142 | lines[line_idx] = new_line 143 | 144 | local lambda_byte_start = pos.lambda_left_margin - 1 145 | local lambda_byte_end = lambda_byte_start + #lambda_line 146 | 147 | table.insert(highlights_to_apply, { 148 | line = line_idx - 1, 149 | col_start = lambda_byte_start, 150 | col_end = lambda_byte_end, 151 | hl_group = config.highlights.lambda, 152 | }) 153 | end 154 | end 155 | 156 | local datetime_str = get_datetime() 157 | if date_line_idx <= #lines then 158 | local current_line = lines[date_line_idx] or '' 159 | local needed_spaces = math.max(0, pos.right_section_left - 1 - #current_line) 160 | local new_line = current_line .. string.rep(' ', needed_spaces) .. datetime_str 161 | lines[date_line_idx] = new_line 162 | 163 | local date_byte_start = #current_line + needed_spaces 164 | local date_byte_end = date_byte_start + #datetime_str 165 | 166 | table.insert(highlights_to_apply, { 167 | line = date_line_idx - 1, 168 | col_start = date_byte_start, 169 | col_end = date_byte_end, 170 | hl_group = config.highlights.date, 171 | }) 172 | end 173 | 174 | local startup_time = vim.g.strive_startup_time or '0' 175 | local plugin_info_str = string.format( 176 | 'load %d/%d plugins in %sms', 177 | vim.g.strive_loaded or 0, 178 | vim.g.strive_count or 0, 179 | startup_time 180 | ) 181 | 182 | if plugin_info_line_idx <= #lines then 183 | local current_line = lines[plugin_info_line_idx] or '' 184 | local needed_spaces = math.max(0, pos.right_section_left - 1 - #current_line) 185 | local new_line = current_line .. string.rep(' ', needed_spaces) .. plugin_info_str 186 | lines[plugin_info_line_idx] = new_line 187 | 188 | local plugin_byte_start = #current_line + needed_spaces 189 | local plugin_byte_end = plugin_byte_start + #plugin_info_str 190 | 191 | table.insert(highlights_to_apply, { 192 | line = plugin_info_line_idx - 1, 193 | col_start = plugin_byte_start, 194 | col_end = plugin_byte_end, 195 | hl_group = config.highlights.footer, 196 | }) 197 | end 198 | 199 | local cursor = {} 200 | 201 | local shortcuts = config.shortcuts 202 | for i, shortcut in ipairs(shortcuts) do 203 | local row_idx = shortcuts_start_idx + i - 1 204 | if row_idx <= #lines then 205 | local shortcut_text = string.format('[%s] %s', shortcut.key, shortcut.desc) 206 | 207 | local current_line = lines[row_idx] or '' 208 | local needed_spaces = math.max(2, pos.right_section_left - 1 - #current_line) 209 | local new_line = current_line .. string.rep(' ', needed_spaces) .. shortcut_text 210 | if i == 1 then 211 | cursor[1] = row_idx 212 | cursor[2] = #new_line - #shortcut_text + 5 213 | end 214 | lines[row_idx] = new_line 215 | 216 | local shortcut_byte_start = #current_line + needed_spaces 217 | 218 | table.insert(highlights_to_apply, { 219 | line = row_idx - 1, 220 | col_start = shortcut_byte_start + 1, 221 | col_end = shortcut_byte_start + 2, 222 | hl_group = config.highlights.key, 223 | }) 224 | 225 | table.insert(highlights_to_apply, { 226 | line = row_idx - 1, 227 | col_start = shortcut_byte_start + 3, 228 | col_end = shortcut_byte_start + #shortcut_text, 229 | hl_group = config.highlights.desc, 230 | }) 231 | end 232 | end 233 | 234 | vim.bo[buf].modifiable = true 235 | vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) 236 | vim.bo[buf].modifiable = false 237 | vim.api.nvim_win_set_cursor(0, cursor) 238 | 239 | local ns_id = vim.api.nvim_create_namespace('dashboard') 240 | for _, hl in ipairs(highlights_to_apply) do 241 | vim.hl.range(buf, ns_id, hl.hl_group, { hl.line, hl.col_start }, { hl.line, hl.col_end }) 242 | end 243 | end 244 | 245 | local function setup_keymaps(buf) 246 | local opts = { noremap = true, silent = true, buffer = buf } 247 | 248 | for _, shortcut in ipairs(config.shortcuts) do 249 | vim.keymap.set('n', shortcut.key, shortcut.action, opts) 250 | end 251 | 252 | vim.keymap.set('n', '', ':q', opts) 253 | vim.keymap.set('n', 'q', ':q', opts) 254 | end 255 | 256 | local function opt_handler() 257 | local save_opts = {} 258 | 259 | save_opts.number = vim.wo.number 260 | save_opts.relativenumber = vim.wo.relativenumber 261 | save_opts.cursorline = vim.wo.cursorline 262 | save_opts.cursorcolumn = vim.wo.cursorcolumn 263 | save_opts.colorcolumn = vim.wo.colorcolumn 264 | save_opts.signcolumn = vim.wo.signcolumn 265 | save_opts.wrap = vim.wo.wrap 266 | save_opts.laststatus = vim.o.laststatus 267 | save_opts.showtabline = vim.o.showtabline 268 | 269 | return function() 270 | vim.wo.number = save_opts.number 271 | vim.wo.relativenumber = save_opts.relativenumber 272 | vim.wo.cursorline = save_opts.cursorline 273 | vim.wo.cursorcolumn = save_opts.cursorcolumn 274 | vim.wo.colorcolumn = save_opts.colorcolumn 275 | vim.wo.signcolumn = save_opts.signcolumn 276 | vim.wo.wrap = save_opts.wrap 277 | vim.o.laststatus = save_opts.laststatus 278 | vim.o.showtabline = save_opts.showtabline 279 | end 280 | end 281 | 282 | function M.show() 283 | if vim.fn.argc() > 0 or vim.fn.line2byte('$') ~= -1 then 284 | return 285 | end 286 | 287 | local buf = create_dashboard_buffer() 288 | vim.api.nvim_set_current_buf(buf) 289 | render_dashboard(buf) 290 | setup_highlights() 291 | setup_keymaps(buf) 292 | 293 | local restore_opt = opt_handler() 294 | 295 | vim.wo.number = false 296 | vim.wo.relativenumber = false 297 | vim.wo.cursorline = false 298 | vim.wo.cursorcolumn = false 299 | vim.wo.colorcolumn = '0' 300 | vim.wo.signcolumn = 'no' 301 | vim.wo.wrap = true 302 | 303 | vim.o.laststatus = 0 304 | vim.o.showtabline = 0 305 | 306 | vim.api.nvim_create_autocmd('VimResized', { 307 | group = group, 308 | callback = function() 309 | if vim.bo.buftype == 'nofile' and vim.bo.filetype == '' then 310 | render_dashboard(buf) 311 | end 312 | end, 313 | }) 314 | 315 | vim.api.nvim_create_autocmd('BufLeave', { 316 | buffer = buf, 317 | group = group, 318 | callback = function() 319 | restore_opt() 320 | end, 321 | }) 322 | end 323 | 324 | vim.api.nvim_create_autocmd('VimEnter', { 325 | group = group, 326 | callback = function() 327 | if vim.fn.argc() == 0 and vim.fn.line2byte('$') == -1 then 328 | M.show() 329 | end 330 | end, 331 | }) 332 | 333 | vim.api.nvim_create_user_command('Dashboard', function() 334 | M.show() 335 | end, {}) 336 | 337 | return M 338 | -------------------------------------------------------------------------------- /lua/private/grep.lua: -------------------------------------------------------------------------------- 1 | local api, QUICK, LOCAL, FORWARD, BACKWARD, mapset = vim.api, 1, 2, 1, 2, vim.keymap.set 2 | local treesitter, fn = vim.treesitter, vim.fn 3 | 4 | local state = { 5 | preview = { 6 | win = nil, 7 | enabled = false, 8 | }, 9 | count = 0, 10 | match_ids = {}, 11 | } 12 | 13 | local function create_preview_window(bufnr) 14 | local preview = state.preview 15 | local qf_win = api.nvim_get_current_win() 16 | local qf_width = api.nvim_win_get_width(qf_win) 17 | local qf_position = api.nvim_win_get_position(qf_win) 18 | 19 | local preview_height = math.floor(vim.o.lines * 0.6) 20 | local preview_row = qf_position[1] - preview_height - 3 21 | 22 | if preview_row < 0 then 23 | preview_row = 0 24 | preview_height = qf_position[1] - 1 25 | end 26 | 27 | local win_opts = { 28 | style = 'minimal', 29 | relative = 'editor', 30 | row = preview_row, 31 | col = qf_position[2], 32 | width = qf_width, 33 | height = preview_height, 34 | focusable = false, 35 | } 36 | 37 | preview.win = api.nvim_open_win(bufnr, false, win_opts) 38 | 39 | mapset('n', '', function() 40 | if preview.win and api.nvim_win_is_valid(preview.win) then 41 | api.nvim_win_close(preview.win, true) 42 | preview.win = nil 43 | end 44 | end, { buffer = preview.buf }) 45 | 46 | api.nvim_create_autocmd('WinClosed', { 47 | buffer = bufnr, 48 | once = true, 49 | callback = function() 50 | api.nvim_win_close(preview.win, true) 51 | state.count = 0 52 | state.preview.win = nil 53 | state.preview.enabled = false 54 | end, 55 | }) 56 | end 57 | 58 | local function update_preview() 59 | local preview = state.preview 60 | if not preview.enabled then 61 | return 62 | end 63 | 64 | local win_id = api.nvim_get_current_win() 65 | local win_info = fn.getwininfo(win_id)[1] 66 | 67 | local is_loclist = win_info.loclist == 1 68 | 69 | local idx = fn.line('.') 70 | local list = is_loclist and fn.getloclist(0) or fn.getqflist() 71 | 72 | if idx > 0 and idx <= #list then 73 | local item = list[idx] 74 | if not item.bufnr then 75 | return 76 | end 77 | 78 | if not preview.win or not api.nvim_win_is_valid(preview.win) then 79 | create_preview_window(item.bufnr) 80 | end 81 | 82 | local ft = vim.filetype.match({ buf = item.bufnr }) 83 | if ft then 84 | local lang = treesitter.language.get_lang(ft) 85 | local ok = pcall(treesitter.get_parser, item.bufnr, lang) 86 | if ok then 87 | vim.treesitter.start(item.bufnr, lang) 88 | end 89 | end 90 | 91 | if preview.win and api.nvim_win_is_valid(preview.win) then 92 | api.nvim_win_set_buf(preview.win, item.bufnr) 93 | api.nvim_win_set_cursor(preview.win, { item.lnum, item.col }) 94 | api.nvim_win_call(preview.win, function() 95 | vim.cmd('normal! zz') 96 | end) 97 | end 98 | end 99 | end 100 | 101 | local function toggle_preview(buf) 102 | local preview = state.preview 103 | preview.enabled = not preview.enabled 104 | if preview.enabled then 105 | update_preview() 106 | api.nvim_create_autocmd('CursorMoved', { 107 | buffer = buf, 108 | callback = update_preview, 109 | }) 110 | elseif preview.win and api.nvim_win_is_valid(preview.win) then 111 | api.nvim_win_close(preview.win, true) 112 | preview.win = nil 113 | end 114 | end 115 | 116 | local function setup_init(buf, is_quick) 117 | vim.opt_local.wrap = false 118 | vim.opt_local.number = false 119 | vim.opt_local.relativenumber = false 120 | vim.opt_local.signcolumn = 'no' 121 | 122 | local win = api.nvim_get_current_win() 123 | fn.clearmatches(win) 124 | 125 | fn.matchadd('qfFileName', '^▸ \\zs.*', 12, -1, { window = win }) 126 | fn.matchadd('qfLineNr', '^\\s\\+\\d\\+:\\d\\+', 20, -1, { window = win }) 127 | fn.matchadd('qfSeparator', '│', 15, -1, { window = win }) 128 | fn.matchadd('qfText', '│ \\zs.*', 10, -1, { window = win }) 129 | 130 | local move = function(dir) 131 | return function() 132 | api.nvim_buf_call(buf, function() 133 | pcall( 134 | vim.cmd, 135 | dir == FORWARD and (is_quick and 'cnext' or 'lnext') or (is_quick and 'cprev' or 'lprev') 136 | ) 137 | update_preview() 138 | end) 139 | end 140 | end 141 | 142 | local preview = state.preview 143 | mapset('n', 'q', function() 144 | if preview.win and api.nvim_win_is_valid(preview.win) then 145 | api.nvim_win_close(preview.win, true) 146 | preview.win = nil 147 | end 148 | vim.cmd('cclose') 149 | end, { buffer = buf }) 150 | 151 | mapset('n', '', move(FORWARD), { buffer = buf }) 152 | mapset('n', '', move(BACKWARD), { buffer = buf }) 153 | 154 | mapset('n', 'p', function() 155 | toggle_preview(buf) 156 | end, { buffer = buf }) 157 | end 158 | 159 | local function update_title() 160 | local width = 15 161 | local bar = '' 162 | 163 | if not state.done then 164 | local anim_pos = state.count % width 165 | for i = 1, width do 166 | bar = bar .. (i == anim_pos and '●' or '○') 167 | end 168 | else 169 | bar = string.rep('●', width) 170 | end 171 | 172 | vim.wo[state.win].stl = 173 | string.format(' %s [%s] %d matches', state.done and 'Done' or 'Searching', bar, state.count) 174 | api.nvim__redraw({ 175 | win = state.win, 176 | buf = state.buf, 177 | statusline = true, 178 | }) 179 | end 180 | 181 | function _G.compact_quickfix_format(info) 182 | local lines = {} 183 | local list = info.quickfix == 1 and vim.fn.getqflist() or vim.fn.getloclist(info.winid) 184 | local last_bufnr = nil 185 | 186 | for i = info.start_idx, info.end_idx do 187 | local item = list[i] 188 | if item and item.valid == 1 and item.lnum > 0 and item.text ~= '' then 189 | local filename = item.bufnr > 0 and vim.fn.bufname(item.bufnr) or '' 190 | local text = item.text or '' 191 | 192 | if item.bufnr ~= last_bufnr then 193 | table.insert(lines, string.format('▸ %s', filename)) 194 | last_bufnr = item.bufnr 195 | end 196 | 197 | table.insert(lines, string.format(' %4d:%-3d │ %s', item.lnum, item.col, text)) 198 | end 199 | end 200 | return lines 201 | end 202 | 203 | local grep = async(function(t, ...) 204 | local args = { ... } 205 | local grepprg = vim.o.grepprg 206 | local cmd = vim.split(grepprg, '%s+', { trimempty = true }) 207 | local qf_fn = t == QUICK and function(...) 208 | fn.setqflist(...) 209 | end or function(...) 210 | fn.setloclist(0, ...) 211 | end 212 | 213 | for _, arg in ipairs(args) do 214 | table.insert(cmd, arg) 215 | end 216 | table.insert(cmd, '--fixed-strings') 217 | 218 | local opened = false 219 | local id = nil 220 | local batch_size = 200 221 | local chunk = {} 222 | local seen_files = {} 223 | local result = try_await(asystem(cmd, { 224 | text = true, 225 | stdout = function(err, data) 226 | assert(not err) 227 | state.done = not data 228 | local process = {} 229 | if data then 230 | local lines = vim.split(data, '\n', { trimempty = true }) 231 | if #lines > 0 then 232 | for _, line in ipairs(lines) do 233 | -- parse format: filename:lnum:col:text 234 | local filename, lnum, col, text = line:match('^([^:]+):(%d+):(%d+):(.*)$') 235 | if filename and lnum and col and text then 236 | -- check is new file 237 | if not seen_files[filename] then 238 | -- insert header for it 239 | table.insert(chunk, string.format('%s:0:0:', filename)) 240 | seen_files[filename] = true 241 | end 242 | end 243 | table.insert(chunk, line) 244 | end 245 | end 246 | end 247 | 248 | if #chunk >= batch_size then 249 | process = { unpack(chunk, 1, batch_size) } 250 | chunk = { unpack(chunk, batch_size + 1, #chunk) } 251 | end 252 | 253 | vim.schedule(function() 254 | if #process > 0 or not data then 255 | qf_fn({}, 'a', { 256 | lines = not data and chunk or process, 257 | id = id, 258 | efm = vim.o.errorformat, 259 | quickfixtextfunc = 'v:lua.compact_quickfix_format', 260 | title = 'Grep', 261 | }) 262 | 263 | if not opened then 264 | vim.cmd(t == QUICK and 'cw' or 'lw') 265 | local buf = api.nvim_get_current_buf() 266 | state.win = api.nvim_get_current_win() 267 | setup_init(buf, t == QUICK) 268 | opened = true 269 | end 270 | 271 | state.count = state.count + (not data and #chunk or #process) 272 | update_title() 273 | end 274 | end) 275 | end, 276 | })) 277 | 278 | if result.error then 279 | return vim.notify('Grep failed: ' .. tostring(result.error.message or ''), vim.log.levels.ERROR) 280 | end 281 | end) 282 | 283 | api.nvim_create_user_command('Grep', function(opts) 284 | grep(LOCAL, opts.args) 285 | end, { nargs = '+', complete = 'file_in_path', desc = 'Search using localtion list' }) 286 | 287 | api.nvim_create_user_command('GREP', function(opts) 288 | grep(QUICK, opts.args) 289 | end, { nargs = '+', complete = 'file_in_path', desc = 'Search using quickfix list' }) 290 | 291 | api.nvim_create_autocmd('CmdlineEnter', { 292 | pattern = ':', 293 | callback = function() 294 | vim.cmd( 295 | [[cnoreabbrev grep (getcmdtype() ==# ':' && getcmdline() ==# 'grep') ? 'Grep' : 'grep']] 296 | ) 297 | end, 298 | }) 299 | -------------------------------------------------------------------------------- /lua/private/jump.lua: -------------------------------------------------------------------------------- 1 | -- Minimal asynchronous fast jump based on rg 2 | 3 | local api = vim.api 4 | local M = {} 5 | local FORWARD, BACKWARD = 1, -1 6 | 7 | local state = { 8 | active = false, 9 | mode = nil, 10 | ns_id = nil, 11 | key_map = {}, 12 | on_key_func = nil, 13 | max_targets = 60, -- keys count 14 | } 15 | 16 | local function cleanup() 17 | if state.active then 18 | if state.ns_id then 19 | api.nvim_buf_clear_namespace(0, state.ns_id, 0, -1) 20 | end 21 | if state.on_key_func then 22 | vim.on_key(nil, state.ns_id) 23 | state.on_key_func = nil 24 | end 25 | 26 | state.active = false 27 | state.mode = nil 28 | state.key_map = {} 29 | 30 | if state.id then 31 | api.nvim_del_autocmd(state.id) 32 | end 33 | end 34 | end 35 | 36 | local function generate_keys(count) 37 | local keys = 'asdghjklzxcvbnmqwertyuiopASDGHJLZXCVBNMQWERTYUIOP1234567890' 38 | local key_len = #keys 39 | local result = {} 40 | 41 | for i = 1, math.min(count, key_len) do 42 | table.insert(result, string.sub(keys, i, i)) 43 | end 44 | 45 | return result 46 | end 47 | 48 | local function mark_targets(targets) 49 | if not state.ns_id then 50 | state.ns_id = api.nvim_create_namespace('jumpmotion') 51 | end 52 | 53 | api.nvim_buf_clear_namespace(0, state.ns_id, 0, -1) 54 | 55 | local keys = generate_keys(#targets) 56 | state.key_map = {} 57 | 58 | for i, target in ipairs(targets) do 59 | if i <= #keys then 60 | local key = keys[i] 61 | state.key_map[key] = target 62 | 63 | api.nvim_buf_set_extmark(0, state.ns_id, target.row, target.col, { 64 | virt_text = { { key, 'JumpMotionTarget' } }, 65 | virt_text_pos = 'overlay', 66 | priority = 100, 67 | }) 68 | end 69 | end 70 | 71 | state.on_key_func = function(char, typed) 72 | if not state.active then 73 | return 74 | end 75 | 76 | if char == '\27' then 77 | cleanup() 78 | return 79 | end 80 | 81 | local target = state.key_map[typed] 82 | if target then 83 | api.nvim_win_set_cursor(0, { target.row + 1, target.col }) 84 | cleanup() 85 | return '' 86 | end 87 | 88 | cleanup() 89 | end 90 | 91 | vim.on_key(state.on_key_func, state.ns_id) 92 | 93 | state.id = api.nvim_create_autocmd({ 'CursorMoved', 'InsertEnter', 'BufLeave', 'WinLeave' }, { 94 | once = true, 95 | callback = function() 96 | if state.active then 97 | cleanup() 98 | end 99 | end, 100 | }) 101 | end 102 | 103 | function M.char(direction) 104 | if vim.fn.executable('rg') == 0 or vim.fn.line2byte(vim.fn.line('$') + 1) == -1 then 105 | return 106 | end 107 | 108 | return function() 109 | async(function() 110 | if state.active then 111 | cleanup() 112 | end 113 | 114 | local ok, char = pcall(function() 115 | return vim.fn.nr2char(vim.fn.getchar()) 116 | end) 117 | if not ok or not char or char == '' or char == vim.fn.nr2char(27) then 118 | return false 119 | end 120 | local char_input = char 121 | 122 | state.active = true 123 | state.mode = 'char' 124 | 125 | local first_line = vim.fn.line('w0') - 1 126 | local curow = api.nvim_win_get_cursor(0)[1] - 1 127 | if curow == 0 and direction == BACKWARD then 128 | return 129 | end 130 | local last_line = vim.fn.line('w$') 131 | 132 | local lines 133 | local base_row 134 | 135 | if direction == FORWARD then 136 | base_row = curow + 1 137 | lines = api.nvim_buf_get_lines(0, curow + 1, last_line, false) 138 | else 139 | base_row = first_line 140 | lines = api.nvim_buf_get_lines(0, first_line, curow, false) 141 | local reversed_lines = {} 142 | for i = #lines, 1, -1 do 143 | table.insert(reversed_lines, lines[i]) 144 | end 145 | lines = reversed_lines 146 | end 147 | 148 | local visible_text = table.concat(lines, '\n') 149 | 150 | local cmd = { 151 | 'rg', 152 | '--json', 153 | '--fixed-strings', 154 | char_input, 155 | } 156 | 157 | local result = await(asystem(cmd, { stdin = visible_text })) 158 | 159 | local targets = {} 160 | local count = 0 161 | 162 | if result.stdout then 163 | for line in string.gmatch(result.stdout, '[^\r\n]+') do 164 | if line:find('"type":"match"') then 165 | local ok, json = pcall(vim.json.decode, line) 166 | if ok and json and json.type == 'match' and json.data then 167 | local row = json.data.line_number - 1 168 | 169 | if json.data.submatches and #json.data.submatches > 0 then 170 | for _, submatch in ipairs(json.data.submatches) do 171 | local col = submatch.start 172 | 173 | local actual_row 174 | if direction == FORWARD then 175 | actual_row = base_row + row 176 | else 177 | actual_row = curow - 1 - row 178 | end 179 | 180 | table.insert(targets, { 181 | row = actual_row, 182 | col = col, 183 | }) 184 | 185 | count = count + 1 186 | if count >= state.max_targets then 187 | break 188 | end 189 | end 190 | end 191 | 192 | if count >= state.max_targets then 193 | break 194 | end 195 | end 196 | end 197 | end 198 | end 199 | 200 | if direction == BACKWARD then 201 | table.sort(targets, function(a, b) 202 | return a.row < b.row 203 | end) 204 | end 205 | 206 | if #targets == 0 then 207 | cleanup() 208 | return 209 | end 210 | 211 | mark_targets(targets) 212 | end)() 213 | end 214 | end 215 | 216 | api.nvim_set_hl(0, 'JumpMotionTarget', { 217 | fg = '#ff4800', 218 | bold = true, 219 | }) 220 | 221 | return { charForward = M.char(FORWARD), charBackward = M.char(BACKWARD) } 222 | -------------------------------------------------------------------------------- /lua/private/keymap.lua: -------------------------------------------------------------------------------- 1 | local api = vim.api 2 | 3 | -- Create a smart keymap wrapper using metatables 4 | local keymap = {} 5 | 6 | -- Valid vim modes 7 | local valid_modes = 8 | { n = true, i = true, v = true, x = true, s = true, o = true, c = true, t = true } 9 | 10 | -- Store mode combinations we've created 11 | local mode_cache = {} 12 | 13 | -- Function that performs the actual mapping 14 | local function perform_mapping(modes, lhs, rhs, opts) 15 | opts = opts or {} 16 | local mapset = vim.keymap.set 17 | 18 | if type(lhs) == 'table' then 19 | -- Handle table of mappings 20 | for key, action in pairs(lhs) do 21 | mapset(modes, key, action, opts) 22 | end 23 | else 24 | -- Handle single mapping 25 | mapset(modes, lhs, rhs, opts) 26 | end 27 | 28 | return keymap -- Return keymap for chaining 29 | end 30 | 31 | -- Parse a mode string into an array of mode characters 32 | local function parse_modes(mode_str) 33 | local modes = {} 34 | for i = 1, #mode_str do 35 | local char = mode_str:sub(i, i) 36 | if valid_modes[char] then 37 | table.insert(modes, char) 38 | end 39 | end 40 | return modes 41 | end 42 | 43 | -- Create the metatable that powers the dynamic mode access 44 | local mt = { 45 | __index = function(_, key) 46 | -- If this mode combination is already cached, return it 47 | if mode_cache[key] then 48 | return mode_cache[key] 49 | end 50 | 51 | -- Check if this is a valid mode string 52 | local modes = parse_modes(key) 53 | if #modes > 0 then 54 | -- Create and cache a function for this mode combination 55 | local mode_fn = function(lhs, rhs, opts) 56 | return perform_mapping(modes, lhs, rhs, opts) 57 | end 58 | 59 | mode_cache[key] = mode_fn 60 | return mode_fn 61 | end 62 | 63 | return nil -- Not a valid mode key 64 | end, 65 | 66 | -- Make the keymap table directly callable 67 | __call = function(_, modes, lhs, rhs, opts) 68 | if type(modes) == 'string' then 69 | -- Convert string to mode list 70 | return perform_mapping(parse_modes(modes), lhs, rhs, opts) 71 | else 72 | -- Assume modes is already a list 73 | return perform_mapping(modes, lhs, rhs, opts) 74 | end 75 | end, 76 | } 77 | 78 | local map = setmetatable(keymap, mt) 79 | 80 | -- Helper function for command mappings 81 | local cmd = function(command) 82 | return '' .. command .. '' 83 | end 84 | 85 | map.n({ 86 | ['j'] = 'gj', 87 | ['k'] = 'gk', 88 | [''] = cmd('write'), 89 | -- ['k'] = cmd(vim.bo.buftype == 'terminal' and 'q!' or 'BufKeepDelete'), 90 | [''] = cmd('bn'), 91 | [''] = cmd('bp'), 92 | [''] = cmd('qa!'), 93 | --window 94 | [''] = 'h', 95 | [''] = 'l', 96 | [''] = 'j', 97 | [''] = 'k', 98 | [''] = cmd('vertical resize -5'), 99 | [''] = cmd('vertical resize +5'), 100 | ['[t'] = cmd('vs | vertical resize -5 | terminal'), 101 | [']t'] = cmd('set splitbelow | sp | set nosplitbelow | resize -5 | terminal'), 102 | ['t'] = cmd('tabnew | terminal'), 103 | ['gV'] = '`[v`]', 104 | }) 105 | 106 | map.i({ 107 | [''] = 'diw', 108 | [''] = '', 109 | [''] = '', 110 | [''] = '^i', 111 | [''] = '', 112 | [''] = '', 113 | --down/up 114 | [''] = 'o', 115 | [''] = 'O', 116 | --@see https://github.com/neovim/neovim/issues/16416 117 | [''] = '', 118 | --@see https://vim.fandom.com/wiki/Moving_lines_up_or_down 119 | [''] = ':m .+1==gi', 120 | }) 121 | 122 | map.i('', function() 123 | local pos = vim.api.nvim_win_get_cursor(0) 124 | local row = pos[1] 125 | local col = pos[2] 126 | local line = vim.api.nvim_get_current_line() 127 | local total_lines = vim.api.nvim_buf_line_count(0) 128 | local trimmed_line = line:gsub('%s+$', '') 129 | local killed_text = '' 130 | 131 | if col == 0 then 132 | if trimmed_line == '' then 133 | if row < total_lines then 134 | killed_text = '\n' 135 | local next_line = api.nvim_buf_get_lines(0, row, row + 1, false)[1] or '' 136 | api.nvim_buf_set_lines(0, row - 1, row + 1, false, { next_line }) 137 | end 138 | else 139 | killed_text = line 140 | api.nvim_set_current_line('') 141 | end 142 | else 143 | if col < #trimmed_line then 144 | killed_text = line:sub(col + 1) 145 | api.nvim_set_current_line(line:sub(1, col)) 146 | else 147 | if row < total_lines then 148 | killed_text = '\n' 149 | local next_line = api.nvim_buf_get_lines(0, row, row + 1, false)[1] or '' 150 | api.nvim_buf_set_lines(0, row - 1, row + 1, false, { line .. next_line }) 151 | end 152 | end 153 | end 154 | 155 | if killed_text ~= '' then 156 | vim.fn.setreg('+', killed_text, 'v') 157 | end 158 | end) 159 | 160 | map.c({ 161 | [''] = '', 162 | [''] = '', 163 | [''] = '', 164 | [''] = '', 165 | [''] = '', 166 | [''] = '', 167 | }) 168 | 169 | map.t({ 170 | [''] = [[]], 171 | ['k'] = cmd('quit'), 172 | }) 173 | 174 | -- insert cut text to paste 175 | map.i('', function() 176 | local mark = api.nvim_buf_get_mark(0, 'a') 177 | local lnum, col = unpack(api.nvim_win_get_cursor(0)) 178 | if mark[1] == 0 then 179 | api.nvim_buf_set_mark(0, 'a', lnum, col, {}) 180 | else 181 | local keys = 'd`aa' 182 | api.nvim_feedkeys(api.nvim_replace_termcodes(keys, true, true, true), 'n', false) 183 | vim.schedule(function() 184 | api.nvim_buf_del_mark(0, 'a') 185 | end) 186 | end 187 | end) 188 | 189 | -- Ctrl-y works like emacs 190 | map.i('', function() 191 | if tonumber(vim.fn.pumvisible()) == 1 or vim.fn.getreg('"+'):find('%w') == nil then 192 | return '' 193 | end 194 | return 'p==a' 195 | end, { expr = true }) 196 | 197 | -- move line down 198 | map.i('', function() 199 | local lnum = api.nvim_win_get_cursor(0)[1] 200 | local line = api.nvim_buf_get_lines(0, lnum - 3, lnum - 2, false)[1] 201 | return #line > 0 and ':m .-2==gi' or 'kkddj:m .-2==gi' 202 | end, { expr = true }) 203 | 204 | map.i('', function() 205 | if tonumber(vim.fn.pumvisible()) == 1 then 206 | return '' 207 | elseif vim.snippet.active({ direction = 1 }) then 208 | return 'lua vim.snippet.jump(1)' 209 | else 210 | return '' 211 | end 212 | end, { expr = true }) 213 | 214 | map.i('', function() 215 | if vim.fn.pumvisible() == 1 then 216 | return '' 217 | elseif vim.snippet.active({ direction = -1 }) then 218 | return 'lua vim.snippet.jump(-1)' 219 | else 220 | return '' 221 | end 222 | end, { expr = true }) 223 | 224 | map.i('', function() 225 | if tonumber(vim.fn.pumvisible()) == 1 then 226 | return '' 227 | end 228 | local line = api.nvim_get_current_line() 229 | local col = api.nvim_win_get_cursor(0)[2] 230 | local before = line:sub(col, col) 231 | local after = line:sub(col + 1, col + 1) 232 | local t = { 233 | ['('] = ')', 234 | ['['] = ']', 235 | ['{'] = '}', 236 | } 237 | if t[before] and t[before] == after then 238 | return 'O' 239 | end 240 | return '' 241 | end, { expr = true }) 242 | 243 | map.i('', function() 244 | if vim.fn.pumvisible() == 1 then 245 | return '' 246 | else 247 | return '' 248 | end 249 | end, { expr = true }) 250 | 251 | local ns_id, mark_id = vim.api.nvim_create_namespace('my_marks'), nil 252 | 253 | map.i('', function() 254 | if not mark_id then 255 | local row, col = unpack(api.nvim_win_get_cursor(0)) 256 | mark_id = api.nvim_buf_set_extmark(0, ns_id, row - 1, col, { 257 | virt_text = { { '⚑', 'DiagnosticError' } }, 258 | hl_group = 'Search', 259 | virt_text_pos = 'inline', 260 | }) 261 | return 262 | end 263 | local mark = api.nvim_buf_get_extmark_by_id(0, ns_id, mark_id, {}) 264 | if not mark or #mark == 0 then 265 | return 266 | end 267 | pcall(api.nvim_win_set_cursor, 0, { mark[1] + 1, mark[2] }) 268 | api.nvim_buf_del_extmark(0, ns_id, mark_id) 269 | mark_id = nil 270 | end) 271 | 272 | -- gX: Web search 273 | map.n('gX', function() 274 | vim.ui.open(('https://google.com/search?q=%s'):format(vim.fn.expand(''))) 275 | end) 276 | 277 | map.x('gX', function() 278 | local lines = vim.fn.getregion(vim.fn.getpos('.'), vim.fn.getpos('v'), { type = vim.fn.mode() }) 279 | vim.ui.open(('https://google.com/search?q=%s'):format(vim.trim(table.concat(lines, ' ')))) 280 | api.nvim_input('') 281 | end) 282 | 283 | map.n('gs', function() 284 | local bufnr = api.nvim_create_buf(false, false) 285 | vim.bo[bufnr].buftype = 'prompt' 286 | vim.fn.prompt_setprompt(bufnr, ' ') 287 | api.nvim_buf_set_extmark(bufnr, api.nvim_create_namespace('WebSearch'), 0, 0, { 288 | line_hl_group = 'String', 289 | }) 290 | local width = math.floor(vim.o.columns * 0.5) 291 | local winid = api.nvim_open_win(bufnr, true, { 292 | relative = 'editor', 293 | row = 5, 294 | width = width, 295 | height = 1, 296 | col = math.floor(vim.o.columns / 2) - math.floor(width / 2), 297 | border = 'rounded', 298 | title = 'Google Search', 299 | title_pos = 'center', 300 | }) 301 | vim.cmd.startinsert() 302 | vim.wo[winid].number = false 303 | vim.wo[winid].stc = '' 304 | vim.wo[winid].lcs = 'trail: ' 305 | vim.wo[winid].wrap = true 306 | vim.wo[winid].signcolumn = 'no' 307 | vim.fn.prompt_setcallback(bufnr, function(text) 308 | vim.ui.open(('https://google.com/search?q=%s'):format(vim.trim(text))) 309 | api.nvim_win_close(winid, true) 310 | end) 311 | vim.keymap.set({ 'n', 'i' }, '', function() 312 | pcall(api.nvim_win_close, winid, true) 313 | end, { buffer = bufnr }) 314 | end) 315 | 316 | map.n({ 317 | -- Lspsaga 318 | ['[d'] = cmd('Lspsaga diagnostic_jump_next'), 319 | [']d'] = cmd('Lspsaga diagnostic_jump_prev'), 320 | ['ga'] = cmd('Lspsaga code_action'), 321 | ['gr'] = cmd('Lspsaga rename'), 322 | ['gd'] = cmd('Lspsaga peek_definition'), 323 | ['gp'] = cmd('Lspsaga goto_definition'), 324 | ['gh'] = cmd('Lspsaga finder'), 325 | -- ['o'] = cmd('Lspsaga outline'), 326 | -- dbsession 327 | ['ss'] = cmd('SessionSave'), 328 | ['sl'] = cmd('SessionLoad'), 329 | -- FzfLua 330 | ['b'] = cmd('FzfLua buffers'), 331 | ['fa'] = cmd('FzfLua live_grep_native'), 332 | ['fs'] = cmd('FzfLua grep_cword'), 333 | ['ff'] = cmd('FzfLua files'), 334 | ['fh'] = cmd('FzfLua helptags'), 335 | ['fo'] = cmd('FzfLua oldfiles'), 336 | ['fg'] = cmd('FzfLua git_files'), 337 | ['gc'] = cmd('FzfLua git_commits'), 338 | ['o'] = cmd('FzfLua lsp_document_symbols'), 339 | ['fc'] = cmd('FzfLua files cwd=$HOME/.config'), 340 | -- flybuf.nvim 341 | ['j'] = cmd('FlyBuf'), 342 | --gitsign 343 | [']g'] = cmd('lua require"gitsigns".next_hunk()'), 344 | ['[g'] = cmd('lua require"gitsigns".prev_hunk()'), 345 | }) 346 | 347 | map.n('', cmd('Dired')) 348 | 349 | -- Lspsaga floaterminal 350 | map.nt('', cmd('Lspsaga term_toggle')) 351 | 352 | map.nx('ga', cmd('Lspsaga code_action')) 353 | 354 | map.n('f', function() 355 | require('private.jump').charForward() 356 | end) 357 | 358 | map.n('F', function() 359 | require('private.jump').charBackward() 360 | end) 361 | -------------------------------------------------------------------------------- /lua/private/pairs.lua: -------------------------------------------------------------------------------- 1 | local api = vim.api 2 | 3 | -- Class for managing bracket pairs 4 | local BracketPair = {} 5 | BracketPair.__index = BracketPair 6 | 7 | function BracketPair.new() 8 | local self = setmetatable({}, BracketPair) 9 | self.pairs = { 10 | ['('] = ')', 11 | ['['] = ']', 12 | ['{'] = '}', 13 | ['"'] = '"', 14 | ["'"] = "'", 15 | ['`'] = '`', 16 | } 17 | -- Extend with any user-defined pairs 18 | self.pairs = vim.tbl_extend('keep', self.pairs, vim.g.fnpairs or {}) 19 | return self 20 | end 21 | 22 | function BracketPair:get_closing(opening) 23 | return self.pairs[opening] 24 | end 25 | 26 | function BracketPair:is_opening(char) 27 | return self.pairs[char] ~= nil 28 | end 29 | 30 | function BracketPair:is_balanced(str, opening_char) 31 | local stack = {} 32 | for i = 1, #str do 33 | local c = str:sub(i, i) 34 | if self.pairs[c] then 35 | table.insert(stack, c) 36 | elseif c == self.pairs[opening_char] then 37 | if #stack == 0 or stack[#stack] ~= opening_char then 38 | return false 39 | end 40 | table.remove(stack) 41 | end 42 | end 43 | return true 44 | end 45 | 46 | -- Class for managing editor state 47 | local State = {} 48 | State.__index = State 49 | 50 | function State.new() 51 | local self = setmetatable({}, State) 52 | self.line = api.nvim_get_current_line() 53 | self.cursor = api.nvim_win_get_cursor(0) 54 | self.mode = api.nvim_get_mode().mode 55 | return self 56 | end 57 | 58 | function State:get_char_before() 59 | local pos = self.cursor[2] 60 | if pos > 0 then 61 | return self.line:sub(pos, pos) 62 | end 63 | return nil 64 | end 65 | 66 | function State:get_char_after() 67 | local pos = self.cursor[2] + 1 68 | if pos <= #self.line then 69 | return self.line:sub(pos, pos) 70 | end 71 | return nil 72 | end 73 | 74 | -- Action classes 75 | local ActionType = { 76 | SKIP = 'skip', 77 | INSERT = 'insert', 78 | DELETE = 'delete', 79 | NOTHING = 'nothing', 80 | } 81 | 82 | local Action = {} 83 | Action.__index = Action 84 | 85 | function Action.skip() 86 | return setmetatable({ 87 | type = ActionType.SKIP, 88 | }, Action) 89 | end 90 | 91 | function Action.insert(opening, closing) 92 | return setmetatable({ 93 | type = ActionType.INSERT, 94 | opening = opening, 95 | closing = closing, 96 | }, Action) 97 | end 98 | 99 | function Action.delete() 100 | return setmetatable({ 101 | type = ActionType.DELETE, 102 | }, Action) 103 | end 104 | 105 | function Action.nothing() 106 | return setmetatable({ 107 | type = ActionType.NOTHING, 108 | }, Action) 109 | end 110 | 111 | -- Action handler 112 | local ActionHandler = {} 113 | 114 | function ActionHandler.handle(action, state, bracket_pairs) 115 | if action.type == ActionType.SKIP then 116 | return '' 117 | elseif action.type == ActionType.INSERT then 118 | return action.opening .. action.closing .. '' 119 | elseif action.type == ActionType.DELETE then 120 | local before = state:get_char_before() 121 | local after = state:get_char_after() 122 | if before and after and bracket_pairs:get_closing(before) == after then 123 | return '' 124 | end 125 | return '' 126 | else -- NOTHING 127 | return '' 128 | end 129 | end 130 | 131 | -- Main plugin class 132 | local Pairs = {} 133 | Pairs.__index = Pairs 134 | 135 | function Pairs.new() 136 | local self = setmetatable({}, Pairs) 137 | self.bracket_pairs = BracketPair.new() 138 | return self 139 | end 140 | 141 | function Pairs:determine_action(char, state) 142 | -- Handle visual mode 143 | if state.mode == 'v' or state.mode == 'V' then 144 | return Action.insert(char, self.bracket_pairs:get_closing(char)) 145 | end 146 | 147 | -- Check if we should skip closing bracket 148 | local next_char = state:get_char_after() 149 | if next_char and next_char == self.bracket_pairs:get_closing(char) then 150 | -- Check bracket balance 151 | local substr = state.line:sub(state.cursor[2] + 1) 152 | if self.bracket_pairs:is_balanced(substr, char) then 153 | return Action.skip() 154 | end 155 | end 156 | 157 | return Action.insert(char, self.bracket_pairs:get_closing(char)) 158 | end 159 | 160 | function Pairs:handle_char(char) 161 | local state = State.new() 162 | local action = self:determine_action(char, state) 163 | return ActionHandler.handle(action, state, self.bracket_pairs) 164 | end 165 | 166 | function Pairs:handle_backspace() 167 | local state = State.new() 168 | return ActionHandler.handle(Action.delete(), state, self.bracket_pairs) 169 | end 170 | 171 | function Pairs:setup() 172 | -- Store reference to self to avoid closure issues 173 | local plugin = self 174 | 175 | -- Setup bracket pairs 176 | for opening, _ in pairs(self.bracket_pairs.pairs) do 177 | vim.keymap.set('i', opening, function() 178 | return plugin:handle_char(opening) 179 | end, { expr = true }) 180 | end 181 | 182 | -- Setup backspace handling 183 | vim.keymap.set('i', '', function() 184 | return plugin:handle_backspace() 185 | end, { expr = true }) 186 | end 187 | 188 | Pairs.new():setup() 189 | -------------------------------------------------------------------------------- /plugin/async.lua: -------------------------------------------------------------------------------- 1 | -- Result type to handle errors properly 2 | local Result = {} 3 | Result.__index = Result 4 | 5 | function Result.success(value) 6 | return setmetatable({ success = true, value = value, error = nil }, Result) 7 | end 8 | 9 | function Result.failure(err) 10 | return setmetatable({ success = false, value = nil, error = err }, Result) 11 | end 12 | 13 | -- Wrap a function to return a promise 14 | function _G.awrap(func) 15 | return function(...) 16 | local args = { ... } 17 | return function(callback) 18 | local function handle_result(...) 19 | local results = { ... } 20 | if #results == 0 then 21 | -- No results 22 | callback(Result.success(nil)) 23 | elseif #results == 1 then 24 | -- Single result 25 | callback(Result.success(results[1])) 26 | else 27 | -- Multiple results 28 | callback(Result.success(results)) 29 | end 30 | end 31 | 32 | -- Handle any errors in the wrapped function 33 | local status, err = pcall(function() 34 | table.insert(args, handle_result) 35 | func(unpack(args)) 36 | end) 37 | 38 | if not status then 39 | callback(Result.failure(err)) 40 | end 41 | end 42 | end 43 | end 44 | 45 | -- Wrap vim.system to provide better error handling and cleaner usage 46 | function _G.asystem(cmd, opts) 47 | opts = opts or {} 48 | return function(callback) 49 | local progress_data = {} 50 | local error_data = {} 51 | local stderr_callback = opts.stderr 52 | 53 | -- Setup options 54 | local system_opts = vim.deepcopy(opts) 55 | 56 | -- Capture stderr for progress if requested 57 | if stderr_callback then 58 | system_opts.stderr = function(_, data) 59 | if data then 60 | table.insert(error_data, data) 61 | stderr_callback(_, data) 62 | end 63 | end 64 | end 65 | 66 | -- Call vim.system with proper error handling 67 | vim.system(cmd, system_opts, function(obj) 68 | -- Success is 0 exit code 69 | local success = obj.code == 0 70 | 71 | if success then 72 | callback(Result.success({ 73 | stdout = obj.stdout, 74 | stderr = obj.stderr, 75 | code = obj.code, 76 | signal = obj.signal, 77 | progress = progress_data, 78 | })) 79 | else 80 | callback(Result.failure({ 81 | message = 'Command failed with exit code: ' .. obj.code, 82 | stdout = obj.stdout, 83 | stderr = obj.stderr, 84 | code = obj.code, 85 | signal = obj.signal, 86 | progress = progress_data, 87 | })) 88 | end 89 | end) 90 | end 91 | end 92 | 93 | -- Await a promise - execution is paused until promise resolves 94 | function _G.await(promise) 95 | local co = coroutine.running() 96 | if not co then 97 | error('Cannot await outside of an async function') 98 | end 99 | 100 | promise(function(result) 101 | vim.schedule(function() 102 | local ok = coroutine.resume(co, result) 103 | if not ok then 104 | vim.notify(debug.traceback(co), vim.log.levels.ERROR) 105 | end 106 | end) 107 | end) 108 | 109 | local result = coroutine.yield() 110 | 111 | -- Propagate errors by throwing them 112 | if not result.success then 113 | error(result.error) 114 | end 115 | 116 | return result.value 117 | end 118 | 119 | -- Safely await a promise, returning a result instead of throwing 120 | function _G.try_await(promise) 121 | local co = coroutine.running() 122 | if not co then 123 | error('Cannot await outside of an async function') 124 | end 125 | 126 | promise(function(result) 127 | vim.schedule(function() 128 | local ok = coroutine.resume(co, result) 129 | if not ok then 130 | vim.notify(debug.traceback(co), vim.log.levels.ERROR) 131 | end 132 | end) 133 | end) 134 | 135 | return coroutine.yield() 136 | end 137 | 138 | -- Create an async function that can use await 139 | function _G.async(func) 140 | return function(...) 141 | local args = { ... } 142 | local co = coroutine.create(function() 143 | local status, result = pcall(function() 144 | return func(unpack(args)) 145 | end) 146 | 147 | if not status then 148 | vim.schedule(function() 149 | vim.notify('Async error: ' .. tostring(result), vim.log.levels.ERROR) 150 | end) 151 | end 152 | 153 | return status and result or nil 154 | end) 155 | 156 | local function step(...) 157 | local ok, err = coroutine.resume(co, ...) 158 | if not ok then 159 | vim.schedule(function() 160 | vim.notify('Coroutine error: ' .. debug.traceback(co, err), vim.log.levels.ERROR) 161 | end) 162 | end 163 | end 164 | 165 | step() 166 | end 167 | end 168 | -------------------------------------------------------------------------------- /plugin/completion.lua: -------------------------------------------------------------------------------- 1 | local api = vim.api 2 | local au = api.nvim_create_autocmd 3 | local g = api.nvim_create_augroup('glepnir.completion', { clear = true }) 4 | 5 | au('LspAttach', { 6 | group = g, 7 | callback = function(args) 8 | local lsp = vim.lsp 9 | local completion = lsp.completion 10 | local ms = lsp.protocol.Methods 11 | 12 | local bufnr = args.buf 13 | local client = lsp.get_client_by_id(args.data.client_id) 14 | if not client or not client:supports_method(ms.textDocument_completion) then 15 | return 16 | end 17 | 18 | if not vim.env.DEBUG_COMPLETION then 19 | local chars = client.server_capabilities.completionProvider.triggerCharacters 20 | if chars then 21 | for i = string.byte('a'), string.byte('z') do 22 | if not vim.list_contains(chars, string.char(i)) then 23 | table.insert(chars, string.char(i)) 24 | end 25 | end 26 | 27 | for i = string.byte('A'), string.byte('Z') do 28 | if not vim.list_contains(chars, string.char(i)) then 29 | table.insert(chars, string.char(i)) 30 | end 31 | end 32 | end 33 | end 34 | 35 | completion.enable(true, client.id, bufnr, { 36 | -- autotrigger = not vim.env.DEBUG_COMPLETION and true or { any = true }, 37 | autotrigger = true, 38 | convert = function(item) 39 | local kind = lsp.protocol.CompletionItemKind[item.kind] or 'u' 40 | return { 41 | abbr = item.label:gsub('%b()', ''), 42 | kind = kind:sub(1, 1):lower(), 43 | menu = '', 44 | } 45 | end, 46 | }) 47 | 48 | if 49 | #api.nvim_get_autocmds({ 50 | buffer = bufnr, 51 | event = { 'CompleteChanged' }, 52 | group = g, 53 | }) == 0 54 | then 55 | au('CompleteChanged', { 56 | buffer = bufnr, 57 | group = g, 58 | callback = function() 59 | local info = vim.fn.complete_info({ 'selected' }) 60 | if info.preview_bufnr and vim.bo[info.preview_bufnr].filetype == '' then 61 | vim.bo[info.preview_bufnr].filetype = 'markdown' 62 | vim.wo[info.preview_winid].conceallevel = 2 63 | vim.wo[info.preview_winid].concealcursor = 'niv' 64 | end 65 | end, 66 | }) 67 | end 68 | end, 69 | }) 70 | -------------------------------------------------------------------------------- /plugin/events.lua: -------------------------------------------------------------------------------- 1 | local api = vim.api 2 | local au = api.nvim_create_autocmd 3 | local group = api.nvim_create_augroup('GlepnirGroup', {}) 4 | 5 | au('TextYankPost', { 6 | group = group, 7 | callback = function() 8 | vim.highlight.on_yank({ higroup = 'IncSearch', timeout = 400 }) 9 | end, 10 | }) 11 | 12 | au('ExitPre', { 13 | group = group, 14 | callback = function() 15 | if vim.env.TERM == 'alacritty' then 16 | vim.o.guicursor = 'a:ver90' 17 | end 18 | end, 19 | desc = 'Set cursor back to beam when leaving Neovim.', 20 | }) 21 | 22 | --disable diagnostic in neovim test file *_spec.lua 23 | au('FileType', { 24 | group = group, 25 | pattern = 'lua', 26 | callback = function(opt) 27 | local fname = vim.api.nvim_buf_get_name(opt.buf) 28 | if fname:find('%w_spec%.lua') then 29 | vim.diagnostic.enable(not vim.diagnostic.is_enabled({ bufnr = opt.buf })) 30 | end 31 | end, 32 | }) 33 | 34 | au('TermOpen', { 35 | group = group, 36 | command = 'setl stc= nonumber | startinsert!', 37 | }) 38 | 39 | au('LspAttach', { 40 | group = group, 41 | callback = function(args) 42 | local client = vim.lsp.get_client_by_id(args.data.client_id) 43 | if vim.bo[args.buf].filetype == 'lua' and api.nvim_buf_get_name(args.buf):find('_spec') then 44 | vim.diagnostic.enable(false, { bufnr = args.buf }) 45 | end 46 | if client and client:supports_method('textDocument/documentColor') then 47 | vim.lsp.document_color.enable(true, args.buf) 48 | end 49 | 50 | if client then 51 | client.server_capabilities.semanticTokensProvider = nil 52 | end 53 | end, 54 | }) 55 | 56 | au('VimEnter', { 57 | callback = function() 58 | vim.fn.setreg('"0', '') 59 | end, 60 | }) 61 | 62 | au('InsertLeave', { 63 | group = group, 64 | callback = function() 65 | if vim.fn.executable('iswitch') == 0 then 66 | return 67 | end 68 | 69 | vim.system({ 'iswitch', '-s', 'com.apple.keylayout.ABC' }, nil, function(proc) 70 | if proc.code ~= 0 then 71 | vim.notify('Failed to switch input source: ' .. proc.stderr, vim.log.levels.WARN) 72 | end 73 | end) 74 | end, 75 | desc = 'auto switch to abc input', 76 | }) 77 | 78 | au('InsertEnter', { 79 | group = group, 80 | once = true, 81 | callback = function() 82 | require('private.pairs') 83 | end, 84 | desc = 'auto pairs', 85 | }) 86 | 87 | au('CmdlineEnter', { 88 | group = group, 89 | once = true, 90 | callback = function() 91 | if vim.version().minor >= 12 then 92 | require('vim._extui').enable({}) 93 | end 94 | end, 95 | }) 96 | 97 | au('UIEnter', { 98 | group = group, 99 | once = true, 100 | callback = function() 101 | vim.schedule(function() 102 | require('private.dashboard').show() 103 | require('private.keymap') 104 | 105 | vim.lsp.enable({ 106 | 'luals', 107 | 'clangd', 108 | 'rust_analyzer', 109 | 'basedpyright', 110 | 'ruff', 111 | 'zls', 112 | 'cmake', 113 | 'tsls', 114 | }) 115 | 116 | vim.lsp.log.set_level(vim.log.levels.OFF) 117 | 118 | vim.diagnostic.config({ 119 | virtual_text = { current_line = true }, 120 | signs = { 121 | text = { '●', '●', '●', '●' }, 122 | numhl = { 123 | 'DiagnosticError', 124 | 'DiagnosticWarn', 125 | 'DiagnosticInfo', 126 | 'DiagnosticHint', 127 | }, 128 | }, 129 | }) 130 | 131 | api.nvim_create_user_command('LspLog', function() 132 | vim.cmd(string.format('tabnew %s', vim.lsp.get_log_path())) 133 | end, { 134 | desc = 'Opens the Nvim LSP client log.', 135 | }) 136 | 137 | api.nvim_create_user_command('LspDebug', function() 138 | vim.lsp.log.set_level(vim.log.levels.WARN) 139 | end, { desc = 'enable lsp log' }) 140 | 141 | require('private.grep') 142 | 143 | vim.cmd.packadd('nohlsearch') 144 | end) 145 | end, 146 | desc = 'Initializer', 147 | }) 148 | 149 | au('FileType', { 150 | pattern = vim.g.language, 151 | callback = function() 152 | vim.treesitter.start() 153 | vim.wo.foldmethod = 'expr' 154 | vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()' 155 | -- vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" 156 | end, 157 | }) 158 | -------------------------------------------------------------------------------- /plugin/package.lua: -------------------------------------------------------------------------------- 1 | local uv, fs = vim.uv, vim.fs 2 | local strive_path = fs.joinpath(vim.fn.stdpath('data'), 'strive.nvim', 'strive') 3 | vim.g.strive_dev_path = '/Users/mw/workspace' 4 | 5 | local installed = (uv.fs_stat(strive_path) or {}).type == 'directory' 6 | async(function() 7 | if not installed then 8 | local result = 9 | try_await(asystem({ 'git', 'clone', 'https://github.com/nvimdev/strive', strive_path }, { 10 | timeout = 5000, 11 | stderr = function(_, data) 12 | if data then 13 | vim.schedule(function() 14 | vim.notify(data, vim.log.levels.INFO) 15 | end) 16 | end 17 | end, 18 | })) 19 | 20 | if not result.success then 21 | return vim.notify('Failed install strive', vim.log.levels.ERROR) 22 | end 23 | vim.notify('Strive installed success', vim.log.levels.INFO) 24 | end 25 | 26 | vim.o.rtp = strive_path .. ',' .. vim.o.rtp 27 | local use = require('strive').use 28 | 29 | use('nvimdev/modeline.nvim'):on({ 'BufEnter */*', 'BufNewFile' }):setup() 30 | use('lewis6991/gitsigns.nvim'):on({ 'BufEnter */*', 'BufNewFile' }):setup({ 31 | signs = { 32 | add = { text = '┃' }, 33 | change = { text = '┃' }, 34 | delete = { text = '_' }, 35 | topdelete = { text = '‾' }, 36 | changedelete = { text = '~' }, 37 | untracked = { text = '┃' }, 38 | }, 39 | }) 40 | use('nvimdev/dired.nvim'):cmd('Dired') 41 | use('nvimdev/indentmini.nvim') 42 | :on('BufEnter */*') 43 | :init(function() 44 | vim.opt.listchars:append({ tab = ' ' }) 45 | end) 46 | :setup({ 47 | only_current = true, 48 | }) 49 | :load_path() 50 | 51 | use('nvimdev/guard.nvim') 52 | :on('BufReadPost') 53 | :config(function() 54 | local ft = require('guard.filetype') 55 | ft('c,cpp'):fmt({ 56 | cmd = 'clang-format', 57 | stdin = true, 58 | ignore_patterns = { 'neovim', 'vim' }, 59 | }) 60 | 61 | ft('lua'):fmt({ 62 | cmd = 'stylua', 63 | args = { '-' }, 64 | stdin = true, 65 | ignore_patterns = 'function.*_spec%.lua', 66 | find = '.stylua.toml', 67 | }) 68 | ft('rust'):fmt('rustfmt') 69 | ft('typescript', 'javascript', 'typescriptreact', 'javascriptreact'):fmt('prettier') 70 | end) 71 | :depends('nvimdev/guard-collection') 72 | :load_path() 73 | 74 | use('nvimdev/dbsession.nvim'):cmd({ 'SessionSave', 'SessionLoad', 'SessionDelete' }) 75 | 76 | use('ibhagwan/fzf-lua'):cmd('FzfLua'):setup({ 77 | 'max-perf', 78 | lsp = { symbols = { symbol_style = 3 } }, 79 | }) 80 | 81 | use('nvim-treesitter/nvim-treesitter'):on('BufReadPre'):branch('main'):run(function() 82 | require('nvim-treesitter').install(vim.g.language) 83 | end) 84 | 85 | use('nvim-treesitter/nvim-treesitter-textobjects') 86 | :on('BufReadPost') 87 | :branch('main') 88 | :setup({ 89 | select = { 90 | -- Automatically jump forward to textobj, similar to targets.vim 91 | lookahead = true, 92 | selection_modes = { 93 | ['@parameter.outer'] = 'v', -- charwise 94 | ['@function.outer'] = 'V', -- linewise 95 | ['@class.outer'] = '', -- blockwise 96 | }, 97 | include_surrounding_whitespace = false, 98 | }, 99 | }) 100 | :config(function() 101 | vim.keymap.set({ 'x', 'o' }, 'af', function() 102 | require('nvim-treesitter-textobjects.select').select_textobject( 103 | '@function.outer', 104 | 'textobjects' 105 | ) 106 | end) 107 | vim.keymap.set({ 'x', 'o' }, 'if', function() 108 | require('nvim-treesitter-textobjects.select').select_textobject( 109 | '@function.inner', 110 | 'textobjects' 111 | ) 112 | end) 113 | vim.keymap.set({ 'x', 'o' }, 'ac', function() 114 | require('nvim-treesitter-textobjects.select').select_textobject( 115 | '@class.outer', 116 | 'textobjects' 117 | ) 118 | end) 119 | vim.keymap.set({ 'x', 'o' }, 'ic', function() 120 | require('nvim-treesitter-textobjects.select').select_textobject( 121 | '@class.inner', 122 | 'textobjects' 123 | ) 124 | end) 125 | vim.keymap.set({ 'x', 'o' }, 'as', function() 126 | require('nvim-treesitter-textobjects.select').select_textobject('@local.scope', 'locals') 127 | end) 128 | end) 129 | 130 | use('nvimdev/phoenix.nvim'):ft(vim.g.language) 131 | 132 | use('nvimdev/lspsaga.nvim') 133 | :on('LspAttach') 134 | :setup({ 135 | ui = { use_nerd = false }, 136 | symbol_in_winbar = { 137 | enable = false, 138 | }, 139 | lightbulb = { 140 | enable = false, 141 | }, 142 | outline = { 143 | layout = 'float', 144 | }, 145 | }) 146 | :load_path() 147 | end)() 148 | -------------------------------------------------------------------------------- /snippets/go.json: -------------------------------------------------------------------------------- 1 | { 2 | "single constant": { 3 | "prefix": "co", 4 | "body": "const ${1:name} = ${2:value}", 5 | "description": "Snippet for a constant" 6 | }, 7 | "variable declaration": { 8 | "prefix": "var", 9 | "body": "var ${1:name} ${2:type}", 10 | "description": "Snippet for a variable" 11 | }, 12 | "type interface declaration": { 13 | "prefix": "tyi", 14 | "body": "type ${1:name} interface {\n\t$0\n}", 15 | "description": "Snippet for a type interface" 16 | }, 17 | "main": { 18 | "prefix": "main", 19 | "body": ["func main() {", "\t$0", "}"], 20 | "description": "main function" 21 | }, 22 | "struct": { 23 | "prefix": "st", 24 | "body": ["type ${1} struct {", "\t${2}", "}"], 25 | "description": "struct" 26 | }, 27 | "func": { 28 | "prefix": "fn", 29 | "body": ["func ${1}() ${2} {", "\t${3}", "}"], 30 | "description": "function" 31 | }, 32 | "method declaration": { 33 | "prefix": "meth", 34 | "body": "func (${1:receiver} ${2:type}) ${3:method}($4) $5 {\n\t$0\n}", 35 | "description": "Snippet for method declaration" 36 | }, 37 | "if statement": { 38 | "prefix": "if", 39 | "body": "if ${1:condition} {\n\t$0\n}", 40 | "description": "Snippet for if statement" 41 | }, 42 | "else branch": { 43 | "prefix": "el", 44 | "body": "else {\n\t$0\n}", 45 | "description": "Snippet for else branch" 46 | }, 47 | "if else statement": { 48 | "prefix": "ie", 49 | "body": "if ${1:condition} {\n\t$2\n} else {\n\t$0\n}", 50 | "description": "Snippet for if else" 51 | }, 52 | "if err != nil": { 53 | "prefix": "iferr", 54 | "body": "if err != nil {\n\t${1:return ${2:nil, }${3:err}}\n}", 55 | "description": "Snippet for if err != nil" 56 | }, 57 | "switch statement": { 58 | "prefix": "switch", 59 | "body": "switch ${1:expression} {\ncase ${2:condition}:\n\t$0\n}", 60 | "description": "Snippet for switch statement" 61 | }, 62 | "select statement": { 63 | "prefix": "sel", 64 | "body": "select {\ncase ${1:condition}:\n\t$0\n}", 65 | "description": "Snippet for select statement" 66 | }, 67 | "case clause": { 68 | "prefix": "cs", 69 | "body": "case ${1:condition}:$0", 70 | "description": "Snippet for case clause" 71 | }, 72 | "for statement": { 73 | "prefix": "for", 74 | "body": "for ${1:i} := 0; $1 < ${2:count}; $1${3:++} {\n\t$0\n}", 75 | "description": "Snippet for a for loop" 76 | }, 77 | "for range statement": { 78 | "prefix": "forr", 79 | "body": "for ${1:_, }${2:var} := range ${3:var} {\n\t$0\n}", 80 | "description": "Snippet for a for range loop" 81 | }, 82 | "map declaration": { 83 | "prefix": "map", 84 | "body": "map[${1:type}]${2:type}", 85 | "description": "Snippet for a map" 86 | }, 87 | "goroutine anonymous function": { 88 | "prefix": "go", 89 | "body": "go func($1) {\n\t$0\n}($2)", 90 | "description": "Snippet for anonymous goroutine declaration" 91 | }, 92 | "goroutine function": { 93 | "prefix": "gf", 94 | "body": "go ${1:func}($0)", 95 | "description": "Snippet for goroutine declaration" 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /snippets/javascriptreact.json: -------------------------------------------------------------------------------- 1 | { 2 | "Import React": { 3 | "prefix": "imr", 4 | "body": ["import * as React from 'react';\n"], 5 | "description": "Import React" 6 | }, 7 | 8 | "Import React and Component": { 9 | "prefix": "imrc", 10 | "body": [ 11 | "import * as React from 'react';", 12 | "import { Component } from 'react';\n" 13 | ], 14 | "description": "Import React, { Component }" 15 | }, 16 | 17 | "Import ReactDOM": { 18 | "prefix": "imrd", 19 | "body": ["import ReactDOM from 'react-dom';"], 20 | "description": "Import ReactDOM" 21 | }, 22 | 23 | "Import React, { useState }": { 24 | "prefix": "imrs", 25 | "body": [ 26 | "import { useState } from 'react';\n" 27 | ], 28 | "description": "Import React, { useState }" 29 | }, 30 | 31 | "Import React, { useState, useEffect }": { 32 | "prefix": "imrse", 33 | "body": [ 34 | "import * as React from 'react';", 35 | "import { useState, useEffect } from 'react';\n" 36 | ], 37 | "description": "Import React, { useState, useEffect }" 38 | }, 39 | 40 | "Import Pure Component": { 41 | "prefix": "impc", 42 | "body": ["import React, { PureComponent } from 'react';\n"], 43 | "description": "Import React, { PureComponent }" 44 | }, 45 | 46 | "Class Component": { 47 | "prefix": "cc", 48 | "body": [ 49 | "interface $1Props {", 50 | "\t$2", 51 | "}", 52 | " ", 53 | "interface $1State {", 54 | "\t$3", 55 | "}", 56 | " ", 57 | "class $1 extends React.Component<$1Props, $1State> {", 58 | "\tstate = { $4: $5 }", 59 | "\trender() { ", 60 | "\t\treturn ( $0 );", 61 | "\t}", 62 | "}", 63 | " ", 64 | "export default $1;" 65 | ], 66 | "description": "Class Component" 67 | }, 68 | 69 | "Class Pure Component": { 70 | "prefix": "cpc", 71 | "body": [ 72 | "export interface $1Props {", 73 | "\t$2", 74 | "}", 75 | " ", 76 | "export interface $1State {", 77 | "\t$3", 78 | "}", 79 | " ", 80 | "class $1 extends React.PureComponent<$1Props, $1State> {", 81 | "\tstate = { $4: $5 }", 82 | "\trender() { ", 83 | "\t\treturn ( $0 );", 84 | "\t}", 85 | "}", 86 | " ", 87 | "export default $1;" 88 | ], 89 | "description": "Class Pure Component" 90 | }, 91 | 92 | "Class Component Constructor": { 93 | "prefix": "ccc", 94 | "body": [ 95 | "interface $1Props {", 96 | "\t$2", 97 | "}", 98 | " ", 99 | "interface $1State {", 100 | "\t$3", 101 | "}", 102 | " ", 103 | "class $1 extends React.Component<$1Props, $1State> {", 104 | "\tconstructor(props: $1Props) {", 105 | "\t\tsuper(props);", 106 | "\t\tthis.state = { $4: $5 };", 107 | "\t}", 108 | "\trender() { ", 109 | "\t\treturn ( $0 );", 110 | "\t}", 111 | "}", 112 | " ", 113 | "export default $1;" 114 | ], 115 | "description": "Class Component with Constructor" 116 | }, 117 | 118 | "Function Component": { 119 | "prefix": "fc", 120 | "body": [ 121 | "interface $1Props {", 122 | "\t$2", 123 | "}", 124 | " ", 125 | "const $1: FunctionComponent<$1Props> = ($3) => {", 126 | "\treturn ( $0 );", 127 | "}", 128 | " ", 129 | "export default $1;" 130 | ], 131 | "description": "Function Component" 132 | }, 133 | 134 | "Function Syntax Component": { 135 | "prefix": "ffc", 136 | "body": [ 137 | "function $1($2) {", 138 | "\treturn ( $0 );", 139 | "}", 140 | "", 141 | "export default $1;" 142 | ], 143 | "description": "Function Syntax Component" 144 | }, 145 | 146 | "Stateless Function Component": { 147 | "prefix": "sfc", 148 | "body": [ 149 | "const $1 = ($2) => {", 150 | "\treturn ( $0 );", 151 | "}", 152 | " ", 153 | "export default $1;" 154 | ], 155 | "description": "Stateless Function Component" 156 | }, 157 | 158 | "componentDidMount": { 159 | "prefix": "cdm", 160 | "body": ["componentDidMount() {", "\t$0", "}"], 161 | "description": "componentDidMount" 162 | }, 163 | 164 | "useEffect": { 165 | "prefix": "uef", 166 | "body": [ 167 | "useEffect(() => {", 168 | "\t$1", 169 | "}, []);" 170 | ], 171 | "description": "useEffect Hook" 172 | }, 173 | 174 | "componentWillMount": { 175 | "prefix": "cwm", 176 | "body": ["//WARNING! To be deprecated in React v17. Use componentDidMount instead.", "componentWillMount() {", "\t$0", "}"], 177 | "description": "componentWillMount" 178 | }, 179 | 180 | "componentWillReceiveProps": { 181 | "prefix": "cwrp", 182 | "body": ["//WARNING! To be deprecated in React v17. Use new lifecycle static getDerivedStateFromProps instead.", "componentWillReceiveProps(nextProps: $1Props) {", "\t$0", "}"], 183 | "description": "componentWillReceiveProps" 184 | }, 185 | 186 | "getDerivedStateFromProps": { 187 | "prefix": "gds", 188 | "body": ["static getDerivedStateFromProps(nextProps: $1Props, prevState: $1State) {", "\t$0", "}"], 189 | "description": "getDerivedStateFromProps" 190 | }, 191 | 192 | "shouldComponentUpdate": { 193 | "prefix": "scu", 194 | "body": ["shouldComponentUpdate(nextProps: $1Props, nextState: $1State) {", "\t$0", "}"], 195 | "description": "shouldComponentUpdate" 196 | }, 197 | 198 | "componentWillUpdate": { 199 | "prefix": "cwu", 200 | "body": ["//WARNING! To be deprecated in React v17. Use componentDidUpdate instead.", "componentWillUpdate(nextProps: $1Props, nextState: $1State) {", "\t$0", "}"], 201 | "description": "componentWillUpdate" 202 | }, 203 | 204 | "componentDidUpdate": { 205 | "prefix": "cdu", 206 | "body": ["componentDidUpdate(prevProps: $1Props, prevState: $1State) {", "\t$0", "}"], 207 | "description": "componentDidUpdate" 208 | }, 209 | 210 | "componentWillUnmount": { 211 | "prefix": "cwun", 212 | "body": ["componentWillUnmount() {", "\t$0", "}"], 213 | "description": "componentWillUnmount" 214 | }, 215 | 216 | "componentDidCatch": { 217 | "prefix": "cdc", 218 | "body": ["componentDidCatch(error, info) {", "\t$0", "}"], 219 | "description": "componentDidCatch" 220 | }, 221 | 222 | "getSnapshotBeforeUpdate": { 223 | "prefix": "gsbu", 224 | "body": ["getSnapshotBeforeUpdate(prevProps: $1Props, prevState: $1State) {", "\t$0", "}"], 225 | "description": "getSnapshotBeforeUpdate" 226 | }, 227 | 228 | "setState": { 229 | "prefix": "ss", 230 | "body": ["this.setState({ $1: $2 });"], 231 | "description": "setState" 232 | }, 233 | 234 | "Functional setState": { 235 | "prefix": "ssf", 236 | "body": ["this.setState(prevState => {", "\treturn { $1: prevState.$1 };", "});"], 237 | "description": "Functional setState" 238 | }, 239 | 240 | "Declare a new state variable using State Hook": { 241 | "prefix": "usf", 242 | "body": [ 243 | "const [${1}, set${1/(.*)/${1:/capitalize}/}] = useState($2);" 244 | ], 245 | "description": "Declare a new state Variable using the State Hook. Hit Tab to apply CamelCase to function" 246 | }, 247 | 248 | "render": { 249 | "prefix": "ren", 250 | "body": ["render() {", "\treturn (", "\t\t $0", "\t);", "}"], 251 | "description": "render" 252 | }, 253 | 254 | "Render Prop": { 255 | "prefix": "rprop", 256 | "body": [ 257 | "interface $1Props {", 258 | "\trender: (state: $1State) => JSX.Element", 259 | "}", 260 | " ", 261 | "interface $1State {", 262 | "\t$2", 263 | "}", 264 | " ", 265 | "class $1 extends React.Component<$1Props, $1State> {", 266 | "\tstate = { $3: $4 }", 267 | "\trender() { ", 268 | "\t\treturn this.props.render(this.state);", 269 | "\t}", 270 | "}", 271 | " ", 272 | "export default $1;" 273 | ], 274 | "description": "Render Prop" 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /snippets/rust.json: -------------------------------------------------------------------------------- 1 | { 2 | "extern crate": { 3 | "prefix": "extern crate", 4 | "body": ["extern crate ${1:name};"], 5 | "description": "Insert extern crate" 6 | }, 7 | "for": { 8 | "prefix": "for", 9 | "body": ["for ${1:elem} in ${2:iter} {", "\t$0", "}"], 10 | "description": "Insert for loop" 11 | }, 12 | "macro_rules": { 13 | "prefix": "macro_rules", 14 | "body": ["macro_rules! $1 {", "\t($2) => {", "\t\t$0", "\t};", "}"], 15 | "description": "Insert macro_rules!" 16 | }, 17 | "if let": { 18 | "prefix": "if let", 19 | "body": ["if let ${1:pattern} = ${2:value} {", "\t$3", "}"], 20 | "description": "Insert if to match a specific pattern, useful for enum variants e.g. `Some(inner)`" 21 | }, 22 | "spawn": { 23 | "prefix": ["thread_spawn", "spawn"], 24 | "body": ["std::thread::spawn(move || {", "\t$1", "})"], 25 | "description": "Wrap code in thread::spawn" 26 | }, 27 | "derive": { 28 | "prefix": "derive", 29 | "body": ["#[derive(${1})]"], 30 | "description": "#[derive(…)]" 31 | }, 32 | "cfg": { 33 | "prefix": "cfg", 34 | "body": ["#[cfg(${1})]"], 35 | "description": "#[cfg(…)]" 36 | }, 37 | "test": { 38 | "prefix": "test", 39 | "body": ["#[test]", "fn ${1:name}() {", " ${2:unimplemented!();}", "}"], 40 | "description": "#[test]" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /snippets/typescriptreact.json: -------------------------------------------------------------------------------- 1 | { 2 | "Import React": { 3 | "prefix": "imr", 4 | "body": ["import React from 'react';"], 5 | "description": "Imports React" 6 | }, 7 | "componentFunctionalTypescript": { 8 | "prefix": "rfc", 9 | "body": [ 10 | "import React from 'react';", 11 | "", 12 | "const ${1:${TM_DIRECTORY/^.*(\\/|\\\\)([^(\\/|\\\\)]+)$/$2/}}: React.FC = () => {", 13 | " return
;", 14 | "}", 15 | "", 16 | "export default ${1:${TM_DIRECTORY/^.*(\\/|\\\\)([^(\\/|\\\\)]+)$/$2/}};" 17 | ], 18 | "description": "Create ReactJS Functional Component Typescript" 19 | }, 20 | "Create useState hook": { 21 | "prefix": "useState", 22 | "body": [ 23 | "const [${1:state}, set${1:State}] = useState(${2:defaultState});" 24 | ], 25 | "description": "Creates React useState hook" 26 | }, 27 | "Create useEffect hook": { 28 | "prefix": "useEffect", 29 | "body": ["useEffect(() => {", "\t", "}, []);"], 30 | "description": "Creates React useEffect hook" 31 | }, 32 | "Create useContext hook": { 33 | "prefix": "useContext", 34 | "body": ["const ${1:value} = useContext(MyContext);"], 35 | "description": "Creates React useContext hook" 36 | }, 37 | "Create useReducer hook": { 38 | "prefix": "useReducer", 39 | "body": [ 40 | "const [${1:state}, dispatch] = useReducer(${2:reducer}, initialState);" 41 | ], 42 | "description": "Creates React useReducer hook" 43 | }, 44 | "Create useCallback hook": { 45 | "prefix": "useCallback", 46 | "body": [ 47 | "const ${1:memoizedCallback} = useCallback(() => {", 48 | "\t", 49 | "}, []);" 50 | ], 51 | "description": "Creates React useCallback hook" 52 | }, 53 | "Create useMemo hook": { 54 | "prefix": "useMemo", 55 | "body": ["const ${1:memoizedValue} = useMemo(() => {", "\t", "}, []);"], 56 | "description": "Creates React useMemo hook" 57 | }, 58 | "Create useRef hook": { 59 | "prefix": "useRef", 60 | "body": ["const ${1:refContainer} = useRef(${2:initialValue});"], 61 | "description": "Creates React useRef hook" 62 | }, 63 | "Create useImperativeHandle hook": { 64 | "prefix": "useImperativeHandle", 65 | "body": ["useImperativeHandle(${1:initialValue}, () => {", "\t", "}, []);"], 66 | "description": "Creates React useImperativeHandle hook" 67 | }, 68 | "Create useLayoutEffect hook": { 69 | "prefix": "useLayoutEffect", 70 | "body": ["useLayoutEffect(() => {", "\t", "}, []);"], 71 | "description": "Creates React useLayoutEffect hook" 72 | }, 73 | "Create useDebugValue hook": { 74 | "prefix": "useDebugValue", 75 | "body": ["useDebugValue(${1:value}"], 76 | "description": "Creates React useDebugValue hook" 77 | }, 78 | "Create useSelector hook": { 79 | "prefix": "useSelector", 80 | "body": [ 81 | "const ${1:selectedData} = useSelector(state => state.${2:YourObject});" 82 | ], 83 | "description": "Creates Redux useSelector hook" 84 | }, 85 | "Create useDispatch hook": { 86 | "prefix": "useDispatch", 87 | "body": ["const dispatch = useDispatch();"], 88 | "description": "Creates Redux useDispatch hook" 89 | }, 90 | "Create useStore hook": { 91 | "prefix": "useStore", 92 | "body": ["const store = useStore();"], 93 | "description": "Creates Redux useStore hook" 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /snippets/zig.json: -------------------------------------------------------------------------------- 1 | { 2 | "var": { 3 | "prefix": "var", 4 | "body": ["var ${1:name}: ${2:type} = ${3:value};$0"], 5 | "description": "var decl" 6 | }, 7 | "const": { 8 | "prefix": "const", 9 | "body": ["const ${1:name}: ${2:type} = ${3:value};$0"], 10 | "description": "const decl" 11 | }, 12 | "arr_init": { 13 | "prefix": "arr_init", 14 | "body": ["[_:${1:sentinel}]${1:type}{${2:val1}, ${3:val2}, ${4:val3}};$0"], 15 | "description": "array/sentinel init" 16 | }, 17 | "list": { 18 | "prefix": "list", 19 | "body": [".{${1:val1}, ${2:val2}, ${3:val3}};$0"], 20 | "description": "anonymous list" 21 | }, 22 | "fn": { 23 | "prefix": "fn", 24 | "body": ["fn ${1:name}() ${2:return_type} {", " $0", "}"], 25 | "description": "fn decl" 26 | }, 27 | "generic_fn": { 28 | "prefix": "fn_T", 29 | "body": [ 30 | "fn ${1:name}(comptime T: type) ${2:return_type} {", 31 | " $0", 32 | "}" 33 | ], 34 | "description": "generic fn decl" 35 | }, 36 | "pub_fn": { 37 | "prefix": "pub_fn", 38 | "body": ["pub fn ${1:main}() ${2:void} {", " $0", "}"], 39 | "description": "pub fn decl" 40 | }, 41 | "extern_fn": { 42 | "prefix": "ext_fn", 43 | "body": [ 44 | "extern \"${1:sourceName}\" stdcallcc fn ${2:name}() ${3:return_type};$0" 45 | ], 46 | "description": "extern fn" 47 | }, 48 | "exp_fn": { 49 | "prefix": "exp_fn", 50 | "body": ["export fn ${1:name}() ${2:return_type} {", " $0", "}"], 51 | "description": "export fn" 52 | }, 53 | "inl_fn": { 54 | "prefix": "inline", 55 | "body": ["inline fn ${1:name}() ${2:return_type} {", " $0", "}"], 56 | "description": "inline fn" 57 | }, 58 | "nakedcc_fn": { 59 | "prefix": "naked", 60 | "body": ["nakedcc fn _${1:name}() ${2:return_type} {", " $0", "}"], 61 | "description": "nakedcc fn" 62 | }, 63 | "block": { 64 | "prefix": "block", 65 | "body": [ 66 | "${1:label}: {", 67 | " const ${2:name} = ${3:value}", 68 | " break :${1:label} ${:return_value}$0", 69 | "};" 70 | ], 71 | "description": "block expr" 72 | }, 73 | "struct_val": { 74 | "prefix": "stru_val", 75 | "body": [ 76 | "struct {", 77 | " .${1:field}: ${2:type},", 78 | " .${3:field}: ${4:type},$0", 79 | "};" 80 | ], 81 | "description": "struct val" 82 | }, 83 | "struct_decl": { 84 | "prefix": "stru_decl", 85 | "body": [ 86 | "const ${1:StructName} = struct {", 87 | " ${2:field}: ${3:type},", 88 | " ${4:field}: ${5:type},$0", 89 | "};" 90 | ], 91 | "description": "struct decl" 92 | }, 93 | "enum": { 94 | "prefix": "enum", 95 | "body": [ 96 | "const ${1:EnumName} = enum(${2:type}) {", 97 | " ${3:variant} = ${4:count},", 98 | " ${5:variant} = ${6:count},$0", 99 | "};" 100 | ], 101 | "description": "enum decl" 102 | }, 103 | "union": { 104 | "prefix": "union", 105 | "body": [ 106 | "const ${1:UnionName} = union(${2:enum}) {", 107 | " ${3:variant} : ${4:type},", 108 | " ${5:variant} : ${6:type},$0", 109 | "};" 110 | ], 111 | "description": "tagged union decl" 112 | }, 113 | "for_val": { 114 | "prefix": "for_v", 115 | "body": ["for (${1:items}) |${2:value}| {", " $0", "}"], 116 | "description": "for value loop" 117 | }, 118 | "for_val_index": { 119 | "prefix": "for_v_i", 120 | "body": ["for (${1:items}) |${2:value},${3:index}| {", " $0", "}"], 121 | "description": "for value,index loop" 122 | }, 123 | "for_inline": { 124 | "prefix": "for_inline", 125 | "body": ["inline for (${1:items}) |${2:value}| {", " $0", "}"], 126 | "description": "inline for loop" 127 | }, 128 | "for_label": { 129 | "prefix": "for_l", 130 | "body": [ 131 | "${1:label}: for (${2:items}) |_| {", 132 | " for (${3:items2}) |_| {", 133 | " ${4|break,continue|} :${1:label};$0", 134 | " }", 135 | "}" 136 | ], 137 | "description": "labeled for loop" 138 | }, 139 | "for_else": { 140 | "prefix": "for_e", 141 | "body": [ 142 | "for (${1:items}) |${2:value}| {", 143 | " break true;$0", 144 | "} else false;" 145 | ], 146 | "description": "for else loop expr" 147 | }, 148 | "while": { 149 | "prefix": "while", 150 | "body": ["while (${1:cond}) : (${2:continue_expr}) {", " $0", "}"], 151 | "description": "while loop" 152 | }, 153 | "while_else": { 154 | "prefix": "while_e", 155 | "body": [ 156 | "while (${1:cond}) : (${2:continue_expr}) {", 157 | " break true;$0", 158 | "} else false;" 159 | ], 160 | "description": "while else loop expression" 161 | }, 162 | "while_opt": { 163 | "prefix": "while?", 164 | "body": [ 165 | "while (${1:nullable}) |${2:value}| {", 166 | " $0", 167 | "} else |err| {", 168 | " ", 169 | "}" 170 | ], 171 | "description": "while optional loop" 172 | }, 173 | "while_label": { 174 | "prefix": "while_l", 175 | "body": [ 176 | "${1:label}: while (${2:cond}) : (${3:continue_expr}) {", 177 | " while (${4:cond}) : (${5:continue_expr}) {", 178 | " ${6|break,continue|} :${1:label};$0", 179 | " }", 180 | "}" 181 | ], 182 | "description": "labeled while loop" 183 | }, 184 | "while_inline": { 185 | "prefix": "while_inline", 186 | "body": ["inline while (${1:cond}) (${2:continue_expr}) {", " $0", "}"], 187 | "description": "inline while loop" 188 | }, 189 | "if": { 190 | "prefix": "if", 191 | "body": ["if (${1:cond}) {", " $0", "}"], 192 | "description": "if expr" 193 | }, 194 | "if_else": { 195 | "prefix": "if_e", 196 | "body": ["if (${1:cond}) {", " $0", "} else {", " unreachable;", "}"], 197 | "description": "if else expr" 198 | }, 199 | "if_opt": { 200 | "prefix": "if?", 201 | "body": ["if (${1:nullable}) |value| {", " $0", "}"], 202 | "description": "if optional" 203 | }, 204 | "if_else_opt": { 205 | "prefix": "if_e?", 206 | "body": [ 207 | "if (${1:nullable}) |value| {", 208 | " $0", 209 | "} else |err| switch(err) {", 210 | " ${2:err_variants} => ${3:value},", 211 | " ${4:err_variants} => ${5:value},", 212 | " else => ${6:value},", 213 | "}" 214 | ], 215 | "description": "if else optional" 216 | }, 217 | "switch": { 218 | "prefix": "switch", 219 | "body": [ 220 | "switch (${1:value}) {", 221 | " ${2:values/range} => ${3:value},", 222 | " ${4:values/range} => ${5:value},", 223 | " else => ${6:value},", 224 | "};$0" 225 | ], 226 | "description": "switch expr" 227 | }, 228 | "test": { 229 | "prefix": "test", 230 | "body": ["test ${1:name} {", " const x = true", " assert(x)$0", "}"], 231 | "description": "test" 232 | }, 233 | "orelse": { 234 | "prefix": "orelse", 235 | "body": ["orelse return unreachable$0"], 236 | "description": "orelse expr" 237 | }, 238 | "defer": { 239 | "prefix": "def", 240 | "body": ["defer {", " $0", "}"], 241 | "description": "defer block" 242 | }, 243 | "errdefer": { 244 | "prefix": "errd", 245 | "body": ["errdefer {", " $0", "}"], 246 | "description": "errdefer block" 247 | }, 248 | "error": { 249 | "prefix": "error", 250 | "body": ["error {", " ${1:variant},", " ${2:variant},$0", "};"], 251 | "description": "error decl" 252 | }, 253 | "catch": { 254 | "prefix": "catch", 255 | "body": [" catch |${1:err}| {", " $0", "};"], 256 | "description": "catch error block" 257 | }, 258 | "comptime": { 259 | "prefix": "comp", 260 | "body": ["comptime {", " $0", "}"], 261 | "description": "comptime block" 262 | }, 263 | "asm": { 264 | "prefix": "asm", 265 | "body": ["asm ${1:volatile} (", " $0", ");"], 266 | "description": "asm block" 267 | }, 268 | "async_call": { 269 | "prefix": "async", 270 | "body": ["async ${1:fn_name}(${2:params})$0"], 271 | "description": "async fn call" 272 | }, 273 | "await": { 274 | "prefix": "await", 275 | "body": ["await ${1:anyframe->T}$0"], 276 | "description": "await frame" 277 | }, 278 | "suspend_block": { 279 | "prefix": "suspend", 280 | "body": ["suspend {", " $0", "}"], 281 | "description": "suspend block" 282 | }, 283 | "resume": { 284 | "prefix": "resume", 285 | "body": ["resume ${1:anyframe};$0"], 286 | "description": "resume frame" 287 | }, 288 | "free": { 289 | "prefix": "free", 290 | "body": ["${1:allocator}.free();$0"], 291 | "description": "allocator free" 292 | }, 293 | "@alignOf": { 294 | "prefix": "alignOf", 295 | "body": ["@alignOf(${1:type})$0"], 296 | "description": "align on specific type" 297 | }, 298 | "@as": { 299 | "prefix": "as", 300 | "body": ["@as(${1:cast_type}, ${2:value})$0"], 301 | "description": "cast value" 302 | }, 303 | "@frame": { 304 | "prefix": "frame", 305 | "body": ["@frame()$0"], 306 | "description": "switching frame" 307 | }, 308 | "@import": { 309 | "prefix": "imp", 310 | "body": ["@import(\"${1:dep_name}\");$0"], 311 | "description": "import dependency" 312 | }, 313 | "@import(std)": { 314 | "prefix": "imp_std", 315 | "body": [ 316 | "@import(\"std\").${1|ascii,atomic,base64,build,builtin,c,coff,crypto,cstr,debug,dwarf,elf,event,fifo,fmt,fs,hash,hash_map,heap,http,io,json,macho,math,mem,meta,net,os,packed_int_array,pdb,process,rand,rb,sort,start,testing,time,unicode,valgrind,zigg|};$0" 317 | ], 318 | "description": "import std namespace" 319 | }, 320 | "@typeOf": { 321 | "prefix": "typeOf", 322 | "body": ["@typeOf(${1:value})$0"], 323 | "description": "type of value" 324 | }, 325 | "@typeName": { 326 | "prefix": "typeName", 327 | "body": ["@typeName(@typeOf(value), value)$0"], 328 | "description": "type name of value" 329 | }, 330 | "@panic": { 331 | "prefix": "panic", 332 | "body": ["@panic(\"${1:message}\");$0"], 333 | "description": "panic" 334 | }, 335 | "@setCold": { 336 | "prefix": "setC", 337 | "body": ["@setCold(true);$0"], 338 | "description": "set rarely call info to optimizer" 339 | }, 340 | "@sizeOf": { 341 | "prefix": "sizeOf", 342 | "body": ["@sizeOf(${1:type})$0"], 343 | "description": "size of type" 344 | }, 345 | "@compileError": { 346 | "prefix": "compileErr", 347 | "body": ["@compileError(\"${1:message}\");$0"], 348 | "description": "compile error" 349 | }, 350 | "@compileLog": { 351 | "prefix": ["compileLog", "log"], 352 | "body": ["@compileError(\"${1:message}\");$0"], 353 | "description": "compile log" 354 | }, 355 | "@math.fn": { 356 | "prefix": "math", 357 | "body": [ 358 | "@${1|sqrt,sin,cos,exp,exp2,log,log2,log10,fabs,floor,ceil,trunc,round|}(\"${2:value}\");$0" 359 | ], 360 | "description": "math functions" 361 | }, 362 | "fnCast": { 363 | "prefix": "cast", 364 | "body": [ 365 | "@${1|alignCast,bitCast,errSetCast,floatCast,intCast,ptrCast,truncate|}(${2:value}, ${3:value})$0" 366 | ], 367 | "description": "fnCast function" 368 | }, 369 | "@opWithOverflow": { 370 | "prefix": ["addWith", "subWith", "mulWith", "overflow"], 371 | "body": [ 372 | "@${1|add,sub,mul,shl|}WithOverflow(${2:type}, ${3:op_1}, ${4:op_2}, ${5:result_pointer})$0" 373 | ], 374 | "description": "Algebraic/Shift operation with overflow check" 375 | }, 376 | "@bitCast": { 377 | "prefix": "bitCast", 378 | "body": ["@byteOffsetOf(${1:packed_type}, ${2:value})$0"], 379 | "description": "value to bit cast" 380 | }, 381 | "@bitOffsetOf": { 382 | "prefix": "bitOff", 383 | "body": ["@bitOffsetOf(${1:packed_type}, ${2:value})$0"], 384 | "description": "bit offset" 385 | }, 386 | "@byteOffsetOf": { 387 | "prefix": "byteOff", 388 | "body": ["@byteOffsetOf(${1:packed_type}, ${2:value})$0"], 389 | "description": "byte offset" 390 | }, 391 | "@bytesToSlice": { 392 | "prefix": "bytesToSlice", 393 | "body": ["@bytesToSlice(${1:packed_type}, ${2:slice})$0"], 394 | "description": "bytes to slice" 395 | }, 396 | "@memberCount": { 397 | "prefix": "memberC", 398 | "body": ["@memberCount(${1:enum_name})$0"], 399 | "description": "enum member count" 400 | }, 401 | "@memberName": { 402 | "prefix": "member_name", 403 | "body": ["@memberName(${1:enum_name}, ${2:variant_count})$0"], 404 | "description": "enum member name" 405 | }, 406 | "@tagName": { 407 | "prefix": "tagName", 408 | "body": ["@tagName(${1:variant}, ${2:variant_string})$0"], 409 | "description": "enum tag name" 410 | }, 411 | "@tagType": { 412 | "prefix": "tagType", 413 | "body": ["@tagType(${1:enum_name})$0"], 414 | "description": "enum tag's count type" 415 | }, 416 | "reflection.type_prop": { 417 | "prefix": "reflect.type_prop", 418 | "body": ["@typeOf(${1:value}).${2|Payload,ErrorSet,Child|}$0"], 419 | "description": "type property (Property,ErrorSet,...)" 420 | }, 421 | "@atomicLoad": { 422 | "prefix": "atomicLoad", 423 | "body": [ 424 | "@atomicLoad(${1:type}, ${2:const_ptr}, .${3|AcqRel,Acquire,Monotonic,Release,SecCst,Unordered|})$0" 425 | ], 426 | "description": "atomics: load ptr dereferenced value" 427 | }, 428 | "@atomicRmw": { 429 | "prefix": "atomicRmw", 430 | "body": [ 431 | "@atomicRmw(${1:type}, ${2:ptr}, .${3|Add,And,Max,Min,Nand,Or,Sub,Xchg,Xor|}, ${4:operand_type}, ${5:builtin.AtomicOrder})$0" 432 | ], 433 | "description": "atomics: modify memory and return prev value" 434 | }, 435 | "std.debug.warn": { 436 | "prefix": "warn", 437 | "body": ["${1:std.debug.}warn(\"${2:message} {}\\n\", .{${3:err}});$0"], 438 | "description": "std.debug.warn" 439 | }, 440 | "std.mem.eql": { 441 | "prefix": "mem.eql", 442 | "body": ["mem.eql(${1:type}, ${2:value}, ${3:value})$0"], 443 | "description": "std.mem.eql" 444 | }, 445 | "std.in/out": { 446 | "prefix": ["stdin", "stdout", "stderr"], 447 | "body": [ 448 | "std.io.${1|getStdOut().outStream(),getStdIn().inStream(),getStdErr()|}$0" 449 | ], 450 | "description": "std.io in/out/err" 451 | }, 452 | "std.debug.assert": { 453 | "prefix": "assert", 454 | "body": ["${1:std.debug.}assert(${2:cond});$0"], 455 | "description": "std.debug.assert" 456 | }, 457 | "std.testing.expect": { 458 | "prefix": "expect", 459 | "body": ["${1:std.testing.}expect(${2:cond});$0"], 460 | "description": "std.testing.expect" 461 | }, 462 | "std.heap.ArenaAllocator": { 463 | "prefix": ["arena", "alloc", "heap"], 464 | "body": [ 465 | "var ${1:arena_all_name} = std.heap.ArenaAllocator.init(std.heap.direct_allocator);", 466 | "defer ${1:arena_all_name}.deinit();", 467 | "const allocator = &${1:arena_all_name}.allocator;", 468 | "const ptr = try allocator.create(${1:type});$0" 469 | ], 470 | "description": "std.heap.ArenaAllocator" 471 | }, 472 | "main_template": { 473 | "prefix": ["main", "hello"], 474 | "body": [ 475 | "const std = @import(\"std\");", 476 | "", 477 | "pub fn main() !void {", 478 | " const stdout = &std.io.getStdOut().outStream();", 479 | " try stdout.print(\"Hello {}!\\n\", .{\"world\"});$0", 480 | "}" 481 | ], 482 | "description": "main/hello world" 483 | }, 484 | "builder_template": { 485 | "prefix": "builder_template", 486 | "body": [ 487 | "const Builder = @import(\"std\").build.Builder;", 488 | "", 489 | "pub fn build(b: *Builder) void {", 490 | " const exe = b.addExecutable(${example}, ${2:example}.zig);", 491 | " exe.setBuildMode(b.standardReleaseOptions());", 492 | " b.default_step.dependeOn(&exe.step);$0", 493 | "}" 494 | ], 495 | "description": "Default build.zig builder" 496 | }, 497 | "adt_template": { 498 | "prefix": "adt_template", 499 | "body": [ 500 | "const std = @import(\"std\");\n", 501 | "const ExprTag = enum {\n Num,\n Plus,\n};\n", 502 | "const Expr = union(ExprTag) {\n Num: i32,\n Plus: struct{ e1: *Expr, e2: *Expr},\n};", 503 | "fn eval(e: *const Expr) i32 {", 504 | " return switch (e.*) {", 505 | " .Num => |n| n,", 506 | " .Plus => |*plus_elem| eval(plus_elem.e1) + eval(plus_elem.e2),", 507 | " else => unreachable,\n };\n}", 508 | "pub fn main() !void {", 509 | " const stdout = &std.io.getStdOut().outStream();", 510 | " const e = &Expr{ .Plus = .{ .e1 = &Expr{ .Num = 6}, .e2 = &Expr{ .Num = 5}}};", 511 | " try stdout.print(\"Hello {}!\\n\", .{\"world\"});$0", 512 | "}" 513 | ], 514 | "description": "Algebraic Data Type" 515 | } 516 | } 517 | -------------------------------------------------------------------------------- /template/main_owner.c: -------------------------------------------------------------------------------- 1 | // Copyright {{_date_}} {{_author_}}. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | {{_cursor_}} 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /template/main_owner.cpp: -------------------------------------------------------------------------------- 1 | // Copyright {{_date_}} {{_author_}}. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | {{_cursor_}} 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /template/main_owner.go: -------------------------------------------------------------------------------- 1 | // Copyright {{_date_}} {{_author_}}. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | func main() { 8 | {{_cursor_}} 9 | } 10 | -------------------------------------------------------------------------------- /template/main_owner.rs: -------------------------------------------------------------------------------- 1 | // Copyright {{_date_}} {{_author_}}. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | fn main() {} 6 | -------------------------------------------------------------------------------- /template/nvim_temp.lua: -------------------------------------------------------------------------------- 1 | local api, fn = vim.api, vim.fn 2 | local {{_variable_}} = {} 3 | 4 | {{_cursor_}} 5 | 6 | return {{_variable_}} 7 | -------------------------------------------------------------------------------- /template/package_owner.go: -------------------------------------------------------------------------------- 1 | // Copyright {{_date_}} glepnir. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package {{_file_name_}} 6 | 7 | {{_cursor_}} 8 | --------------------------------------------------------------------------------