├── my_snippets ├── package.json ├── lua │ ├── all.lua │ ├── markdown.lua │ └── go.lua ├── snippets.snippets ├── sh.snippets └── go.snippets ├── lua ├── plugins │ ├── indent.lua │ ├── terminal.lua │ ├── rest.lua │ ├── icon.lua │ ├── game.lua │ ├── undo.lua │ ├── vsc.lua │ ├── motion.lua │ ├── wakatime.lua │ ├── txtobjs.lua │ ├── tmux.lua │ ├── session.lua │ ├── files.lua │ ├── profile.lua │ ├── colorscheme.lua │ ├── database.lua │ ├── test.lua │ ├── ui.lua │ ├── snippet.lua │ ├── edit_support.lua │ ├── note.lua │ ├── im_select.lua │ ├── debugging.lua │ ├── fold.lua │ ├── try.lua │ ├── lsp.lua │ ├── cmp.lua │ ├── treesitter.lua │ └── misc.lua ├── lib.lua ├── keyword.lua ├── keymap.lua ├── autocmd.lua ├── bookmarks.lua ├── lsp_config.lua └── dap_set.lua ├── .parrot.md ├── .gitignore ├── .gitmodules ├── Makefile ├── .luarc.json ├── macros.json ├── .github └── workflows │ └── docker-image.yml ├── AGENTS.md ├── Dockerfile ├── init.lua ├── lazy-lock.json ├── .vimrc └── README.md /my_snippets/package.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lua/plugins/indent.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /lua/plugins/terminal.lua: -------------------------------------------------------------------------------- 1 | return {} 2 | -------------------------------------------------------------------------------- /lua/plugins/rest.lua: -------------------------------------------------------------------------------- 1 | return { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /.parrot.md: -------------------------------------------------------------------------------- 1 | Additional context is provided below. 2 | 3 | -------------------------------------------------------------------------------- /lua/plugins/icon.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { "nvim-tree/nvim-web-devicons", event = "VeryLazy" }, 3 | } 4 | -------------------------------------------------------------------------------- /lua/plugins/game.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "ThePrimeagen/vim-be-good", 4 | cmd = "VimBeGood", 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /lua/plugins/undo.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | cmd = { "UndotreeToggle" }, 4 | "mbbill/undotree", 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /my_snippets/lua/all.lua: -------------------------------------------------------------------------------- 1 | local ls = require("luasnip") 2 | local s = ls.s 3 | local fmt = require("luasnip.extras.fmt").fmt 4 | -------------------------------------------------------------------------------- /lua/plugins/vsc.lua: -------------------------------------------------------------------------------- 1 | return { 2 | --- more stable than gitsign.nvim 3 | { "airblade/vim-gitgutter" }, 4 | 5 | { 6 | "tpope/vim-fugitive", 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /my_snippets/snippets.snippets: -------------------------------------------------------------------------------- 1 | snippet snip 2 | snippet ${1:trigger} "${2:description}" 3 | ${0:${VISUAL}} 4 | snippet v 5 | {VISUAL} 6 | snippet $ 7 | ${${1:1}:${0:text}} 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Session.vim 2 | spell/* 3 | spell/en.utf-8.add 4 | spell/en.utf-8.spl 5 | sessions/* 6 | lua/secret.lua 7 | messages.txt 8 | macros.json.tmp 9 | bd.lua 10 | snacks.nvim 11 | -------------------------------------------------------------------------------- /lua/plugins/motion.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "jinh0/eyeliner.nvim", 4 | keys = { "f", "t" }, 5 | config = function() 6 | require("eyeliner").setup({ 7 | highlight_on_key = true, 8 | dim = true, 9 | }) 10 | end, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /lua/plugins/wakatime.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | enabled = function() 4 | -- local file = vim.fn["expand"]("~/.wakatime.cfg") 5 | -- return vim.fn["filereadable"](file) == 1 6 | return false 7 | end, 8 | "wakatime/vim-wakatime", 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pack/airblade/start"] 2 | path = pack/airblade/start 3 | url = https://github.com/airblade/vim-gitgutter.git 4 | [submodule "pack/github/start/copilot.vim"] 5 | path = pack/github/start/copilot.vim 6 | url = https://github.com/github/copilot.vim.git 7 | -------------------------------------------------------------------------------- /lua/plugins/txtobjs.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "kylechui/nvim-surround", 4 | keys = { "cs", "ys", "ds" }, 5 | config = function() 6 | require("nvim-surround").setup({ 7 | -- Configuration here, or leave empty to use defaults 8 | }) 9 | end, 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | echo "install" 3 | python3 -m pip install --user --upgrade pynvim 4 | npm i -g bash-language-server 5 | git clone https://github.com/github/copilot.vim.git \ 6 | ~/.vim/pack/github/start/copilot.vim 7 | git submodule update --init 8 | upload: 9 | git add . 10 | git commit -m "update config" 11 | git push origin master 12 | -------------------------------------------------------------------------------- /lua/plugins/tmux.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "xiantang/Navigator.nvim", 4 | keys = { 5 | { "", "NavigatorRight", {} }, 6 | { "", "NavigatorLeft", {} }, 7 | { "", "NavigatorUp", {} }, 8 | { "", "NavigatorDown", {} }, 9 | }, 10 | -- master 11 | config = function() 12 | require("Navigator").setup({}) 13 | end, 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /lua/plugins/session.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "rmagatti/auto-session", 4 | config = function() 5 | vim.o.sessionoptions = "buffers,curdir,winsize,localoptions" 6 | require("auto-session").setup({ 7 | session_lens = { 8 | load_on_setup = false, 9 | }, 10 | log_level = "error", 11 | auto_session_suppress_dirs = { "~/", "~/Projects", "~/Downloads", "/" }, 12 | }) 13 | end, 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /.luarc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", 3 | "Lua.completion.autoRequire": false, 4 | "Lua.diagnostics.disable": [ 5 | "unused-local", 6 | "missing-fields" 7 | ], 8 | "Lua.diagnostics.globals": [ 9 | "vim", 10 | "defer", 11 | "gofumpt", 12 | "core", 13 | "require" 14 | ], 15 | "Lua.workspace.checkThirdParty": false 16 | } 17 | -------------------------------------------------------------------------------- /lua/lib.lua: -------------------------------------------------------------------------------- 1 | M = {} 2 | 3 | function M.safeRequire(module) 4 | local success, loadedModule = pcall(require, module) 5 | if success then 6 | return loadedModule 7 | end 8 | return nil 9 | end 10 | 11 | function M.location() 12 | local buf_name = vim.api.nvim_buf_get_name(0) 13 | local val = vim.fn.filereadable(buf_name) 14 | if val == 1 then 15 | MiniFiles.open(buf_name) 16 | MiniFiles.reveal_cwd() 17 | else 18 | MiniFiles.open() 19 | MiniFiles.reveal_cwd() 20 | end 21 | end 22 | 23 | return M 24 | -------------------------------------------------------------------------------- /lua/plugins/files.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "xiantang/nvim-tree.lua", 4 | version = "*", 5 | lazy = false, 6 | dev = true, 7 | keys = { 8 | { 9 | "l", 10 | ":NvimTreeFindFile ", 11 | desc = "smart location", 12 | }, 13 | { 14 | "t", 15 | ":NvimTreeToggle ", 16 | }, 17 | }, 18 | dependencies = { 19 | "nvim-tree/nvim-web-devicons", 20 | }, 21 | config = function() 22 | require("nvim-tree").setup({ 23 | marks = { 24 | enable_persistence = true, 25 | } 26 | }) 27 | end, 28 | }, 29 | } 30 | -------------------------------------------------------------------------------- /lua/plugins/profile.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "folke/snacks.nvim", 4 | keys = { 5 | { 6 | "up", 7 | function() 8 | Snacks.toggle.profiler():toggle() 9 | end, 10 | desc = "Toggle Profiler", 11 | }, 12 | { 13 | "uh", 14 | function() 15 | Snacks.toggle.profiler_highlights():toggle() 16 | end, 17 | desc = "Toggle Profiler Highlights", 18 | }, 19 | { 20 | "us", 21 | function() 22 | Snacks.profiler.scratch() 23 | end, 24 | desc = "Profiler Scratch Buffer", 25 | }, 26 | }, 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /lua/plugins/colorscheme.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "norcalli/nvim-colorizer.lua", 4 | config = function() 5 | require("colorizer").setup() 6 | end, 7 | }, 8 | { 9 | "folke/tokyonight.nvim", 10 | priority = 1000, 11 | enabled = false, 12 | opts = {}, 13 | }, 14 | { 15 | "xiantang/darcula-dark.nvim", 16 | config = function() 17 | -- setup must be called before loading 18 | require("darcula").setup({ 19 | ---@diagnostic disable-next-line: assign-type-mismatch 20 | opt = { 21 | integrations = { 22 | telescope = false, 23 | lualine = true, 24 | lsp_semantics_token = true, 25 | nvim_cmp = true, 26 | dap_nvim = true, 27 | }, 28 | }, 29 | }) 30 | end, 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /my_snippets/lua/markdown.lua: -------------------------------------------------------------------------------- 1 | local ls = require("luasnip") 2 | 3 | ls.add_snippets("markdown", { 4 | -- todo date of today 5 | ls.parser.parse_snippet("todo", "# todo ${CURRENT_YEAR}-${CURRENT_MONTH}-${CURRENT_DATE}"), 6 | }) 7 | 8 | ls.add_snippets("norg", { 9 | -- todo date of today 10 | ls.parser.parse_snippet("today", "* ${CURRENT_YEAR}/${CURRENT_MONTH}/${CURRENT_DATE}"), 11 | }) 12 | ls.add_snippets("markdown", { 13 | ls.parser.parse_snippet("-", "- [ ] ${1}"), 14 | }) 15 | 16 | ls.add_snippets("gitcommit", { 17 | ls.parser.parse_snippet("dai", "update daily ${CURRENT_YEAR}-${CURRENT_MONTH}-${CURRENT_DATE}"), 18 | }) 19 | 20 | ls.add_snippets("gitcommit", { 21 | ls.parser.parse_snippet("lint", "lint(code): fix the annoying lint error"), 22 | }) 23 | -------------------------------------------------------------------------------- /lua/plugins/database.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "kristijanhusak/vim-dadbod-ui", 3 | keys = { 4 | { "db", ":DBUIToggle", desc = "DBUIToggle" }, 5 | }, 6 | dependencies = { 7 | { "tpope/vim-dadbod", lazy = true }, 8 | { "kristijanhusak/vim-dadbod-completion", ft = { "sql", "mysql", "plsql" }, lazy = true }, 9 | }, 10 | cmd = { 11 | "DBUI", 12 | "DBUIToggle", 13 | "DBUIAddConnection", 14 | "DBUIFindBuffer", 15 | }, 16 | init = function() 17 | -- Your DBUI configuration 18 | vim.g.db_ui_use_nerd_fonts = 1 19 | vim.g.db_ui_execute_on_save = 0 20 | vim.g.db_ui_auto_execute_table_helpers = 1 21 | vim.g.db_ui_table_helpers = { 22 | mysql = { 23 | ["Show Create table"] = "show create table {table} \\G", 24 | }, 25 | } 26 | end, 27 | } 28 | -------------------------------------------------------------------------------- /my_snippets/sh.snippets: -------------------------------------------------------------------------------- 1 | snippet whilereadvar "while read loop to process lines from a variable" 2 | while IFS= read -r ${1:line}; do 3 | echo "\$${1:line}" 4 | done <<< "\$${2:the_list}" 5 | 6 | snippet fori "An index-based iteration for loop" 7 | for ((${1:i} = 0; ${1:i} < ${0:10}; ${1:i}++)); do 8 | echo "\$${1:i}" 9 | done 10 | 11 | snippet forr "for loop through array elements" 12 | for ${1:item} in "\${${2:array}[@]}"; do 13 | echo "\$${1:item}" 14 | done 15 | 16 | snippet <grep!-R\"\\\"\\>." 12 | }, 13 | { 14 | "name": "snake_to_camel_case", 15 | "raw": "eWl3bW1vEiIbOhtWOnMvX1woLlwpL1xVXDEvZw1kYXdrSmBtdml3cA==", 16 | "content": "yiwmmo\":V:s/_\\(.\\)/\\U\\1/gdawkJ`mviwp" 17 | }, 18 | { 19 | "name": "remove_function_call", 20 | "raw": "eXltbVBEYG15aWFrcGpkZGts", 21 | "content": "yymmPD`myiakpjddkl" 22 | }, 23 | { 24 | "name": "telescope_find_by_current_word", 25 | "raw": "eWl3OlRlbGVzY29wZSBsaXZlX2dyZXANXGISIlxiCg==", 26 | "content": "yiw:Telescopelive_grep\\b\"\\b" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: [ "master","dev" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Build the Docker image 15 | run: docker build . --file Dockerfile --tag neovim 16 | - name: run the Docker image 17 | id: record 18 | run: | 19 | docker run -d --name neovim neovim tail -f /dev/null 20 | docker exec -i neovim /bin/bash -c "nvim --headless --startuptime log +qa || exit 0" 21 | echo "##[set-output name=startuptime;]$(docker exec -i neovim /bin/bash -c "cat log" | tail -n 1 |awk '{print $1}' |sed 's/\..*//' | sed 's/^0*//' )" 22 | - name: Bring Your Own Badge 23 | uses: RubbaBoy/BYOB@v1.2.1 24 | with: 25 | NAME: "startuptime" 26 | LABEL: 'startuptime' 27 | STATUS: ${{ steps.record.outputs.startuptime }} ms 28 | COLOR: 00EEFF 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /AGENTS.md: -------------------------------------------------------------------------------- 1 | # AGENTS 2 | 3 | - Scope: Neovim config; primary code in `init.lua` and `lua/**`. 4 | - Build: `docker build . --file Dockerfile --tag neovim`. 5 | - Install deps: `make install` (pynvim, bash-language-server, submodules). 6 | - Plugin sync: `nvim --headless "+Lazy! restore" +qa`. 7 | - Tests: no repo-level test runner defined. 8 | - Formatting: via LSP/none-ls; shfmt, gofmt, goimports, stylua, black, isort, nixfmt. 9 | - Linting: hadolint diagnostics via none-ls; no standalone lint script. 10 | - Indentation: follow existing Lua style (tabs, trailing commas). 11 | - Imports: `local mod = require("...")`; keep require near usage. 12 | - Optional deps: prefer `require("lib").safeRequire`/`pcall` guards. 13 | - Naming: `local` variables; modules return `M` table of functions. 14 | - Plugin specs: table entries with `event/cmd/keys/config/opts`. 15 | - Error handling: use `vim.notify` for user-facing warnings/errors. 16 | - Keymaps: use `vim.keymap.set` with `desc`, `silent`, `noremap`. 17 | - Avoid adding new tooling/scripts unless asked. 18 | - Cursor/Copilot rules: none found in `.cursor/rules/`, `.cursorrules`, `.github/copilot-instructions.md`. 19 | -------------------------------------------------------------------------------- /lua/plugins/test.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | cmd = "AsyncRun", 4 | "skywind3000/asyncrun.vim", 5 | }, 6 | { 7 | "vim-test/vim-test", 8 | keys = { 9 | "tt", 10 | "tf", 11 | }, 12 | lazy = false, 13 | dependencies = { 14 | "tpope/vim-dispatch", 15 | }, 16 | config = function() 17 | vim.keymap.set( 18 | "n", 19 | "tt", 20 | ":TestNearest -v", 21 | { desc = "TestNearest", silent = true, noremap = true } 22 | ) 23 | vim.keymap.set("n", "tf", ":GoTestFile", { desc = "GoTestFile", silent = true, noremap = true }) 24 | vim.keymap.set( 25 | "n", 26 | "uv", 27 | ":TestVisit", 28 | { desc = "Go to last visit test file", silent = true, noremap = true } 29 | ) 30 | 31 | vim.cmd([[ 32 | let test#strategy = { 33 | \ 'nearest': 'asyncrun', 34 | \ 'file': 'dispatch', 35 | \ 'suite': 'basic', 36 | \} 37 | let test#neovim#term_position = "topleft" 38 | let test#neovim#term_position = "vert" 39 | let test#go#gotest#options = '-gcflags="all=-l -N" -v' 40 | let test#neovim#term_position = "vert botright 51" 41 | let g:asyncrun_open = 8 42 | ]]) 43 | end, 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /lua/keyword.lua: -------------------------------------------------------------------------------- 1 | -- Custom nvim-cmp source for GitHub handles. 2 | 3 | local handles = {} 4 | 5 | local registered = false 6 | 7 | local keywords = { 8 | go = { 9 | "if", 10 | "for", 11 | }, 12 | lua = { 13 | "if", 14 | "for", 15 | }, 16 | } 17 | 18 | handles.setup = function() 19 | if registered then 20 | return 21 | end 22 | registered = true 23 | 24 | local has_cmp, cmp = pcall(require, "cmp") 25 | 26 | if not has_cmp then 27 | return 28 | end 29 | 30 | local source = {} 31 | 32 | source.new = function() 33 | return setmetatable({}, { __index = source }) 34 | end 35 | 36 | source.complete = function(self, request, callback) 37 | local filetype = vim.api.nvim_buf_get_option(0, "filetype") 38 | local input = string.sub(request.context.cursor_before_line, request.offset - 1) 39 | local prefix = string.sub(request.context.cursor_before_line, 1, request.offset - 1) 40 | 41 | local items = {} 42 | local lang = keywords[filetype] 43 | if lang == nil then 44 | return 45 | end 46 | for _, keyword in pairs(lang) do 47 | table.insert(items, { 48 | label = keyword, 49 | kind = cmp.lsp.CompletionItemKind.Keyword, 50 | }) 51 | end 52 | callback({ 53 | items = items, 54 | isIncomplete = true, 55 | }) 56 | end 57 | 58 | cmp.register_source("keyword", source.new()) 59 | end 60 | 61 | return handles 62 | -------------------------------------------------------------------------------- /lua/plugins/ui.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { "kevinhwang91/nvim-bqf", ft = "qf" }, 3 | { 4 | "nvim-lualine/lualine.nvim", 5 | dependencies = { "nvim-tree/nvim-web-devicons" }, 6 | config = function() 7 | local function buffer_count() 8 | local count = 0 9 | for b = 1, vim.fn.bufnr("$") do 10 | if vim.fn.buflisted(b) ~= 0 and vim.api.nvim_buf_get_option(b, "buftype") ~= "quickfix" then 11 | count = count + 1 12 | end 13 | end 14 | 15 | return "bufs: " .. count 16 | end 17 | require("lualine").setup({ 18 | sections = { 19 | lualine_a = { "mode" }, 20 | lualine_b = { "branch", "diff", "diagnostics" }, 21 | lualine_c = { { "filename", path = 1 }, buffer_count }, 22 | lualine_x = { "encoding", "fileformat", "filetype" }, 23 | lualine_y = { "progress" }, 24 | lualine_z = { "location" }, 25 | }, 26 | }) 27 | end, 28 | }, 29 | { 30 | "petertriho/nvim-scrollbar", 31 | event = { "BufReadPost", "BufNewFile", "BufWritePre" }, 32 | config = function() 33 | require("scrollbar").setup({ 34 | handlers = { 35 | cursor = true, 36 | diagnostic = false, 37 | gitsigns = false, -- Requires gitsigns 38 | handle = true, 39 | search = false, -- Requires hlslens 40 | ale = false, -- Requires ALE 41 | }, 42 | set_highlights = true, 43 | }) 44 | end, 45 | }, 46 | } 47 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim 2 | 3 | # Set image locale. 4 | ENV LANG=en_US.UTF-8 5 | ENV LANGUAGE=en_US:en 6 | ENV TZ=Asia/Singapore 7 | ENV DEBIAN_FRONTEND=noninteractive 8 | 9 | RUN apt-get update \ 10 | && apt-get install -y --no-install-recommends \ 11 | ca-certificates \ 12 | curl \ 13 | fzf \ 14 | ripgrep \ 15 | tree \ 16 | git \ 17 | xclip \ 18 | python3 \ 19 | python3-venv \ 20 | python3-pip \ 21 | nodejs \ 22 | npm \ 23 | tzdata \ 24 | ninja-build \ 25 | gettext \ 26 | libtool \ 27 | libtool-bin \ 28 | autoconf \ 29 | automake \ 30 | make \ 31 | cmake \ 32 | g++ \ 33 | pkg-config \ 34 | zip \ 35 | unzip \ 36 | sqlite3 \ 37 | libsqlite3-dev \ 38 | && rm -rf /var/lib/apt/lists/* 39 | 40 | # Create a Python virtual environment 41 | RUN python3 -m venv /venv 42 | 43 | # Activate the virtual environment 44 | ENV PATH="/venv/bin:$PATH" 45 | 46 | # Cooperate Neovim with Python 3. 47 | RUN pip3 install pynvim 48 | 49 | # Cooperate NodeJS with Neovim. 50 | RUN npm i -g neovim 51 | 52 | # Install Neovim from source. 53 | RUN mkdir -p /root/TMP 54 | RUN cd /root/TMP && git clone https://github.com/neovim/neovim 55 | RUN cd /root/TMP/neovim && git checkout stable && make -j4 && make install 56 | 57 | COPY ./ /root/.config/nvim/ 58 | 59 | # Install Neovim extensions. 60 | RUN nvim --headless "+Lazy! restore" +qa || exit 0 61 | RUN touch /root/.NERDTreeBookmarks 62 | -------------------------------------------------------------------------------- /lua/plugins/snippet.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "L3MON4D3/LuaSnip", 4 | config = function() 5 | require("luasnip.loaders.from_vscode").load({ 6 | include = { "norg", "c", "go", "python", "sh", "json", "lua", "gitcommit", "sql", "markdown" }, 7 | }) 8 | require("luasnip.loaders.from_vscode").lazy_load({ paths = { vim.fn.expand("~/.config/nvim/my_snippets") } }) 9 | require("luasnip.loaders.from_snipmate").lazy_load({ 10 | paths = { vim.fn.expand("~/.config/nvim/my_snippets") }, 11 | }) 12 | 13 | local ls = require("luasnip") 14 | vim.keymap.set({ "i", "s" }, "", function() 15 | ls.jump(1) 16 | end, { silent = true }) 17 | vim.keymap.set({ "i", "s" }, "", function() 18 | ls.jump(-1) 19 | end, { silent = true }) 20 | local ls = require("luasnip") 21 | vim.api.nvim_create_autocmd("CursorMovedI", { 22 | pattern = "*", 23 | callback = function(ev) 24 | if not ls.session or not ls.session.current_nodes[ev.buf] or ls.session.jump_active then 25 | return 26 | end 27 | 28 | local current_node = ls.session.current_nodes[ev.buf] 29 | local current_start, current_end = current_node:get_buf_position() 30 | current_start[1] = current_start[1] + 1 -- (1, 0) indexed 31 | current_end[1] = current_end[1] + 1 -- (1, 0) indexed 32 | local cursor = vim.api.nvim_win_get_cursor(0) 33 | 34 | if 35 | cursor[1] < current_start[1] 36 | or cursor[1] > current_end[1] 37 | or cursor[2] < current_start[2] 38 | or cursor[2] > current_end[2] 39 | then 40 | ls.unlink_current() 41 | end 42 | end, 43 | }) 44 | end, 45 | 46 | event = "InsertEnter", 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /lua/plugins/edit_support.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { "romainl/vim-cool", event = "CursorMoved" }, 3 | { 4 | "segeljakt/vim-silicon", 5 | cmd = "Silicon", 6 | config = function() 7 | vim.cmd([[ 8 | let g:silicon={} 9 | let g:plug_window = 'botright 40vnew' 10 | let g:silicon['output'] = '~/images/silicon-{time:%Y-%m-%d-%H%M%S}.png']]) 11 | end, 12 | }, 13 | { 14 | "andymass/vim-matchup", 15 | keys = { "%", "g%" }, 16 | config = function() 17 | -- may set any options here 18 | vim.g.matchup_matchparen_offscreen = { method = "scrolloff" } 19 | end, 20 | }, 21 | -- { 22 | -- "folke/neodev.nvim", 23 | -- ft = "lua", 24 | -- config = function() 25 | -- require("neodev").setup({}) 26 | -- end, 27 | -- }, 28 | { 29 | "folke/lazydev.nvim", 30 | ft = "lua", -- only load on lua files 31 | opts = { 32 | library = { 33 | -- See the configuration section for more details 34 | -- Load luvit types when the `vim.uv` word is found 35 | { path = "luvit-meta/library", words = { "vim%.uv" } }, 36 | }, 37 | }, 38 | }, 39 | { "vim-scripts/ReplaceWithRegister", keys = "gr" }, 40 | { 41 | "numToStr/Comment.nvim", 42 | keys = { { "gb", mode = { "n", "v" } }, { "gc", mode = { "n", "v" } } }, 43 | config = function() 44 | require("Comment").setup() 45 | end, 46 | }, 47 | { 48 | "windwp/nvim-autopairs", 49 | event = { "InsertEnter" }, 50 | config = function() 51 | require("nvim-autopairs").setup({ 52 | fast_wrap = {}, 53 | disable_filetype = { "TelescopePrompt", "vim", "sh" }, 54 | }) 55 | end, 56 | }, 57 | { 58 | "tpope/vim-sleuth", 59 | -- event = { "InsertEnter" }, 60 | -- config = function() 61 | -- require("guess-indent").setup({}) 62 | -- end, 63 | }, 64 | } 65 | -------------------------------------------------------------------------------- /lua/plugins/note.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "nvim-neorg/neorg", 4 | build = ":Neorg sync-parsers", 5 | enabled = false, 6 | ft = "norg", 7 | keys = { 8 | { "jn", ":Neorg workspace notes:Neorg journal today", desc = "[J]ournal [N]owday " }, 9 | { "jy", ":Neorg workspace notes:Neorg journal yesterday", desc = "[J]ournal [Y]esterday" }, 10 | { "jt", ":Neorg workspace notes:Neorg journal tomorrow", desc = "[J]ournal [T]omorrow " }, 11 | }, 12 | opts = { 13 | load = { 14 | ["core.keybinds"] = { 15 | config = { 16 | default_keybinds = false, 17 | hook = function(keybinds) 18 | keybinds.remap_event("norg", "i", "", "core.itero.next-iteration") 19 | keybinds.remap_event("norg", "n", "", "core.itero.next-iteration") 20 | end, 21 | }, 22 | }, 23 | ["core.defaults"] = {}, -- Loads default behaviour 24 | -- ["core.presenter"] = { config = { 25 | -- zen_mode = "zen-mode", 26 | -- } }, 27 | ["core.export"] = {}, 28 | ["core.completion"] = { config = { engine = "nvim-cmp" } }, 29 | ["core.export.markdown"] = { 30 | config = { 31 | extensions = "all", 32 | }, 33 | }, 34 | ["core.concealer"] = { 35 | config = { 36 | folds = false, 37 | icons = { 38 | todo = { 39 | undone = { 40 | icon = " ", 41 | }, 42 | }, 43 | }, 44 | }, 45 | }, -- Adds pretty icons to your documents 46 | ["core.dirman"] = { -- Manages Neorg workspaces 47 | config = { 48 | workspaces = { 49 | notes = "~/notes", 50 | }, 51 | }, 52 | }, 53 | }, 54 | }, 55 | dependencies = { { "nvim-lua/plenary.nvim" } }, 56 | }, 57 | } 58 | -------------------------------------------------------------------------------- /lua/plugins/im_select.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | event = { "InsertEnter", "BufEnter" }, 4 | "keaising/im-select.nvim", 5 | config = function() 6 | require("im_select").setup({ 7 | -- IM will be set to `default_im_select` in `normal` mode(`EnterVim` or `InsertLeave`) 8 | -- For Windows/WSL, default: "1033", aka: English US Keyboard 9 | -- For macOS, default: "com.apple.keylayout.ABC", aka: US 10 | -- You can use `im-select` in cli to get the IM name of you preferred 11 | default_im_select = "com.apple.keylayout.ABC", 12 | -- Set to 1 if you don't want restore IM status when `InsertEnter` 13 | keep_quiet_on_no_binary = true, 14 | disable_auto_restore = 0, 15 | }) 16 | -- check is macos 17 | if vim.fn.has("mac") == 1 then 18 | local function all_trim(s) 19 | return s:match("^%s*(.-)%s*$") 20 | end 21 | vim.api.nvim_create_autocmd({ "InsertEnter", "FocusGained" }, { 22 | callback = function() 23 | local default_im_select = "com.apple.keylayout.ABC" 24 | local current_select = all_trim(vim.fn.system({ "im-select" })) 25 | if current_select ~= default_im_select then 26 | vim.fn.system({ "im-select", default_im_select }) 27 | end 28 | end, 29 | }) 30 | else 31 | local function all_trim(s) 32 | return s:match("^%s*(.-)%s*$") 33 | end 34 | local function run_shell_command(command) 35 | local handle = io.popen(command) 36 | local result = handle:read("*a") 37 | handle:close() 38 | return result 39 | end 40 | vim.api.nvim_create_autocmd({ "InsertEnter", "FocusGained" }, { 41 | callback = function() 42 | local default_im_select = "com.apple.keylayout.ABC" 43 | local current_select = all_trim(run_shell_command("sudo mac im-select")) 44 | if current_select ~= default_im_select then 45 | run_shell_command("sudo mac im-select " .. default_im_select) 46 | end 47 | end, 48 | }) 49 | end 50 | end, 51 | }, 52 | } 53 | -------------------------------------------------------------------------------- /lua/keymap.lua: -------------------------------------------------------------------------------- 1 | -- vim.cmd([[ 2 | -- ]]) 3 | local opts = { noremap = true, silent = true } 4 | 5 | vim.keymap.set("v", "y", "ygv", opts) 6 | 7 | -- nnoremap :cp 8 | -- nnoremap :cn 9 | -- because hhkb layout backtick is hard to press 10 | -- vim.keymap.set("n", "o", "o", opts) 11 | -- vim.keymap.set("n", "c", "c", opts) 12 | -- vim.keymap.set("n", "r", "r", opts) 13 | -- vim.keymap.set("n", "q", "q", opts) 14 | vim.keymap.set("n", "n", "nzz") 15 | vim.keymap.set("n", "N", "Nzz") 16 | vim.keymap.set("n", "", ":vertical resize +5", opts) 17 | vim.keymap.set("n", "", ":vertical resize -5", opts) 18 | vim.keymap.set("n", "", ":resize +5", opts) 19 | vim.keymap.set("n", "db", "%bd|e#", { desc = "Close all buffers but the current one" }) 20 | 21 | vim.keymap.set("n", "", ":resize -5", opts) 22 | vim.keymap.set("n", "0", "^", opts) 23 | vim.keymap.set("n", "ZZ", ":wq", opts) 24 | vim.keymap.set("n", "z=", "1z=", opts) 25 | vim.keymap.set("n", "gs", ":Git", opts) 26 | vim.keymap.set("n", "gb", ":Git blame", opts) 27 | vim.keymap.set("n", "gl", ":Gllog -- %", opts) 28 | -- we can use s and v to split 29 | vim.keymap.set("n", "s", ":sp", { desc = "[S]plit window" }) 30 | vim.keymap.set("n", "v", ":vsp", { desc = "[V]ertically [S]plit window" }) 31 | vim.keymap.set("n", " r", ":GoRename", opts) 32 | vim.keymap.set("n", "ZZ", ":wqa", opts) 33 | vim.keymap.set("n", "gp", "`[v`]", opts) 34 | 35 | vim.cmd([[ 36 | "ctrl A to move to line start when in command mode like in iterm2 37 | "ctrl E to move to line end when in command mode like in iterm2 38 | cnoremap 39 | cnoremap 40 | inoremap + 41 | nnoremap "+p 42 | cnoremap + 43 | ]]) 44 | 45 | vim.cmd([[ 46 | tnoremap "+p 47 | tnoremap 48 | ]]) 49 | 50 | local function t(str) 51 | return vim.api.nvim_replace_termcodes(str, true, true, true) 52 | end 53 | 54 | function _G.smart_ctrl_e() 55 | local ret = vim.api.nvim_eval("copilot#GetDisplayedSuggestion()") 56 | if ret.text ~= "" then 57 | return ret.text 58 | else 59 | return t("A") 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lua/autocmd.lua: -------------------------------------------------------------------------------- 1 | vim.cmd([[ 2 | function Undotree_record() abort 3 | if has("persistent_undo") 4 | let target_path = expand('~/.undodir') 5 | " create the directory and any parent directories 6 | " if the location does not exist. 7 | if !isdirectory(target_path) 8 | call mkdir(target_path, "p", 0700) 9 | endif 10 | 11 | let &undodir=target_path 12 | set undofile 13 | endif 14 | endfunction 15 | let g:undotree_WindowLayout = 3 16 | au BufEnter * call Undotree_record() 17 | au TermOpen * setlocal nobuflisted 18 | "au WinResized * wincmd = 19 | au BufEnter leetcode.cn_*.txt set filetype=go 20 | " https://github.com/fatih/vim-go/issues/1757 21 | au BufEnter *.conf set filetype=config 22 | au BufEnter * set formatoptions-=cro 23 | au BufEnter Brewfile set filetype=ruby 24 | au BufEnter .zpreztorc set filetype=zsh 25 | au BufEnter nerdtree setlocal relativenumber 26 | " au CursorHold * checktime 27 | " au CursorHold,CursorHoldI * checktime 28 | au BufRead,BufNewFile *.jq setfiletype jq 29 | au BufRead,BufNewFile *.http setfiletype http 30 | au BufNewFile,BufRead *.template setfiletype gotmpl 31 | au BufNewFile,BufRead sshconfig setfiletype sshconfig 32 | au BufNewFile,BufRead */ssh/config setf sshconfig 33 | au BufWinEnter NvimTree setlocal rnu 34 | au VimEnter * :clearjumps 35 | autocmd FileType dbout setlocal nofoldenable 36 | au InsertLeave,VimEnter * :silent exec "!sudo mac im-select com.apple.keylayout.ABC" 37 | au User GnuPG setl textwidth=72 38 | autocmd VimLeavePre * :redir >> ~/.config/nvim/messages.txt | silent messages | redir END 39 | ]]) 40 | vim.api.nvim_create_autocmd("BufWritePre", { 41 | pattern = { "*.go" }, 42 | callback = function() 43 | local params = vim.lsp.util.make_range_params(nil, vim.lsp.util._get_offset_encoding()) 44 | params.context = { only = { "source.organizeImports" } } 45 | 46 | local result = vim.lsp.buf_request_sync(0, "textDocument/codeAction", params, 3000) 47 | for _, res in pairs(result or {}) do 48 | for _, r in pairs(res.result or {}) do 49 | if r.edit then 50 | vim.lsp.util.apply_workspace_edit(r.edit, vim.lsp.util._get_offset_encoding()) 51 | else 52 | vim.lsp.buf.execute_command(r.command) 53 | end 54 | end 55 | end 56 | end, 57 | }) 58 | 59 | vim.api.nvim_create_autocmd("TextYankPost", { 60 | pattern = { "*" }, 61 | callback = function() 62 | vim.highlight.on_yank({ 63 | timeout = 50, 64 | }) 65 | end, 66 | }) 67 | -------------------------------------------------------------------------------- /lua/plugins/debugging.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "leoluz/nvim-dap-go", 4 | config = function() 5 | local function get_arguments() 6 | return coroutine.create(function(dap_run_co) 7 | local args = {} 8 | vim.ui.input({ prompt = "Args: " }, function(input) 9 | args = vim.split(input or "", " ") 10 | coroutine.resume(dap_run_co, args) 11 | end) 12 | end) 13 | end 14 | require("dap-go").setup({ 15 | -- Additional dap configurations can be added. 16 | -- dap_configurations accepts a list of tables where each entry 17 | -- represents a dap configuration. For more details do: 18 | -- :help dap-configuration 19 | dap_configurations = { 20 | { 21 | type = "go", 22 | name = "Debug Package (with args)", 23 | request = "launch", 24 | program = "${workspaceFolder}", 25 | args = get_arguments, 26 | }, 27 | }, 28 | -- delve configurations 29 | delve = { 30 | -- the path to the executable dlv which will be used for debugging. 31 | -- by default, this is the "dlv" executable on your PATH. 32 | path = "dlv", 33 | -- time to wait for delve to initialize the debug session. 34 | -- default to 20 seconds 35 | initialize_timeout_sec = 20, 36 | -- a string that defines the port to start delve debugger. 37 | -- default to string "${port}" which instructs nvim-dap 38 | -- to start the process in a random available port 39 | port = "${port}", 40 | -- additional args to pass to dlv 41 | args = {}, 42 | -- the build flags that are passed to delve. 43 | -- defaults to empty string, but can be used to provide flags 44 | -- such as "-tags=unit" to make sure the test suite is 45 | -- compiled during debugging, for example. 46 | -- passing build flags using args is ineffective, as those are 47 | -- ignored by delve in dap mode. 48 | build_flags = "-tags=util,integration,core", 49 | }, 50 | }) 51 | end, 52 | }, 53 | { "rcarriga/nvim-dap-ui", lazy = true }, 54 | { 55 | keys = { 56 | { "de", ':lua require"dap".toggle_breakpoint()' }, 57 | }, 58 | "mfussenegger/nvim-dap", 59 | config = function() 60 | require("nvim-dap-virtual-text").setup() 61 | require("dap_set") 62 | end, 63 | }, 64 | dependencies = { 65 | "theHamsta/nvim-dap-virtual-text", 66 | }, 67 | { 68 | "theHamsta/nvim-dap-virtual-text", 69 | lazy = true, 70 | }, 71 | } 72 | -------------------------------------------------------------------------------- /my_snippets/go.snippets: -------------------------------------------------------------------------------- 1 | snippet func "Snippet for function declaration" 2 | func ${1}(${2}) ${3} { 3 | ${0} 4 | } 5 | snippet for "Snippet for a pure for loop" for ${1} { ${0} 6 | } 7 | 8 | snippet fori "Snippet for a for loop" 9 | for ${1:i} := ${2:0}; ${1} < ${3:count}; ${1}${4:++} { 10 | ${0} 11 | } 12 | 13 | snippet forr "Snippet for a for range loop" 14 | for ${1:_, }${2:v} := range ${3:v} { 15 | ${0} 16 | } 17 | 18 | snippet map "Snippet for a map" 19 | map[${1:type}]${2:type} 20 | 21 | snippet tf "Snippet for Test function" 22 | func Test${1}(t *testing.T) { 23 | ${0} 24 | } 25 | 26 | snippet make "Snippet for make statement" 27 | make(${1:type}, ${2:0}) 28 | 29 | snippet if "Snippet for if statement" 30 | if ${1:condition} { 31 | ${0} 32 | } 33 | 34 | snippet el "Snippet for else branch" 35 | else { 36 | ${0} 37 | } 38 | 39 | snippet sw "switch" 40 | switch ${1:var} { 41 | case ${2:value1}: 42 | ${3} 43 | case ${4:value2}: 44 | ${5} 45 | default: 46 | ${0} 47 | } 48 | 49 | snippet ife "Use the statement before the if condition" 50 | if err != nil { 51 | return err 52 | } 53 | 54 | snippet stru "struct" 55 | type ${1} struct { 56 | ${2} 57 | } 58 | 59 | snippet inter "interface" 60 | type ${1} interface { 61 | ${2} 62 | } 63 | 64 | snippet sli "slice literal" 65 | ${1} := []${2}{${3}} 66 | 67 | snippet gorm "Snippet for struct gorm tag" 68 | \`gorm:"${1}"\` 69 | 70 | snippet mockr "mock and return" 71 | mockey.Mock(${1:text}).Return(${2:text}).Build() 72 | 73 | snippet mockt "mock and To" 74 | mockey.Mock(${1:text}).To(${2:text}).Build() 75 | 76 | snippet sw 77 | switch ${1:var} { 78 | case ${2:value1}: 79 | ${3} 80 | case ${4:value2}: 81 | ${5} 82 | default: 83 | ${6} 84 | } 85 | 86 | snippet tfpost 87 | func Test${1:Name}(t *testing.T) { 88 | 89 | router := testfunctions.SetupRouter() 90 | 91 | mockey.PatchConvey("Test${1:Name}", t, func() { 92 | 93 | // req and resp body 94 | req:= ${2:YourRequest}{ 95 | } 96 | resp := ${3:YourResponse}{} 97 | 98 | // mock code 99 | { 100 | mocktcc.UsingDefaultValue() 101 | } 102 | 103 | code, err := router.DoPost("${4:url}", req, &resp) 104 | if err != nil { 105 | t.Error(err) 106 | } 107 | 108 | // assert 109 | assert.Equal(t, 200, code) 110 | }) 111 | } 112 | 113 | -------------------------------------------------------------------------------- /lua/plugins/fold.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "kevinhwang91/nvim-ufo", 4 | config = function() 5 | local handler = function(virtText, lnum, endLnum, width, truncate) 6 | local newVirtText = {} 7 | local suffix = (" 󰁂 %d "):format(endLnum - lnum) 8 | local sufWidth = vim.fn.strdisplaywidth(suffix) 9 | local targetWidth = width - sufWidth 10 | local curWidth = 0 11 | for _, chunk in ipairs(virtText) do 12 | local chunkText = chunk[1] 13 | local chunkWidth = vim.fn.strdisplaywidth(chunkText) 14 | if targetWidth > curWidth + chunkWidth then 15 | table.insert(newVirtText, chunk) 16 | else 17 | chunkText = truncate(chunkText, targetWidth - curWidth) 18 | local hlGroup = chunk[2] 19 | table.insert(newVirtText, { chunkText, hlGroup }) 20 | chunkWidth = vim.fn.strdisplaywidth(chunkText) 21 | -- str width returned from truncate() may less than 2nd argument, need padding 22 | if curWidth + chunkWidth < targetWidth then 23 | suffix = suffix .. (" "):rep(targetWidth - curWidth - chunkWidth) 24 | end 25 | break 26 | end 27 | curWidth = curWidth + chunkWidth 28 | end 29 | table.insert(newVirtText, { suffix, "MoreMsg" }) 30 | return newVirtText 31 | end 32 | vim.o.foldcolumn = "1" -- '0' is not bad 33 | -- vim.cmd("set foldopen-=hor") 34 | vim.o.foldlevel = 99 -- Using ufo provider need a large value, feel free to decrease the value 35 | vim.o.foldlevelstart = 99 36 | vim.o.foldenable = true 37 | vim.o.fillchars = [[eob: ,fold: ,foldopen:,foldsep: ,foldclose:]] 38 | 39 | -- these are "extra", change them as you like 40 | vim.keymap.set("n", "zR", require("ufo").openAllFolds) 41 | vim.keymap.set("n", "zM", require("ufo").closeAllFolds) 42 | -- vim.keymap.set("n", "", "za") 43 | 44 | require("ufo").setup({ 45 | fold_virt_text_handler = handler, 46 | provider_selector = function(bufnr, filetype, buftype) 47 | return { "treesitter", "indent" } 48 | end, 49 | }) 50 | end, 51 | dependencies = { 52 | "kevinhwang91/promise-async", 53 | { 54 | "luukvbaal/statuscol.nvim", 55 | config = function() 56 | local builtin = require("statuscol.builtin") 57 | local statuscol = require("statuscol") 58 | statuscol.setup({ 59 | relculright = true, 60 | segments = { 61 | { text = { "%s" }, click = "v:lua.ScSa" }, 62 | { text = { builtin.foldfunc }, click = "v:lua.ScFa" }, 63 | { text = { builtin.lnumfunc, " " }, click = "v:lua.ScLa" }, 64 | }, 65 | }) 66 | -- Some setups still reference the old global StatusCol(), so provide a fallback to avoid nil errors. 67 | if not _G.StatusCol then 68 | _G.StatusCol = function() 69 | return statuscol.get_statuscol_string() 70 | end 71 | end 72 | end, 73 | }, 74 | }, 75 | }, 76 | } 77 | -------------------------------------------------------------------------------- /lua/plugins/try.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | enabled = false, 4 | "nvim-pack/nvim-spectre", 5 | }, 6 | { 7 | enabled = false, 8 | "RRethy/vim-illuminate", 9 | config = function() 10 | -- default configuration 11 | require("illuminate").configure({ 12 | -- providers: provider used to get references in the buffer, ordered by priority 13 | providers = { 14 | "lsp", 15 | "treesitter", 16 | "regex", 17 | }, 18 | -- delay: delay in milliseconds 19 | delay = 100, 20 | -- filetype_overrides: filetype specific overrides. 21 | -- The keys are strings to represent the filetype while the values are tables that 22 | -- supports the same keys passed to .configure except for filetypes_denylist and filetypes_allowlist 23 | filetype_overrides = {}, 24 | -- filetypes_denylist: filetypes to not illuminate, this overrides filetypes_allowlist 25 | filetypes_denylist = { 26 | "dirbuf", 27 | "dirvish", 28 | "fugitive", 29 | }, 30 | -- filetypes_allowlist: filetypes to illuminate, this is overridden by filetypes_denylist 31 | -- You must set filetypes_denylist = {} to override the defaults to allow filetypes_allowlist to take effect 32 | filetypes_allowlist = {}, 33 | -- modes_denylist: modes to not illuminate, this overrides modes_allowlist 34 | -- See `:help mode()` for possible values 35 | modes_denylist = {}, 36 | -- modes_allowlist: modes to illuminate, this is overridden by modes_denylist 37 | -- See `:help mode()` for possible values 38 | modes_allowlist = {}, 39 | -- providers_regex_syntax_denylist: syntax to not illuminate, this overrides providers_regex_syntax_allowlist 40 | -- Only applies to the 'regex' provider 41 | -- Use :echom synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'name') 42 | providers_regex_syntax_denylist = {}, 43 | -- providers_regex_syntax_allowlist: syntax to illuminate, this is overridden by providers_regex_syntax_denylist 44 | -- Only applies to the 'regex' provider 45 | -- Use :echom synIDattr(synIDtrans(synID(line('.'), col('.'), 1)), 'name') 46 | providers_regex_syntax_allowlist = {}, 47 | -- under_cursor: whether or not to illuminate under the cursor 48 | under_cursor = true, 49 | -- large_file_cutoff: number of lines at which to use large_file_config 50 | -- The `under_cursor` option is disabled when this cutoff is hit 51 | large_file_cutoff = nil, 52 | -- large_file_config: config to use for large files (based on large_file_cutoff). 53 | -- Supports the same keys passed to .configure 54 | -- If nil, vim-illuminate will be disabled for large files. 55 | large_file_overrides = nil, 56 | -- min_count_to_highlight: minimum number of matches required to perform highlighting 57 | min_count_to_highlight = 1, 58 | -- should_enable: a callback that overrides all other settings to 59 | -- enable/disable illumination. This will be called a lot so don't do 60 | -- anything expensive in it. 61 | should_enable = function(bufnr) 62 | return true 63 | end, 64 | -- case_insensitive_regex: sets regex case sensitivity 65 | case_insensitive_regex = false, 66 | }) 67 | end, 68 | }, 69 | } 70 | -------------------------------------------------------------------------------- /lua/plugins/lsp.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "nvimtools/none-ls.nvim", 4 | event = { "BufReadPost", "BufNewFile", "BufWritePre" }, 5 | config = function() 6 | local null_ls = require("null-ls") 7 | -- require("custom_code_actions") 8 | null_ls.setup({ 9 | sources = { 10 | null_ls.builtins.formatting.shfmt, 11 | -- null_ls.builtins.formatting.nginx_beautifier, 12 | null_ls.builtins.formatting.gofmt, 13 | null_ls.builtins.formatting.goimports, 14 | -- null_ls.builtins.code_actions.shellcheck, 15 | null_ls.builtins.formatting.stylua, 16 | -- for python 17 | null_ls.builtins.formatting.black, 18 | null_ls.builtins.formatting.isort, 19 | null_ls.builtins.diagnostics.hadolint, 20 | null_ls.builtins.formatting.nixfmt, 21 | }, 22 | debug = true, 23 | }) 24 | end, 25 | }, 26 | { 27 | "ray-x/lsp_signature.nvim", 28 | event = "VeryLazy", 29 | opts = { 30 | floating_window = false, -- virtual hint enable 31 | hint_prefix = " ", 32 | hint_scheme = "TSConstructor", 33 | floating_window_above_cur_line = true, 34 | }, 35 | config = function(_, opts) 36 | require("lsp_signature").setup(opts) 37 | end, 38 | }, 39 | { 40 | "neovim/nvim-lspconfig", 41 | event = { "BufReadPre", "BufNewFile" }, 42 | -- use commit 43 | dependencies = { 44 | -- IMPORTANT: make sure to setup neodev BEFORE lspconfig 45 | -- "folke/neodev.nvim", 46 | }, 47 | config = function() 48 | require("lsp_config") 49 | end, 50 | }, 51 | { 52 | "williamboman/mason.nvim", 53 | cmd = { "Mason", "MasonInstall" }, 54 | config = function() 55 | local safeRequire = require("lib").safeRequire 56 | local is_mac = vim.fn.has("mac") == 1 57 | if is_mac == 0 then 58 | local mason_registry = require("mason-registry") 59 | mason_registry:on("package:install:success", function(pkg) 60 | pkg:get_receipt():if_present(function(receipt) 61 | for _, rel_path in pairs(receipt.links.bin) do 62 | local bin_abs_path = pkg:get_install_path() .. "/extension/server/bin/" .. rel_path 63 | os.execute( 64 | 'patchelf --set-interpreter "$(patchelf --print-interpreter $(grep -oE \\/nix\\/store\\/[a-z0-9]+-neovim-unwrapped-[0-9]+\\.[0-9]+\\.[0-9]+\\/bin\\/nvim $(which nvim)))" ' 65 | .. bin_abs_path 66 | ) 67 | end 68 | end) 69 | end) 70 | end 71 | safeRequire("mason").setup({ 72 | ui = { 73 | icons = { 74 | package_installed = "✓", 75 | }, 76 | }, 77 | }) 78 | safeRequire("mason-lspconfig").setup({ 79 | ensure_installed = { 80 | -- "awk_ls", 81 | -- "lua_ls", 82 | "sqlls", 83 | "jsonls", 84 | "pyright", 85 | "dockerls", 86 | "bashls", 87 | "vimls", 88 | "yamlls", 89 | "ts_ls", 90 | }, 91 | }) 92 | end, 93 | }, 94 | { "williamboman/mason-lspconfig.nvim", lazy = true }, 95 | { 96 | "ray-x/go.nvim", 97 | enabled = false, 98 | ft = "go", 99 | config = function() 100 | require("go").setup({ 101 | -- https://github.com/ray-x/go.nvim/issues/113 102 | lsp_codelens = false, 103 | }) 104 | end, 105 | }, 106 | 107 | { "ray-x/guihua.lua", event = "VeryLazy", enabled = false }, 108 | } 109 | -------------------------------------------------------------------------------- /lua/plugins/cmp.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "saghen/blink.cmp", 4 | lazy = false, -- lazy loading handled internally 5 | -- optional: provides snippets for the snippet source 6 | -- dependencies = "rafamadriz/friendly-snippets", 7 | 8 | -- use a release tag to download pre-built binaries 9 | tag = "v1.1.1", 10 | dependencies = "L3MON4D3/LuaSnip", 11 | -- OR build from source, requires nightly: https://rust-lang.github.io/rustup/concepts/channels.html#working-with-nightly-rust 12 | -- build = 'cargo build --release', 13 | -- If you use nix, you can build from source using latest nightly rust with: 14 | -- build = 'nix run .#build-plugin', 15 | 16 | ---@module 'blink.cmp' 17 | ---@type blink.cmp.Config 18 | opts = { 19 | snippets = { 20 | preset = "luasnip", 21 | expand = function(snippet) 22 | require("luasnip").lsp_expand(snippet) 23 | end, 24 | active = function(filter) 25 | if filter and filter.direction then 26 | return require("luasnip").jumpable(filter.direction) 27 | end 28 | return require("luasnip").in_snippet() 29 | end, 30 | jump = function(direction) 31 | require("luasnip").jump(direction) 32 | end, 33 | }, 34 | -- sources = { 35 | -- default = { "lsp", "path", "buffer", "luasnip" }, 36 | -- }, 37 | 38 | fuzzy = { 39 | -- The rust binary in my environment is out of date; force Lua to avoid version mismatches 40 | implementation = "lua", 41 | }, 42 | 43 | cmdline = { 44 | enabled = true, 45 | }, 46 | -- 'default' for mappings similar to built-in completion 47 | -- 'super-tab' for mappings similar to vscode (tab to accept, arrow keys to navigate) 48 | -- 'enter' for mappings similar to 'super-tab' but with 'enter' to accept 49 | -- see the "default configuration" section below for full documentation on how to define 50 | -- your own keymap. 51 | keymap = { 52 | [""] = { "show", "show_documentation", "hide_documentation" }, 53 | [""] = { "hide" }, 54 | [""] = { "select_and_accept" }, 55 | 56 | [""] = { "select_prev", "fallback" }, 57 | [""] = { "select_next", "fallback" }, 58 | 59 | [""] = { "scroll_documentation_up", "fallback" }, 60 | [""] = { "scroll_documentation_down", "fallback" }, 61 | 62 | [""] = { "fallback" }, 63 | [""] = { "snippet_backward", "fallback" }, 64 | }, 65 | 66 | appearance = { 67 | -- Sets the fallback highlight groups to nvim-cmp's highlight groups 68 | -- Useful for when your theme doesn't support blink.cmp 69 | -- will be removed in a future release 70 | use_nvim_cmp_as_default = false, 71 | -- Set to 'mono' for 'Nerd Font Mono' or 'normal' for 'Nerd Font' 72 | -- Adjusts spacing to ensure icons are aligned 73 | nerd_font_variant = "mono", 74 | }, 75 | 76 | -- default list of enabled providers defined so that you can extend it 77 | -- elsewhere in your config, without redefining it, via `opts_extend` 78 | 79 | completion = { 80 | menu = { 81 | border = "rounded", 82 | auto_show = function() 83 | return vim.bo.buftype ~= "prompt" 84 | and vim.b.completion ~= false 85 | and vim.bo.filetype ~= "TelescopePrompt" 86 | end, 87 | }, 88 | documentation = { 89 | auto_show = true, 90 | window = { 91 | border = "rounded", 92 | }, 93 | }, 94 | }, 95 | 96 | -- accept = { 97 | -- auto_brackets = { 98 | -- enabled = true, 99 | -- }, 100 | -- }, 101 | 102 | -- experimental signature help support 103 | -- signature = { enabled = true } 104 | }, 105 | -- allows extending the providers array elsewhere in your config 106 | -- without having to redefine it 107 | opts_extend = { "sources.default" }, 108 | }, 109 | } 110 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | if vim.fn.has("nvim-0.11") == 1 then 2 | vim.keymap.del({ "n" }, "grn") 3 | vim.keymap.del({ "n", "x" }, "gra") 4 | vim.keymap.del({ "n" }, "gri") 5 | end 6 | if vim.env.PROF then 7 | -- example for lazy.nvim 8 | -- change this to the correct path for your plugin manager 9 | local snacks = vim.fn.stdpath("data") .. "/lazy/snacks.nvim" 10 | vim.opt.rtp:append(snacks) 11 | require("snacks.profiler").startup({ 12 | startup = { 13 | event = "VimEnter", -- stop profiler on this event. Defaults to `VimEnter` 14 | -- event = "UIEnter", 15 | -- event = "VeryLazy", 16 | }, 17 | }) 18 | end 19 | local safeRequire = require("lib").safeRequire 20 | -- [[ Setting options ]] 21 | -- See `:help vim.o` 22 | -- use Bold 23 | -- source vim script 24 | -- vimrc can be reusued 25 | vim.cmd("source ~/.config/nvim/.vimrc") 26 | 27 | if vim.g.neovide then 28 | -- Put anything you want to happen only in Neovide here 29 | vim.o.guifont = "FiraCode Nerd Font Mono:h15" 30 | end 31 | vim.g.hardtime_default_on = 1 32 | vim.g.hardtime_maxcount = 2 33 | vim.g.hardtime_timeout = 700 34 | vim.g.list_of_normal_keys = { "h", "j", "k", "l", "-", "+", "", "", "", "" } 35 | vim.g.list_of_visual_keys = { "h", "j", "k", "l", "-", "+", "", "", "", "" } 36 | vim.g.list_of_insert_keys = { "", "", "", "" } 37 | vim.g.list_of_disabled_keys = {} 38 | vim.opt.conceallevel = 2 39 | local set = vim.o 40 | set.ts = 2 41 | set.termguicolors = true 42 | set.sts = 2 43 | set.sw = 2 44 | 45 | safeRequire("autocmd") 46 | safeRequire("keymap") 47 | local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" 48 | if not vim.loop.fs_stat(lazypath) then 49 | vim.fn.system({ 50 | "git", 51 | "clone", 52 | "--filter=blob:none", 53 | "https://github.com/folke/lazy.nvim.git", 54 | "--branch=stable", -- latest stable release 55 | lazypath, 56 | }) 57 | end 58 | 59 | vim.opt.rtp:prepend(lazypath) 60 | 61 | safeRequire("lazy").setup("plugins", { 62 | dev = { 63 | path = "~/sidepro/", 64 | patterns = {}, -- For example {"folke"} 65 | fallback = true, -- Fallback to git when local plugin doesn't exist 66 | }, 67 | change_detection = { 68 | -- automatically check for config file changes and reload the ui 69 | enabled = false, 70 | notify = true, -- get a notification when changes are found 71 | }, 72 | }) 73 | 74 | 75 | vim.cmd.colorscheme("darcula-dark") 76 | vim.cmd.cnoreabbrev([[git Git]]) 77 | vim.cmd.cnoreabbrev([[gp Git push]]) 78 | vim.cmd.cnoreabbrev([[w' w]]) 79 | vim.cmd.cnoreabbrev([[Gbrowse GBrowse]]) 80 | vim.cmd([[ 81 | nnoremap $ g$ 82 | nnoremap 0 g0 83 | nnoremap j v:count > 1 ? "j" : "gj" 84 | nnoremap k v:count > 1 ? "k" : "gk" 85 | ]]) 86 | local function fix_it_when_its_wrong(wrong, right) 87 | -- syntax keyword WordError wrong 88 | vim.cmd.abbreviate(wrong, right) 89 | local cmd = string.format("syntax keyword SpellBad %s", wrong) 90 | vim.cmd(cmd) 91 | end 92 | 93 | -- use map to for loop 94 | 95 | local dict = { 96 | stirng = "string", 97 | ture = "true", 98 | fucntion = "function", 99 | reutrn = "return", 100 | ehco = "echo", 101 | } 102 | 103 | for k, v in pairs(dict) do 104 | fix_it_when_its_wrong(k, v) 105 | end 106 | vim.g.copilot_no_tab_map = true 107 | vim.g.copilot_assume_mapped = true 108 | 109 | -- require("bookmarks").setup() 110 | 111 | vim.opt.fillchars:append("diff:╱") 112 | 113 | 114 | -- Silence the specific position encoding message 115 | local notify_original = vim.notify 116 | vim.notify = function(msg, ...) 117 | if 118 | msg 119 | and ( 120 | msg:match 'position_encoding param is required' 121 | or msg:match 'Defaulting to position encoding of the first client' 122 | or msg:match 'multiple different client offset_encodings' 123 | ) 124 | then 125 | return 126 | end 127 | return notify_original(msg, ...) 128 | end 129 | -------------------------------------------------------------------------------- /lazy-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" }, 3 | "LuaSnip": { "branch": "master", "commit": "3732756842a2f7e0e76a7b0487e9692072857277" }, 4 | "Navigator.nvim": { "branch": "master", "commit": "990f1df42391e508e55d86083e220c15cc1f2140" }, 5 | "ReplaceWithRegister": { "branch": "master", "commit": "832efc23111d19591d495dc72286de2fb0b09345" }, 6 | "asyncrun.vim": { "branch": "master", "commit": "98d3c0fdeb983f0ef62fe3a49da440f6d2c045ce" }, 7 | "auto-session": { "branch": "main", "commit": "292492ab7af4bd8b9e37e28508bc8ce995722fd5" }, 8 | "blink.cmp": { "branch": "main", "commit": "cb5e346d9e0efa7a3eee7fd4da0b690c48d2a98e" }, 9 | "darcula-dark.nvim": { "branch": "main", "commit": "54fd17d266a41de052360935a93af07538ecb2f5" }, 10 | "eyeliner.nvim": { "branch": "main", "commit": "8f197eb30cecdf4c2cc9988a5eecc6bc34c0c7d6" }, 11 | "im-select.nvim": { "branch": "master", "commit": "113a6905a1c95d2990269f96abcbad9718209557" }, 12 | "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, 13 | "lazydev.nvim": { "branch": "main", "commit": "5231c62aa83c2f8dc8e7ba957aa77098cda1257d" }, 14 | "lsp_signature.nvim": { "branch": "master", "commit": "7d3bb0a641f516f1c7fd2e47852580dadbd7a430" }, 15 | "lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" }, 16 | "mason-lspconfig.nvim": { "branch": "main", "commit": "9f9c67795d0795a6e8612f5a899ca64a074a1076" }, 17 | "mason.nvim": { "branch": "main", "commit": "57e5a8addb8c71fb063ee4acda466c7cf6ad2800" }, 18 | "none-ls.nvim": { "branch": "main", "commit": "5abf61927023ea83031753504adb19630ba80eef" }, 19 | "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, 20 | "nvim-autopairs": { "branch": "master", "commit": "c2a0dd0d931d0fb07665e1fedb1ea688da3b80b4" }, 21 | "nvim-bqf": { "branch": "main", "commit": "ba2b365969d7c2c6301d48e13aeee59568765529" }, 22 | "nvim-colorizer.lua": { "branch": "master", "commit": "a065833f35a3a7cc3ef137ac88b5381da2ba302e" }, 23 | "nvim-dap": { "branch": "master", "commit": "818cd8787a77a97703eb1d9090543a374f79a9ac" }, 24 | "nvim-dap-go": { "branch": "main", "commit": "b4421153ead5d726603b02743ea40cf26a51ed5f" }, 25 | "nvim-dap-ui": { "branch": "master", "commit": "cf91d5e2d07c72903d052f5207511bf7ecdb7122" }, 26 | "nvim-dap-virtual-text": { "branch": "master", "commit": "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" }, 27 | "nvim-lspconfig": { "branch": "master", "commit": "8973916a3d015d65a8c4614e141f4270a713cf33" }, 28 | "nvim-scrollbar": { "branch": "main", "commit": "f8e87b96cd6362ef8579be456afee3b38fd7e2a8" }, 29 | "nvim-surround": { "branch": "main", "commit": "1098d7b3c34adcfa7feb3289ee434529abd4afd1" }, 30 | "nvim-tree.lua": { "branch": "master", "commit": "7108587882d0073606dea3aec1a7df5c62bcc55e" }, 31 | "nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" }, 32 | "nvim-treesitter-textobjects": { "branch": "master", "commit": "5ca4aaa6efdcc59be46b95a3e876300cfead05ef" }, 33 | "nvim-ufo": { "branch": "main", "commit": "72d54c31079d38d8dfc5456131b1d0fb5c0264b0" }, 34 | "nvim-web-devicons": { "branch": "master", "commit": "6788013bb9cb784e606ada44206b0e755e4323d7" }, 35 | "opencode.nvim": { "branch": "main", "commit": "dfca5bb214d78a600781d50da350238b3e6e2621" }, 36 | "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, 37 | "promise-async": { "branch": "main", "commit": "119e8961014c9bfaf1487bf3c2a393d254f337e2" }, 38 | "snacks.nvim": { "branch": "main", "commit": "fe7cfe9800a182274d0f868a74b7263b8c0c020b" }, 39 | "statuscol.nvim": { "branch": "main", "commit": "c46172d0911aa5d49ba5f39f4351d1bb7aa289cc" }, 40 | "tabout.nvim": { "branch": "master", "commit": "9a3499480a8e53dcaa665e2836f287e3b7764009" }, 41 | "undotree": { "branch": "master", "commit": "0f1c9816975b5d7f87d5003a19c53c6fd2ff6f7f" }, 42 | "vim-be-good": { "branch": "master", "commit": "0ae3de14eb8efc6effe7704b5e46495e91931cc5" }, 43 | "vim-cool": { "branch": "master", "commit": "9ea940c0d537e55de0de4c0298c04b976960fb12" }, 44 | "vim-dadbod": { "branch": "master", "commit": "e95afed23712f969f83b4857a24cf9d59114c2e6" }, 45 | "vim-dadbod-completion": { "branch": "master", "commit": "a8dac0b3cf6132c80dc9b18bef36d4cf7a9e1fe6" }, 46 | "vim-dadbod-ui": { "branch": "master", "commit": "48c4f271da13d380592f4907e2d1d5558044e4e5" }, 47 | "vim-dispatch": { "branch": "master", "commit": "a2ff28abdb2d89725192db5b8562977d392a4d3f" }, 48 | "vim-fugitive": { "branch": "master", "commit": "61b51c09b7c9ce04e821f6cf76ea4f6f903e3cf4" }, 49 | "vim-gitgutter": { "branch": "main", "commit": "0acb772e76064cc406664ab595b58b3fac76488a" }, 50 | "vim-gnupg": { "branch": "main", "commit": "f9b608f29003dfde6450931dc0f495a912973a88" }, 51 | "vim-matchup": { "branch": "master", "commit": "1c276e12b49a83c1bdca74351187b8adea5da4b9" }, 52 | "vim-silicon": { "branch": "master", "commit": "4a93122ae2139a12e2a56f064d086c05160b6835" }, 53 | "vim-sleuth": { "branch": "master", "commit": "be69bff86754b1aa5adcbb527d7fcd1635a84080" }, 54 | "vim-test": { "branch": "master", "commit": "aa619692ff48a3cf3e6bdb893765039488d4e5f3" }, 55 | "vscode-diff.nvim": { "branch": "main", "commit": "f2c6907410161f430e3301fb170fd1d2094174aa" } 56 | } 57 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | let mapleader = " " 2 | let maplocalleader = " " 3 | set nu rnu hidden autoindent modifiable smartcase autoread 4 | set laststatus=3 5 | set splitright noswapfile hlsearch autoindent 6 | set smartindent equalalways ignorecase 7 | set softtabstop=4 8 | set tabstop=4 9 | set shiftwidth=4 10 | set expandtab 11 | set smartindent 12 | set signcolumn=yes 13 | highlight Cursor guifg=white guibg=black 14 | highlight iCursor guifg=white guibg=steelblue 15 | set wcm=9 16 | set nospell 17 | set guicursor=n-v-c:block-Cursor 18 | set guicursor+=i:ver100-iCursor 19 | set mouse= 20 | 21 | "lang en_US.UTF-8 22 | set clipboard+=unnamedplus 23 | function! IsNixOS() 24 | let l:uname_output = system('uname -a') 25 | if l:uname_output =~ 'NixOS' 26 | return 1 27 | else 28 | return 0 29 | endif 30 | endfunction 31 | if IsNixOS() 32 | set clipboard+=unnamedplus 33 | let g:netrw_browsex_viewer ='sudo mac open' 34 | let g:clipboard = { 35 | \ 'name': 'yank', 36 | \ 'copy': { 37 | \ '+': 'sudo mac pbcopy', 38 | \ '*': 'sudo mac pbcopy', 39 | \ }, 40 | \ 'paste': { 41 | \ '+': 'sudo mac pbpaste', 42 | \ '*': 'sudo mac pbpaste', 43 | \ }, 44 | \ 'cache_enabled': 0, 45 | \ } 46 | else 47 | set clipboard=unnamed 48 | endif 49 | 50 | set encoding=utf-8 51 | set wildoptions-=pum 52 | set sessionoptions="blank" 53 | " nnoremap 54 | nnoremap zz 55 | nnoremap zz 56 | nnoremap zz 57 | nnoremap zz 58 | noremap { {zz 59 | noremap } }zz 60 | imap 61 | imap 62 | " nnoremap j v:count > 0 ? "m'" . v:count . "j" : 'gj' 63 | " nnoremap k v:count > 0 ? "m'" . v:count . "k" : 'gk' 64 | if !has('nvim') 65 | syntax on 66 | let g:netrw_bufsettings = 'noma nomod rnu nobl nowrap ro' 67 | colorscheme desert 68 | let &t_SI.="\e[5 q" "SI = INSERT mode 69 | let &t_SR.="\e[4 q" "SR = REPLACE mode 70 | let &t_EI.="\e[1 q" "EI = NORMAL mode (ELSE) 71 | let g:netrw_banner = 0 72 | let g:netrw_liststyle = 3 73 | let g:netrw_browse_split = 4 74 | let g:netrw_altv = 1 75 | let g:netrw_winsize = 25 76 | noremap s s 77 | noremap v v 78 | " if not neovim 79 | " vim only 80 | if has('nvim') 81 | finish 82 | endif 83 | 84 | noremap t :Vexplore 85 | nnoremap h 86 | nnoremap j 87 | nnoremap k 88 | nnoremap l 89 | noremap - :Ntree 90 | function! FZF() abort 91 | let l:tempname = tempname() 92 | execute 'silent !fzf --multi ' . '| awk ''{ print $1":1:0" }'' > ' . fnameescape(l:tempname) 93 | try 94 | execute 'cfile ' . l:tempname 95 | redraw! 96 | finally 97 | call delete(l:tempname) 98 | endtry 99 | endfunction 100 | command! -nargs=* Files call FZF() 101 | nnoremap p :Files 102 | function! RG(args) abort 103 | let l:tempname = tempname() 104 | let l:pattern = '.' 105 | if len(a:args) > 0 106 | let l:pattern = a:args 107 | endif 108 | execute 'silent !rg --vimgrep ''' . l:pattern . ''' | fzf -m > ' . fnameescape(l:tempname) 109 | try 110 | execute 'cfile ' . l:tempname 111 | redraw! 112 | finally 113 | call delete(l:tempname) 114 | endtry 115 | endfunction 116 | command! -nargs=* Rg call RG() 117 | nnoremap P :Rg 118 | endif 119 | noremap b :ls:b 120 | 121 | let g:asyncrun_open = 6 122 | function! ToggleQuickFix() 123 | if empty(filter(getwininfo(), 'v:val.quickfix')) 124 | copen 125 | else 126 | cclose 127 | endif 128 | endfunction 129 | nnoremap :call ToggleQuickFix() 130 | nnoremap ]q :cnext 131 | nnoremap [q :cprevious 132 | nnoremap :onvsh 133 | iabbrev :w 134 | 135 | 136 | let g:myLang = 0 137 | let g:myLangList = ['en_gb','nospell'] 138 | function! MySpellLang() 139 | "loop through languages 140 | if g:myLang == 0 | let &l:spelllang = g:myLangList[g:myLang] | setlocal spell | endif 141 | if g:myLang == 1 | setlocal nospell | endif 142 | if g:myLang == 2 | let &l:spelllang = g:myLangList[g:myLang] | setlocal spell | endif 143 | echomsg 'language:' g:myLangList[g:myLang] 144 | let g:myLang = g:myLang + 1 145 | if g:myLang >= len(g:myLangList) | let g:myLang = 0 | endif 146 | endfunction 147 | map :call MySpellLang() 148 | 149 | " edit macro 150 | nnoremap mm :='let @'. v:register .' = '. string(getreg(v:register)) 151 | " User Commands 152 | command TSGDFunctionName norm 0[[$F(bzz 153 | command TSNXFunctionName norm 0]]$F(bzz 154 | command BufOnly :%bd|e# 155 | let g:gitgutter_sign_added = '│' 156 | let g:gitgutter_sign_modified = '~' 157 | let g:gitgutter_sign_removed = '_' 158 | let g:gitgutter_sign_removed_first_line = '‾' 159 | " let g:gitgutter_sign_removed_above_and_below = '{' 160 | " let g:gitgutter_sign_modified_removed = 'ww' 161 | set updatetime=100 162 | 163 | onoremap i/ :normal! T/vt/ 164 | onoremap a/ :normal! F/vf/ 165 | xnoremap i/ :normal! T/vt/ 166 | xnoremap a/ :normal! F/vf/ 167 | -------------------------------------------------------------------------------- /lua/bookmarks.lua: -------------------------------------------------------------------------------- 1 | -- local M = {} 2 | -- local Snacks = require("snacks") 3 | -- local Path = require("plenary.path") 4 | -- 5 | -- M.bookmarks = {} 6 | -- M.extmarks = {} 7 | -- M.namespace = vim.api.nvim_create_namespace("bookmarks") 8 | -- 9 | -- local function get_bookmark_file() 10 | -- local project_root = vim.fn.getcwd() 11 | -- local project_name = vim.fn.fnamemodify(project_root, ":t") 12 | -- local cache_dir = vim.fn.stdpath("cache") 13 | -- return Path:new(cache_dir, "nvim_bookmarks", project_name .. "_bookmarks.json") 14 | -- end 15 | -- 16 | -- local function save_bookmarks() 17 | -- local bookmark_file = get_bookmark_file() 18 | -- bookmark_file:parent():mkdir({ parents = true, exists_ok = true }) 19 | -- bookmark_file:write(vim.fn.json_encode(M.bookmarks), "w") 20 | -- end 21 | -- 22 | -- local function load_bookmarks() 23 | -- local bookmark_file = get_bookmark_file() 24 | -- if bookmark_file:exists() then 25 | -- local content = bookmark_file:read() 26 | -- M.bookmarks = vim.fn.json_decode(content) 27 | -- else 28 | -- M.bookmarks = {} 29 | -- end 30 | -- end 31 | -- 32 | -- local function set_extmark(bufnr, line, note) 33 | -- local id = vim.api.nvim_buf_set_extmark(bufnr, M.namespace, line - 1, -1, { 34 | -- virt_text = { { "🔖 " .. note, "Comment" } }, 35 | -- virt_text_pos = "eol", 36 | -- }) 37 | -- table.insert(M.extmarks, { id = id, bufnr = bufnr }) 38 | -- end 39 | -- 40 | -- local function update_virtual_text() 41 | -- -- 清除所有旧的 extmarks 42 | -- for _, extmark in pairs(M.extmarks) do 43 | -- pcall(vim.api.nvim_buf_del_extmark, extmark.bufnr, M.namespace, extmark.id) 44 | -- end 45 | -- M.extmarks = {} 46 | -- 47 | -- -- 为每个打开的缓冲区添加新的 virtual text 48 | -- for _, buf in ipairs(vim.api.nvim_list_bufs()) do 49 | -- if vim.api.nvim_buf_is_loaded(buf) then 50 | -- local file = vim.api.nvim_buf_get_name(buf) 51 | -- for _, bookmark in pairs(M.bookmarks) do 52 | -- if bookmark.file == file then 53 | -- set_extmark(buf, bookmark.line, bookmark.note) 54 | -- end 55 | -- end 56 | -- end 57 | -- end 58 | -- end 59 | -- 60 | -- function M.toggle_bookmark() 61 | -- load_bookmarks() 62 | -- local file = vim.fn.expand("%:p") 63 | -- local line = vim.fn.line(".") 64 | -- local key = file .. ":" .. line 65 | -- 66 | -- if M.bookmarks[key] then 67 | -- M.bookmarks[key] = nil 68 | -- else 69 | -- vim.ui.input({ prompt = "Enter bookmark note: " }, function(note) 70 | -- if note then 71 | -- M.bookmarks[key] = { file = file, line = line, note = note } 72 | -- end 73 | -- end) 74 | -- end 75 | -- save_bookmarks() 76 | -- update_virtual_text() 77 | -- end 78 | -- 79 | -- function M.apply_buffer_virtual_text() 80 | -- for _, extmark in pairs(M.extmarks) do 81 | -- pcall(vim.api.nvim_buf_del_extmark, extmark.bufnr, M.namespace, extmark.id) 82 | -- end 83 | -- 84 | -- local current_file = vim.fn.expand("%:p") 85 | -- local bufnr = vim.api.nvim_get_current_buf() 86 | -- 87 | -- -- 获取当前缓冲区的所有 extmarks 88 | -- local existing_extmarks = vim.api.nvim_buf_get_extmarks(bufnr, M.namespace, 0, -1, { details = true }) 89 | -- local extmark_lines = {} 90 | -- 91 | -- -- 创建一个查找表,用于快速检查行是否已有 extmark 92 | -- for _, extmark in ipairs(existing_extmarks) do 93 | -- extmark_lines[extmark[2] + 1] = true -- extmark 行号从 0 开始,所以要 +1 94 | -- end 95 | -- 96 | -- for _, bookmark in pairs(M.bookmarks) do 97 | -- if bookmark.file == current_file then 98 | -- -- 检查该行是否已经有 extmark 99 | -- if not extmark_lines[bookmark.line] then 100 | -- set_extmark(bufnr, bookmark.line, bookmark.note) 101 | -- end 102 | -- end 103 | -- end 104 | -- end 105 | -- 106 | -- function M.list_bookmarks() 107 | -- load_bookmarks() 108 | -- local bookmark_list = {} 109 | -- for _, bookmark in pairs(M.bookmarks) do 110 | -- local line = tonumber(bookmark.line) 111 | -- local display_path = vim.fn.fnamemodify(bookmark.file, ":~:.") 112 | -- table.insert(bookmark_list, { 113 | -- file = bookmark.file, 114 | -- line = line, 115 | -- note = bookmark.note, 116 | -- text = string.format("%s %s:%d", bookmark.note, display_path, line), 117 | -- display_path = display_path, 118 | -- pos = { line, 0 }, 119 | -- }) 120 | -- end 121 | -- 122 | -- Snacks.picker.pick("bookmarks", { 123 | -- title = "Bookmarks", 124 | -- items = bookmark_list, 125 | -- format = function(item) 126 | -- return { 127 | -- { item.note or "", "Title" }, 128 | -- { " " .. item.display_path .. ":" .. item.line, "Comment" }, 129 | -- } 130 | -- end, 131 | -- preview = "preview", 132 | -- confirm = function(picker, item) 133 | -- picker:close() 134 | -- if not item or not item.file then 135 | -- return 136 | -- end 137 | -- vim.cmd("edit " .. vim.fn.fnameescape(item.file)) 138 | -- vim.api.nvim_win_set_cursor(0, { item.line, 0 }) 139 | -- vim.schedule(M.apply_buffer_virtual_text) 140 | -- end, 141 | -- }) 142 | -- end 143 | -- 144 | -- function M.setup() 145 | -- load_bookmarks() 146 | -- update_virtual_text() 147 | -- 148 | -- --abc 149 | -- vim.cmd([[ 150 | -- augroup Bookmarks 151 | -- autocmd! 152 | -- autocmd BufRead * lua require('bookmarks').apply_buffer_virtual_text() 153 | -- autocmd BufEnter * lua require('bookmarks').apply_buffer_virtual_text() 154 | -- autocmd BufWritePost * lua require('bookmarks').apply_buffer_virtual_text() 155 | -- augroup END 156 | -- ]]) 157 | -- 158 | -- vim.api.nvim_set_keymap( 159 | -- "n", 160 | -- "mm", 161 | -- 'lua require("bookmarks").toggle_bookmark()', 162 | -- { noremap = true, silent = true } 163 | -- ) 164 | -- vim.api.nvim_set_keymap( 165 | -- "n", 166 | -- "ml", 167 | -- 'lua require("bookmarks").list_bookmarks()', 168 | -- { noremap = true, silent = true } 169 | -- ) 170 | -- end 171 | -- 172 | -- return M 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nvim-conf/ 2 | image 3 | 4 | 5 | 6 | 7 | ![](https://byob.yarr.is/xiantang/nvim-conf/startuptime) 8 | 9 | 10 | ## Install Instructions 11 | 12 | > Install requires Neovim 0.9+. Always review the code before installing a configuration. 13 | 14 | Clone the repository and install the plugins: 15 | 16 | ```sh 17 | git clone git@github.com:xiantang/nvim-conf ~/.config/xiantang/nvim-conf 18 | NVIM_APPNAME=xiantang/nvim-conf/ nvim --headless +"Lazy! sync" +qa 19 | ``` 20 | 21 | Open Neovim with this config: 22 | 23 | ```sh 24 | NVIM_APPNAME=xiantang/nvim-conf/ nvim 25 | ``` 26 | 27 | ## Plugins 28 | 29 | ### code-runner 30 | 31 | + [michaelb/sniprun](https://dotfyle.com/plugins/michaelb/sniprun) 32 | ### colorscheme 33 | 34 | + [RRethy/nvim-base16](https://dotfyle.com/plugins/RRethy/nvim-base16) 35 | + [catppuccin/nvim](https://dotfyle.com/plugins/catppuccin/nvim) 36 | + [sainnhe/sonokai](https://dotfyle.com/plugins/sainnhe/sonokai) 37 | + [xiantang/darcula-dark.nvim](https://dotfyle.com/plugins/xiantang/darcula-dark.nvim) 38 | ### comment 39 | 40 | + [numToStr/Comment.nvim](https://dotfyle.com/plugins/numToStr/Comment.nvim) 41 | ### completion 42 | 43 | + [hrsh7th/nvim-cmp](https://dotfyle.com/plugins/hrsh7th/nvim-cmp) 44 | ### cursorline 45 | 46 | + [echasnovski/mini.cursorword](https://dotfyle.com/plugins/echasnovski/mini.cursorword) 47 | ### debugging 48 | 49 | + [rcarriga/nvim-dap-ui](https://dotfyle.com/plugins/rcarriga/nvim-dap-ui) 50 | + [mfussenegger/nvim-dap](https://dotfyle.com/plugins/mfussenegger/nvim-dap) 51 | ### editing-support 52 | 53 | + [nvim-treesitter/nvim-treesitter-context](https://dotfyle.com/plugins/nvim-treesitter/nvim-treesitter-context) 54 | + [folke/zen-mode.nvim](https://dotfyle.com/plugins/folke/zen-mode.nvim) 55 | + [windwp/nvim-autopairs](https://dotfyle.com/plugins/windwp/nvim-autopairs) 56 | + [keaising/im-select.nvim](https://dotfyle.com/plugins/keaising/im-select.nvim) 57 | ### file-explorer 58 | 59 | + [stevearc/oil.nvim](https://dotfyle.com/plugins/stevearc/oil.nvim) 60 | ### fuzzy-finder 61 | 62 | + [nvim-telescope/telescope.nvim](https://dotfyle.com/plugins/nvim-telescope/telescope.nvim) 63 | ### game 64 | 65 | + [ThePrimeagen/vim-be-good](https://dotfyle.com/plugins/ThePrimeagen/vim-be-good) 66 | ### git 67 | 68 | + [lewis6991/gitsigns.nvim](https://dotfyle.com/plugins/lewis6991/gitsigns.nvim) 69 | ### golang 70 | 71 | + [ray-x/go.nvim](https://dotfyle.com/plugins/ray-x/go.nvim) 72 | ### indent 73 | 74 | + [echasnovski/mini.indentscope](https://dotfyle.com/plugins/echasnovski/mini.indentscope) 75 | + [lukas-reineke/indent-blankline.nvim](https://dotfyle.com/plugins/lukas-reineke/indent-blankline.nvim) 76 | ### keybinding 77 | 78 | + [folke/which-key.nvim](https://dotfyle.com/plugins/folke/which-key.nvim) 79 | ### lsp 80 | 81 | + [simrat39/symbols-outline.nvim](https://dotfyle.com/plugins/simrat39/symbols-outline.nvim) 82 | + [onsails/lspkind.nvim](https://dotfyle.com/plugins/onsails/lspkind.nvim) 83 | + [jose-elias-alvarez/null-ls.nvim](https://dotfyle.com/plugins/jose-elias-alvarez/null-ls.nvim) 84 | + [j-hui/fidget.nvim](https://dotfyle.com/plugins/j-hui/fidget.nvim) 85 | + [glepnir/lspsaga.nvim](https://dotfyle.com/plugins/glepnir/lspsaga.nvim) 86 | ### lsp-installer 87 | 88 | + [williamboman/mason.nvim](https://dotfyle.com/plugins/williamboman/mason.nvim) 89 | ### note-taking 90 | 91 | + [nvim-neorg/neorg](https://dotfyle.com/plugins/nvim-neorg/neorg) 92 | ### nvim-dev 93 | 94 | + [jbyuki/one-small-step-for-vimkind](https://dotfyle.com/plugins/jbyuki/one-small-step-for-vimkind) 95 | + [ray-x/guihua.lua](https://dotfyle.com/plugins/ray-x/guihua.lua) 96 | + [folke/neodev.nvim](https://dotfyle.com/plugins/folke/neodev.nvim) 97 | + [nvim-lua/plenary.nvim](https://dotfyle.com/plugins/nvim-lua/plenary.nvim) 98 | ### plugin-manager 99 | 100 | + [folke/lazy.nvim](https://dotfyle.com/plugins/folke/lazy.nvim) 101 | ### scrollbar 102 | 103 | + [petertriho/nvim-scrollbar](https://dotfyle.com/plugins/petertriho/nvim-scrollbar) 104 | ### session 105 | 106 | + [rmagatti/auto-session](https://dotfyle.com/plugins/rmagatti/auto-session) 107 | ### snippet 108 | 109 | + [L3MON4D3/LuaSnip](https://dotfyle.com/plugins/L3MON4D3/LuaSnip) 110 | ### statusline 111 | 112 | + [nvim-lualine/lualine.nvim](https://dotfyle.com/plugins/nvim-lualine/lualine.nvim) 113 | ### syntax 114 | 115 | + [kylechui/nvim-surround](https://dotfyle.com/plugins/kylechui/nvim-surround) 116 | + [nvim-treesitter/nvim-treesitter](https://dotfyle.com/plugins/nvim-treesitter/nvim-treesitter) 117 | ### tmux 118 | 119 | + [numToStr/Navigator.nvim](https://dotfyle.com/plugins/numToStr/Navigator.nvim) 120 | ### utility 121 | 122 | + [rcarriga/nvim-notify](https://dotfyle.com/plugins/rcarriga/nvim-notify) 123 | ## Language Servers 124 | 125 | + awk_ls 126 | + bashls 127 | + dockerls 128 | + gopls 129 | + jqls 130 | + jsonls 131 | + pyright 132 | + sqlls 133 | + terraformls 134 | + tsserver 135 | + vimls 136 | + yamlls 137 | 138 | 139 | This readme was generated by [Dotfyle](https://dotfyle.com) 140 | 141 | 142 | 143 | ### mini vim(without plugins) 144 | `alias vim="vim -S https://raw.githubusercontent.com/xiantang/nvim-conf/dev/.vimrc"` 145 | 146 | ### Font 147 | (FiraCode Nerd Font Mono)[https://github.com/ryanoasis/nerd-fonts/tree/master/patched-fonts/FiraCode] 148 | 149 | ### gopls 150 | use gopls build by myself https://github.com/xiantang/tools due to https://github.com/golang/go/issues/40871 151 | 152 | 153 | -------------------------------------------------------------------------------- /lua/lsp_config.lua: -------------------------------------------------------------------------------- 1 | -- vim.lsp.set_log_level("ERROR") 2 | 3 | if not (vim.lsp and vim.lsp.config and vim.lsp.enable) then 4 | vim.notify("vim.lsp.config/enable is missing (requires Neovim >= 0.11)", vim.log.levels.ERROR) 5 | return 6 | end 7 | 8 | -- fallback if lsp exit suddenly 9 | --[[ vim.api.nvim_create_autocmd("LspDetach", { 10 | callback = function(args) 11 | -- print("detaching LSP..") 12 | local bufname = vim.fn.bufname(args.buf) 13 | -- if bufname:match("%.go$") then 14 | -- print("bufname " .. bufname) 15 | -- print("restarting LSP..") 16 | vim.cmd("LspStart") 17 | -- end 18 | end, 19 | }) ]] 20 | local lsp_formatting = function(bufnr) 21 | vim.lsp.buf.format({ 22 | filter = function(client) 23 | -- apply whatever logic you want (in this example, we'll only use null-ls) 24 | return client.name == "null-ls" 25 | end, 26 | bufnr = bufnr, 27 | }) 28 | end 29 | -- if you want to set up formatting on save, you can use this as a callback 30 | local augroup = vim.api.nvim_create_augroup("LspFormatting", {}) 31 | -- get function name in body of golang function 32 | function _G.get_cur_go_func_name() 33 | -- get current line number 34 | local line = vim.api.nvim_win_get_cursor(0)[1] 35 | -- get current line 36 | local line_str = vim.api.nvim_buf_get_lines(0, line - 1, line, false)[1] 37 | -- get function name if not find, try to find in previous line 38 | -- for loop 39 | while not string.find(line_str, "func%s+([%w_]+)") do 40 | line = line - 1 41 | line_str = vim.api.nvim_buf_get_lines(0, line - 1, line, false)[1] 42 | if not line_str then 43 | return nil 44 | end 45 | end 46 | return string.match(line_str, "func%s+([%w_]+)") 47 | end 48 | 49 | local on_attach = function(client, bufnr) 50 | vim.cmd("syntax on") 51 | if client.name == "gopls" and not client.server_capabilities.semanticTokensProvider then 52 | local semantic = client.config.capabilities.textDocument.semanticTokens 53 | client.server_capabilities.semanticTokensProvider = { 54 | full = true, 55 | legend = { tokenModifiers = semantic.tokenModifiers, tokenTypes = semantic.tokenTypes }, 56 | range = true, 57 | } 58 | end 59 | local function buf_set_keymap(...) 60 | vim.api.nvim_buf_set_keymap(bufnr, ...) 61 | end 62 | 63 | local function buf_set_option(...) 64 | vim.api.nvim_buf_set_option(bufnr, ...) 65 | end 66 | 67 | -- add to your shared on_attach callback 68 | if client.supports_method("textDocument/formatting") then 69 | vim.api.nvim_clear_autocmds({ group = augroup, buffer = bufnr }) 70 | vim.api.nvim_create_autocmd("BufWritePre", { 71 | group = augroup, 72 | buffer = bufnr, 73 | callback = function() 74 | lsp_formatting(bufnr) 75 | end, 76 | }) 77 | end 78 | -- end 79 | 80 | buf_set_option("omnifunc", "v:lua.vim.lsp.omnifunc") 81 | 82 | -- cousor hold for 3 seconds, show signature helper 83 | -- silent 84 | -- vim.api.nvim_command([[autocmd CursorHold lua vim.lsp.buf.hover() ]]) 85 | -- Mappings. 86 | local opts = { noremap = true, silent = true } 87 | buf_set_keymap("n", "", "", opts) 88 | buf_set_keymap("n", "gD", "lua vim.lsp.buf.type_definition()", opts) 89 | buf_set_keymap("n", "gd", "lua vim.lsp.buf.definition()", opts) 90 | buf_set_keymap("n", "gd", "vsplit | lua vim.lsp.buf.definition()", opts) 91 | -- buf_set_keymap("n", "gv", "lua vim.lsp.buf.peek_definition()", opts) -- Note: Native LSP doesn't have peek_definition 92 | -- buf_set_keymap("n", "ga", "lua vim.lsp.buf.code_action()", opts) 93 | -- -- coode action for extract function or variable 94 | -- buf_set_keymap("v", "ga", "lua vim.lsp.bug.code_action()", opts) 95 | -- buf_set_keymap("v", "ga", "lua vim.lsp.buf.range_code_action()", opts) 96 | buf_set_keymap("n", "K", "lua vim.lsp.buf.hover()", opts) 97 | buf_set_keymap("n", "dt", "lua require('dap-go').debug_test()", opts) 98 | buf_set_keymap("n", "wa", "lua vim.lsp.buf.add_workspace_folder()", opts) 99 | buf_set_keymap("n", "wr", "lua vim.lsp.buf.remove_workspace_folder()", opts) 100 | buf_set_keymap("n", "wl", "lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))", opts) 101 | buf_set_keymap("n", "rn", "lua vim.lsp.buf.rename()", opts) 102 | vim.keymap.set("n", "gr", vim.lsp.buf.references, opts) 103 | vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts) 104 | buf_set_keymap("n", "f", ":lua vim.lsp.buf.format()", opts) 105 | -- if current buff end with _test.go, then set keymap for error 106 | local buf_name = vim.api.nvim_buf_get_name(bufnr) 107 | buf_set_keymap("n", "ge", "lua vim.diagnostic.goto_next()", opts) 108 | 109 | -- Set autocommands conditional on server_capabilities 110 | if client.server_capabilities.document_highlight then 111 | vim.api.nvim_exec( 112 | [[ 113 | hi LspReferenceRead cterm=bold ctermbg=DarkMagenta guibg=LightYellow 114 | hi LspReferenceText cterm=bold ctermbg=DarkMagenta guibg=LightYellow 115 | hi LspReferenceWrite cterm=bold ctermbg=DarkMagenta guibg=LightYellow 116 | augroup lsp_document_highlight 117 | autocmd! * 118 | autocmd CursorHold lua vim.lsp.buf.document_highlight() 119 | autocmd CursorMoved lua vim.lsp.buf.clear_references() 120 | augroup END 121 | ]], 122 | false 123 | ) 124 | end 125 | end 126 | 127 | -- auto cmd 128 | 129 | function gofumpt(timeoutms) 130 | -- get current file path 131 | local file_path = vim.api.nvim_buf_get_name(0) 132 | local command = string.format("!gofumpt -w %s", file_path) 133 | -- run cmd in background 134 | vim.cmd(command) 135 | end 136 | 137 | -- set up lspconfig 138 | 139 | local common_servers = { 140 | -- "ocamllsp", 141 | -- "awk_ls", 142 | "sqlls", 143 | "jqls", 144 | "pyright", 145 | "bashls", 146 | "vimls", 147 | "ts_ls", 148 | "yamlls", 149 | "terraformls", 150 | "rnix", 151 | } 152 | 153 | local capabilities = require("blink.cmp").get_lsp_capabilities() 154 | capabilities.textDocument.foldingRange = { 155 | dynamicRegistration = false, 156 | lineFoldingOnly = true, 157 | } 158 | capabilities.workspace = capabilities.workspace or {} 159 | capabilities.workspace.workspaceFolders = true 160 | capabilities.workspace.didChangeWatchedFiles = capabilities.workspace.didChangeWatchedFiles or {} 161 | capabilities.workspace.didChangeWatchedFiles.dynamicRegistration = true 162 | local function setup_server(server, opts) 163 | local config = vim.tbl_deep_extend("force", { 164 | flags = { 165 | allow_incremental_sync = false, 166 | debounce_text_changes = 500, 167 | }, 168 | on_attach = on_attach, 169 | capabilities = capabilities, 170 | }, opts or {}) 171 | 172 | vim.lsp.config(server, config) 173 | vim.lsp.enable(server) 174 | end 175 | 176 | for _, server in ipairs(common_servers) do 177 | setup_server(server) 178 | end 179 | 180 | setup_server("lua_ls", { 181 | settings = { 182 | Lua = { 183 | runtime = { 184 | -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) 185 | version = "LuaJIT", 186 | }, 187 | diagnostics = { 188 | -- Get the language server to recognize the `vim` global 189 | globals = { "vim", "hs" }, 190 | }, 191 | workspace = { 192 | checkThirdParty = false, 193 | -- Make the server aware of Neovim runtime files 194 | library = { 195 | -- vim.api.nvim_get_runtime_file("", true), 196 | "/Applications/Hammerspoon.app/Contents/Resources/extensions/hs/", 197 | vim.fn.expand("~/lualib/share/lua/5.4"), 198 | vim.fn.expand("~/lualib/lib/luarocks/rocks-5.4"), 199 | "/opt/homebrew/opt/openresty/lualib", 200 | }, 201 | }, 202 | -- Do not send telemetry data containing a randomized but unique identifier 203 | telemetry = { 204 | enable = false, 205 | }, 206 | }, 207 | }, 208 | }) 209 | 210 | setup_server("gopls", { 211 | cmd = { "gopls" }, 212 | settings = { 213 | gopls = { 214 | -- PAINPOINT 215 | usePlaceholders = false, 216 | -- semanticTokens = true, 217 | experimentalPostfixCompletions = true, 218 | analyses = { 219 | unusedparams = true, 220 | shadow = true, 221 | }, 222 | -- use gopls build by myself https://github.com/xiantang/tools 223 | -- staticcheck = true, 224 | expandWorkspaceToModule = true, 225 | }, 226 | }, 227 | }) 228 | 229 | vim.api.nvim_create_user_command("LspCapabilities", function() 230 | local curBuf = vim.api.nvim_get_current_buf() 231 | local clients = vim.lsp.get_active_clients({ bufnr = curBuf }) 232 | 233 | for _, client in pairs(clients) do 234 | if client.name ~= "null-ls" then 235 | local capAsList = {} 236 | for key, value in pairs(client.server_capabilities) do 237 | if value and key:find("Provider") then 238 | local capability = key:gsub("Provider$", "") 239 | table.insert(capAsList, "- " .. capability) 240 | end 241 | end 242 | table.sort(capAsList) -- sorts alphabetically 243 | local msg = "# " .. client.name .. "\n" .. table.concat(capAsList, "\n") 244 | vim.notify(msg, "trace", { 245 | on_open = function(win) 246 | local buf = vim.api.nvim_win_get_buf(win) 247 | vim.api.nvim_buf_set_option(buf, "filetype", "markdown") 248 | end, 249 | timeout = 14000, 250 | }) 251 | fn.setreg("+", "Capabilities = " .. vim.inspect(client.server_capabilities)) 252 | end 253 | end 254 | end, {}) 255 | -------------------------------------------------------------------------------- /lua/plugins/treesitter.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "nvim-treesitter/nvim-treesitter", 4 | build = ":TSUpdate", 5 | config = function() 6 | local enabled = { 7 | "java", 8 | "ruby", 9 | "lua", 10 | "vim", 11 | "bash", 12 | "go", 13 | "ssh_config", 14 | "markdown", 15 | "gomod", 16 | "gosum", 17 | "norg", 18 | "python", 19 | "yaml", 20 | "make", 21 | "gitignore", 22 | "http", 23 | "terraform", 24 | "thrift", 25 | "sql", 26 | "json", 27 | } 28 | -- local path = "/usr/local/lib/nvim/parser" 29 | -- vim.opt.runtimepath:append(path) 30 | 31 | require("nvim-treesitter.configs").setup({ 32 | -- parser_install_dir = path, 33 | 34 | -- will cause panic so I disable it 35 | incremental_selection = { 36 | enable = false, 37 | keymaps = { 38 | init_selection = true, 39 | node_incremental = "v", 40 | node_decremental = "", 41 | }, 42 | }, 43 | ensure_installed = enabled, 44 | highlight = { 45 | enable = true, 46 | }, 47 | }) 48 | 49 | local ts_utils = require("nvim-treesitter.ts_utils") 50 | 51 | local node_list = {} 52 | local current_index = nil 53 | 54 | function start_select() 55 | node_list = {} 56 | current_index = nil 57 | current_index = 1 58 | vim.cmd("normal! v") 59 | end 60 | 61 | function find_expand_node(node) 62 | local start_row, start_col, end_row, end_col = node:range() 63 | local parent = node:parent() 64 | if parent == nil then 65 | return nil 66 | end 67 | local parent_start_row, parent_start_col, parent_end_row, parent_end_col = parent:range() 68 | if 69 | start_row == parent_start_row 70 | and start_col == parent_start_col 71 | and end_row == parent_end_row 72 | and end_col == parent_end_col 73 | then 74 | return find_expand_node(parent) 75 | end 76 | return parent 77 | end 78 | 79 | function select_parent_node() 80 | if current_index == nil then 81 | return 82 | end 83 | 84 | local node = node_list[current_index - 1] 85 | local parent = nil 86 | if node == nil then 87 | parent = ts_utils.get_node_at_cursor() 88 | else 89 | parent = find_expand_node(node) 90 | end 91 | if not parent then 92 | vim.cmd("normal! gv") 93 | return 94 | end 95 | 96 | table.insert(node_list, parent) 97 | current_index = current_index + 1 98 | local start_row, start_col, end_row, end_col = parent:range() 99 | vim.fn.setpos(".", { 0, start_row + 1, start_col + 1, 0 }) 100 | vim.cmd("normal! v") 101 | vim.fn.setpos(".", { 0, end_row + 1, end_col, 0 }) 102 | end 103 | 104 | function restore_last_selection() 105 | if not current_index or current_index <= 1 then 106 | return 107 | end 108 | 109 | current_index = current_index - 1 110 | local node = node_list[current_index] 111 | local start_row, start_col, end_row, end_col = node:range() 112 | vim.fn.setpos(".", { 0, start_row + 1, start_col + 1, 0 }) 113 | vim.cmd("normal! v") 114 | vim.fn.setpos(".", { 0, end_row + 1, end_col, 0 }) 115 | end 116 | 117 | vim.api.nvim_set_keymap("n", "v", ":lua start_select()", { noremap = true, silent = true }) 118 | vim.api.nvim_set_keymap("v", "v", ":lua select_parent_node()", { noremap = true, silent = true }) 119 | vim.api.nvim_set_keymap("v", "", ":lua restore_last_selection()", { noremap = true, silent = true }) 120 | 121 | require("nvim-treesitter.configs").setup({ 122 | -- parser_install_dir = "/opt/homebrew/Cellar/neovim/0.9.2/lib/nvim/parser", 123 | textobjects = { 124 | select = { 125 | enable = true, 126 | 127 | keymaps = { 128 | -- You can use the capture groups defined in textobjects.scm 129 | ["af"] = "@function.outer", 130 | ["if"] = "@function.inner", 131 | ["ia"] = "@parameter.inner", 132 | ["aa"] = "@parameter.outer", 133 | }, 134 | }, 135 | move = { 136 | enable = true, 137 | set_jumps = true, -- whether to set jumps in the jumplist 138 | goto_next_start = { 139 | ["]m"] = "@function.outer", 140 | ["]]"] = { query = "@function.outer", desc = "Next class start" }, 141 | -- 142 | -- You can use regex matching (i.e. lua pattern) and/or pass a list in a "query" key to group multiple queires. 143 | ["]o"] = "@loop.*", 144 | -- ["]o"] = { query = { "@loop.inner", "@loop.outer" } } 145 | -- 146 | -- You can pass a query group to use query from `queries//.scm file in your runtime path. 147 | -- Below example nvim-treesitter's `locals.scm` and `folds.scm`. They also provide highlights.scm and indent.scm. 148 | ["]s"] = { query = "@scope", query_group = "locals", desc = "Next scope" }, 149 | ["]z"] = { query = "@fold", query_group = "folds", desc = "Next fold" }, 150 | }, 151 | goto_next_end = { 152 | ["]M"] = "@function.outer", 153 | ["]["] = "@class.outer", 154 | }, 155 | goto_previous_start = { 156 | ["[["] = "@function.outer", 157 | }, 158 | goto_previous_end = { 159 | ["[M"] = "@function.outer", 160 | ["[]"] = "@class.outer", 161 | }, 162 | -- Below will go to either the start or the end, whichever is closer. 163 | -- Use if you want more granular movements 164 | -- Make it even more gradual by adding multiple queries and regex. 165 | goto_next = { 166 | ["]d"] = "@conditional.outer", 167 | }, 168 | goto_previous = { 169 | ["[d"] = "@conditional.outer", 170 | }, 171 | }, 172 | }, 173 | }) 174 | local function goto_function(direction) 175 | local ts = vim.treesitter 176 | local queries = require("nvim-treesitter.query") 177 | local filetype = vim.api.nvim_buf_get_option(0, "ft") 178 | local lang = require("nvim-treesitter.parsers").ft_to_lang(filetype) 179 | 180 | -- Define Treesitter query 181 | local go_query = [[ 182 | (function_declaration 183 | name: (identifier) @function_name) 184 | (method_declaration 185 | name: (field_identifier) @function_name) 186 | ]] 187 | local query = [[ 188 | (function_declaration 189 | name: (identifier) @function_name) 190 | ]] 191 | 192 | -- Get current buffer's Treesitter syntax tree 193 | local parser = ts.get_parser(0, lang) 194 | if not parser then return end 195 | 196 | local tree = parser:parse()[1] 197 | if not tree then return end 198 | 199 | local root = tree:root() 200 | if not root then return end 201 | 202 | -- Get query object 203 | if lang == "go" then 204 | query = go_query 205 | end 206 | local query_obj = vim.treesitter.query.parse(lang, query) 207 | if not query_obj then return end 208 | 209 | -- Execute query 210 | local matches = {} 211 | for id, node in query_obj:iter_captures(root, 0) do 212 | local name = query_obj.captures[id] 213 | if name == "function_name" and node then 214 | -- Check if the node has a valid range 215 | local ok, _ = pcall(function() return node:range() end) 216 | if ok then 217 | table.insert(matches, node) 218 | end 219 | end 220 | end 221 | 222 | -- If matches found, move cursor to function name 223 | if #matches > 0 then 224 | local closest_function = nil 225 | local closest_distance = nil 226 | local row, col = unpack(vim.api.nvim_win_get_cursor(0)) 227 | row = row - 1 -- Convert to 0-indexed 228 | 229 | for _, function_name_node in ipairs(matches) do 230 | local ok, sr, sc = pcall(function() 231 | local start_row, start_col, _, _ = function_name_node:range() 232 | return start_row, start_col 233 | end) 234 | 235 | if ok and sr ~= nil then 236 | local distance = math.abs(sr - row) 237 | 238 | if direction == "prev" and (sr < row or (sr == row and sc < col)) then 239 | if closest_distance == nil or distance < closest_distance then 240 | closest_distance = distance 241 | closest_function = function_name_node 242 | end 243 | elseif direction == "next" and (sr > row or (sr == row and sc > col)) then 244 | if closest_distance == nil or distance < closest_distance then 245 | closest_distance = distance 246 | closest_function = function_name_node 247 | end 248 | end 249 | end 250 | end 251 | 252 | if closest_function then 253 | local ok, sr, sc = pcall(function() 254 | local start_row, start_col, _, _ = closest_function:range() 255 | return start_row, start_col 256 | end) 257 | 258 | if ok and sr ~= nil then 259 | vim.cmd("normal! m`") 260 | vim.api.nvim_win_set_cursor(0, { sr + 1, sc }) 261 | vim.api.nvim_feedkeys("zz", "n", false) 262 | end 263 | end 264 | end 265 | end 266 | 267 | local function goto_prev_function() 268 | goto_function("prev") 269 | end 270 | 271 | local function goto_next_function() 272 | goto_function("next") 273 | end 274 | 275 | -- 绑定键映射 276 | vim.keymap.set("n", "[f", goto_prev_function, { noremap = true, silent = true }) 277 | vim.keymap.set("n", "]f", goto_next_function, { noremap = true, silent = true }) 278 | end, 279 | }, 280 | { 281 | "nvim-treesitter/nvim-treesitter-textobjects", 282 | dependencies = { 283 | "nvim-treesitter/nvim-treesitter", 284 | }, 285 | config = function() 286 | end, 287 | }, 288 | } 289 | -------------------------------------------------------------------------------- /lua/dap_set.lua: -------------------------------------------------------------------------------- 1 | local safeRequire = require("lib").safeRequire 2 | local dap = safeRequire("dap") 3 | local dapui = safeRequire("dapui") 4 | 5 | if not dap then 6 | vim.notify("nvim-dap not available", vim.log.levels.WARN) 7 | return 8 | end 9 | 10 | if dapui then 11 | dapui.setup({ 12 | icons = { expanded = "▾", collapsed = "▸", current_frame = "▸" }, 13 | mappings = { 14 | -- Use a table to apply multiple mappings 15 | expand = { "", "<2-LeftMouse>" }, 16 | open = "o", 17 | remove = "d", 18 | edit = "e", 19 | repl = "r", 20 | toggle = "t", 21 | }, 22 | -- Expand lines larger than the window 23 | -- Requires >= 0.7 24 | expand_lines = vim.fn.has("nvim-0.7") == 1, 25 | -- Layouts define sections of the screen to place windows. 26 | -- The position can be "left", "right", "top" or "bottom". 27 | -- The size specifies the height/width depending on position. It can be an Int 28 | -- or a Float. Integer specifies height/width directly (i.e. 20 lines/columns) while 29 | -- Float value specifies percentage (i.e. 0.3 - 30% of available lines/columns) 30 | -- Elements are the elements shown in the layout (in order). 31 | -- Layouts are opened in order so that earlier layouts take priority in window sizing. 32 | layouts = { 33 | { 34 | elements = { 35 | -- Elements can be strings or table with id and size keys. 36 | { id = "scopes", size = 0.25 }, 37 | "watches", 38 | }, 39 | size = 40, -- 40 columns 40 | position = "left", 41 | }, 42 | { 43 | elements = { 44 | "repl", 45 | }, 46 | size = 0.25, -- 25% of total lines 47 | position = "bottom", 48 | }, 49 | }, 50 | controls = { 51 | -- Requires Neovim nightly (or 0.8 when released) 52 | enabled = true, 53 | -- Display controls in this element 54 | element = "repl", 55 | icons = { 56 | pause = "", 57 | play = "", 58 | step_into = "", 59 | step_over = "", 60 | step_out = "", 61 | step_back = "", 62 | run_last = "↻", 63 | terminate = "□", 64 | }, 65 | }, 66 | floating = { 67 | max_height = nil, -- These can be integers or a float between 0 and 1. 68 | max_width = nil, -- Floats will be treated as percentage of your screen. 69 | border = "single", -- Border style. Can be "single", "double" or "rounded" 70 | mappings = { 71 | close = { "q", "" }, 72 | }, 73 | }, 74 | windows = { indent = 1 }, 75 | render = { 76 | max_type_length = nil, -- Can be integer or nil. 77 | max_value_lines = 100, -- Can be integer or nil. 78 | }, 79 | }) 80 | else 81 | -- vim.notify("nvim-dap-ui not available", vim.log.levels.WARN) 82 | end 83 | dap.defaults.fallback.terminal_win_cmd = "50vsplit new" 84 | 85 | -- show the debug console 86 | dap.defaults.fallback.console = "internalConsole" 87 | 88 | dap.listeners.after["event_initialized"]["key_map"] = function() 89 | -- close nerd tree 90 | if dapui then 91 | dapui.open() 92 | end 93 | vim.api.nvim_set_keymap("n", "c", 'lua require"dap".continue()', { noremap = true, silent = true }) 94 | vim.api.nvim_set_keymap("n", "n", 'lua require"dap".step_over() | zz', { noremap = true, silent = true }) 95 | vim.api.nvim_set_keymap("n", "s", 'lua require"dap".step_into() | zz', { noremap = true, silent = true }) 96 | vim.api.nvim_set_keymap("n", "o", 'lua require"dap".step_out() | zz', { noremap = true, silent = true }) 97 | vim.api.nvim_set_keymap("n", "r", 'lua require"dap".repl.open()', { noremap = true, silent = true }) 98 | -- stop terminal 99 | vim.api.nvim_set_keymap("n", "q", 'lua require"dap".disconnect()', { noremap = true, silent = true }) 100 | end 101 | 102 | function defer() 103 | if dapui then 104 | dapui.close() 105 | end 106 | -- rollback to default keymap 107 | -- nvim_del_keymap 108 | -- source keymap.lua 109 | vim.cmd("source ~/.config/nvim/lua/keymap.lua") 110 | end 111 | 112 | dap.listeners.after["disconnected"]["key_map"] = function() 113 | defer() 114 | end 115 | 116 | dap.listeners.before["event_exited"]["key_map"] = function() 117 | defer() 118 | end 119 | 120 | -- attach stop 121 | 122 | dap.listeners.after["event_terminated"]["key_map"] = function() 123 | defer() 124 | end 125 | 126 | local function log_to_file() 127 | -- https://github.com/microsoft/debugpy/wiki/Enable-debugger-logs 128 | vim.env.DEBUGPY_LOG_DIR = vim.fn.stdpath("cache") .. "/debugpy" 129 | return true 130 | end 131 | 132 | dap.adapters.python = function(cb, config) 133 | if config.request == "attach" then 134 | ---@diagnostic disable-next-line: undefined-field 135 | local port = (config.connect or config).port 136 | ---@diagnostic disable-next-line: undefined-field 137 | local host = (config.connect or config).host or "127.0.0.1" 138 | cb({ 139 | type = "server", 140 | port = assert(port, "`connect.port` is required for a python `attach` configuration"), 141 | host = host, 142 | options = { 143 | source_filetype = "python", 144 | }, 145 | }) 146 | else 147 | cb({ 148 | type = "executable", 149 | command = "python", 150 | args = { "-m", "debugpy.adapter" }, 151 | options = { 152 | source_filetype = "python", 153 | }, 154 | }) 155 | end 156 | end 157 | 158 | local prev_function_node = nil 159 | local prev_function_name = "" 160 | 161 | -- < Retrieve the name of the function the cursor is in. 162 | function _G.function_surrounding_cursor() 163 | local ts_utils = safeRequire("nvim-treesitter.ts_utils") 164 | if not ts_utils then 165 | return "" 166 | end 167 | local current_node = ts_utils.get_node_at_cursor() 168 | 169 | if not current_node then 170 | return "" 171 | end 172 | 173 | local func = current_node 174 | 175 | while func do 176 | if func:type() == "function_definition" or func:type() == "function_declaration" then 177 | break 178 | end 179 | 180 | func = func:parent() 181 | end 182 | 183 | if not func then 184 | prev_function_node = nil 185 | prev_function_name = "" 186 | return "" 187 | end 188 | 189 | if func == prev_function_node then 190 | return prev_function_name 191 | end 192 | 193 | prev_function_node = func 194 | 195 | local find_name 196 | find_name = function(node) 197 | for i = 0, node:named_child_count() - 1, 1 do 198 | local child = node:named_child(i) 199 | local type = child:type() 200 | 201 | if type == "identifier" or type == "operator_name" then 202 | return (ts_utils.get_node_text(child))[1] 203 | else 204 | local name = find_name(child) 205 | 206 | if name then 207 | return name 208 | end 209 | end 210 | end 211 | 212 | return nil 213 | end 214 | 215 | prev_function_name = find_name(func) 216 | return prev_function_name 217 | end 218 | 219 | local prev_class_node = nil 220 | local prev_class_name = "" 221 | 222 | function _G.class_surrounding_cursor() 223 | local ts_utils = safeRequire("nvim-treesitter.ts_utils") 224 | if not ts_utils then 225 | return "" 226 | end 227 | local current_node = ts_utils.get_node_at_cursor() 228 | 229 | if not current_node then 230 | return "" 231 | end 232 | 233 | local func = current_node 234 | 235 | while func do 236 | if func:type() == "class_definition" or func:type() == "class_declaration" then 237 | break 238 | end 239 | 240 | func = func:parent() 241 | end 242 | 243 | if not func then 244 | prev_class_node = nil 245 | prev_class_name = "" 246 | return "" 247 | end 248 | 249 | if func == prev_class_node then 250 | return prev_class_name 251 | end 252 | 253 | prev_class_node = func 254 | 255 | local find_name 256 | find_name = function(node) 257 | for i = 0, node:named_child_count() - 1, 1 do 258 | local child = node:named_child(i) 259 | local type = child:type() 260 | 261 | if type == "identifier" or type == "operator_name" then 262 | return (ts_utils.get_node_text(child))[1] 263 | else 264 | local name = find_name(child) 265 | 266 | if name then 267 | return name 268 | end 269 | end 270 | end 271 | 272 | return nil 273 | end 274 | 275 | prev_class_name = find_name(func) 276 | return prev_class_name 277 | end 278 | dap.set_log_level("TRACE") 279 | 280 | local function get_module_path() 281 | return vim.fn.expand("%:.:r:gs?/?.?") 282 | end 283 | local function prune_nil(items) 284 | return vim.tbl_filter(function(x) 285 | return x 286 | end, items) 287 | end 288 | 289 | dap.configurations.python = { 290 | { 291 | type = "python", 292 | request = "launch", 293 | name = "Launch file", 294 | justMyCode = false, 295 | program = "${file}", 296 | logToFile = log_to_file, 297 | pythonPath = function() 298 | return "/opt/homebrew/bin/python3" 299 | end, 300 | }, 301 | { 302 | type = "python", 303 | request = "attach", 304 | name = "Attach remote", 305 | connect = function() 306 | local host = vim.fn.input("Host [127.0.0.1]: ") 307 | host = host ~= "" and host or "127.0.0.1" 308 | local port = tonumber(vim.fn.input("Port [5678]: ")) or 5678 309 | return { host = host, port = port } 310 | end, 311 | }, 312 | { 313 | type = "python", 314 | request = "launch", 315 | name = "Debug test function", 316 | module = "unittest", 317 | args = function() 318 | local path = get_module_path() 319 | local classname = class_surrounding_cursor() 320 | local function_name = function_surrounding_cursor() 321 | local test_path = table.concat(prune_nil({ path, classname, function_name }), ".") 322 | return { 323 | "-v", 324 | test_path, 325 | } 326 | end, 327 | console = "integratedTerminal", 328 | justMyCode = false, 329 | logToFile = log_to_file, 330 | pythonPath = function() 331 | return "/opt/homebrew/bin/python3" 332 | end, 333 | }, 334 | } 335 | 336 | dap.adapters.bashdb = { 337 | type = "executable", 338 | command = vim.fn.stdpath("data") .. "/mason/packages/bash-debug-adapter/bash-debug-adapter", 339 | name = "bashdb", 340 | pathBash = "/opt/homebrew/bin/bash", 341 | } 342 | 343 | dap.configurations.sh = { 344 | { 345 | type = "bashdb", 346 | request = "launch", 347 | name = "Launch file", 348 | showDebugOutput = true, 349 | pathBashdb = vim.fn.stdpath("data") .. "/mason/packages/bash-debug-adapter/extension/bashdb_dir/bashdb", 350 | pathBashdbLib = vim.fn.stdpath("data") .. "/mason/packages/bash-debug-adapter/extension/bashdb_dir", 351 | trace = true, 352 | file = "${file}", 353 | program = "${file}", 354 | cwd = "${workspaceFolder}", 355 | pathCat = "cat", 356 | pathBash = "/opt/homebrew/bin/bash", 357 | pathMkfifo = "/usr/bin/mkfifo", 358 | pathPkill = "/usr/bin/pkill", 359 | args = {}, 360 | env = {}, 361 | terminalKind = "integrated", 362 | }, 363 | } 364 | -------------------------------------------------------------------------------- /lua/plugins/misc.lua: -------------------------------------------------------------------------------- 1 | -- Expand 'cc' into 'CodeCompanion' in the command line 2 | vim.cmd([[cab cc CodeCompanion]]) 3 | vim.g.codecompanion_auto_tool_mode = true 4 | 5 | return { 6 | { 7 | "NickvanDyke/opencode.nvim", 8 | dependencies = { 9 | -- Recommended for `ask()` and `select()`. 10 | -- Required for `snacks` provider. 11 | ---@module 'snacks' <- Loads `snacks.nvim` types for configuration intellisense. 12 | { "folke/snacks.nvim", opts = { input = {}, picker = {}, terminal = {} } }, 13 | }, 14 | config = function() 15 | ---@type opencode.Opts 16 | vim.g.opencode_opts = { 17 | provider = { 18 | enabled = "tmux", 19 | }, 20 | -- Your configuration, if any — see `lua/opencode/config.lua`, or "goto definition". 21 | } 22 | 23 | -- Required for `opts.events.reload`. 24 | vim.o.autoread = true 25 | 26 | -- Recommended/example keymaps. 27 | vim.keymap.set({ "n", "x" }, "", function() 28 | require("opencode").ask("@this: ", { submit = true }) 29 | end, { desc = "Ask opencode" }) 30 | vim.keymap.set({ "n", "x" }, "", function() 31 | require("opencode").select() 32 | end, { desc = "Execute opencode action…" }) 33 | vim.keymap.set({ "n", "t" }, "", function() 34 | require("opencode").toggle() 35 | end, { desc = "Toggle opencode" }) 36 | 37 | vim.keymap.set({ "n", "x" }, "go", function() 38 | return require("opencode").operator("@this ") 39 | end, { expr = true, desc = "Add range to opencode" }) 40 | vim.keymap.set("n", "goo", function() 41 | return require("opencode").operator("@this ") .. "_" 42 | end, { expr = true, desc = "Add line to opencode" }) 43 | 44 | vim.keymap.set("n", "", function() 45 | require("opencode").command("session.half.page.up") 46 | end, { desc = "opencode half page up" }) 47 | vim.keymap.set("n", "", function() 48 | require("opencode").command("session.half.page.down") 49 | end, { desc = "opencode half page down" }) 50 | 51 | -- You may want these if you stick with the opinionated "" and "" above — otherwise consider "o". 52 | vim.keymap.set("n", "+", "", { desc = "Increment", noremap = true }) 53 | vim.keymap.set("n", "-", "", { desc = "Decrement", noremap = true }) 54 | end, 55 | }, 56 | { 57 | "esmuellert/vscode-diff.nvim", 58 | dependencies = { "MunifTanjim/nui.nvim" }, 59 | keys = { 60 | { "d", ":CodeDiff" }, 61 | }, 62 | cmd = "CodeDiff", 63 | config = function() 64 | require("vscode-diff").setup({ 65 | -- Highlight configuration 66 | highlights = { 67 | line_insert = "#334043", 68 | line_delete = "#473145", 69 | char_insert = "#465d60", 70 | char_delete = "#473144", 71 | char_brightness = 1.4, 72 | }, 73 | 74 | -- Diff view behavior 75 | diff = { 76 | disable_inlay_hints = true, -- Disable inlay hints in diff windows for cleaner view 77 | max_computation_time_ms = 5000, -- Maximum time for diff computation (VSCode default) 78 | }, 79 | 80 | -- Keymaps in diff view 81 | keymaps = { 82 | view = { 83 | quit = "q", -- Close diff tab 84 | toggle_explorer = "b", -- Toggle explorer visibility (explorer mode only) 85 | next_hunk = "]c", -- Jump to next change 86 | prev_hunk = "[c", -- Jump to previous change 87 | next_file = "]f", -- Next file in explorer mode 88 | prev_file = "[f", -- Previous file in explorer mode 89 | }, 90 | explorer = { 91 | select = "", -- Open diff for selected file 92 | hover = "K", -- Show file diff preview 93 | refresh = "R", -- Refresh git status 94 | }, 95 | }, 96 | }) 97 | end, 98 | }, 99 | { "nvim-lua/plenary.nvim" }, 100 | { 101 | "abecodes/tabout.nvim", 102 | lazy = false, 103 | config = function() 104 | require("tabout").setup({ 105 | tabkey = "", -- key to trigger tabout, set to an empty string to disable 106 | backwards_tabkey = "", -- key to trigger backwards tabout, set to an empty string to disable 107 | act_as_tab = true, -- shift content if tab out is not possible 108 | act_as_shift_tab = false, -- reverse shift content if tab out is not possible (if your keyboard/terminal supports ) 109 | default_tab = "", -- shift default action (only at the beginning of a line, otherwise is used) 110 | default_shift_tab = "", -- reverse shift default action, 111 | enable_backwards = true, -- well ... 112 | completion = false, -- if the tabkey is used in a completion pum 113 | tabouts = { 114 | { open = "'", close = "'" }, 115 | { open = '"', close = '"' }, 116 | { open = "`", close = "`" }, 117 | { open = "(", close = ")" }, 118 | { open = "[", close = "]" }, 119 | { open = "{", close = "}" }, 120 | }, 121 | ignore_beginning = true, --[[ if the cursor is at the beginning of a filled element it will rather tab out than shift the content ]] 122 | exclude = {}, -- tabout will ignore these filetypes 123 | }) 124 | end, 125 | dependencies = { -- These are optional 126 | "nvim-treesitter/nvim-treesitter", 127 | "L3MON4D3/LuaSnip", 128 | }, 129 | opt = true, -- Set this to true if the plugin is optional 130 | event = "InsertCharPre", -- Set the event to 'InsertCharPre' for better compatibility 131 | priority = 1000, 132 | }, 133 | { 134 | "folke/snacks.nvim", 135 | priority = 1000, 136 | lazy = false, 137 | init = function() 138 | local function setup_gbrowse() 139 | -- Override Fugitive's GBrowse to funnel through snacks.gitbrowse 140 | vim.api.nvim_create_user_command("GBrowse", function(cmd) 141 | local opts = { 142 | what = cmd.args ~= "" and cmd.args or "permalink", 143 | line_start = cmd.range ~= 0 and cmd.line1 or nil, 144 | line_end = cmd.range ~= 0 and cmd.line2 or nil, 145 | } 146 | 147 | if cmd.bang then 148 | opts.open = function(url) 149 | vim.fn.setreg("+", url) 150 | vim.notify("Copied Git URL to clipboard", vim.log.levels.INFO) 151 | end 152 | end 153 | 154 | Snacks.gitbrowse(opts) 155 | end, { range = true, nargs = "?", bang = true, desc = "Git Browse (permalink)", force = true }) 156 | end 157 | 158 | setup_gbrowse() 159 | vim.api.nvim_create_autocmd("User", { 160 | pattern = "VeryLazy", 161 | callback = setup_gbrowse, 162 | }) 163 | 164 | -- LSP progress notifications via Snacks' notifier 165 | local progress = vim.defaulttable() 166 | vim.api.nvim_create_autocmd("LspProgress", { 167 | ---@param ev {data: {client_id: integer, params: lsp.ProgressParams}} 168 | callback = function(ev) 169 | local client = vim.lsp.get_client_by_id(ev.data.client_id) 170 | local value = ev.data.params.value 171 | if not client or type(value) ~= "table" then 172 | return 173 | end 174 | local p = progress[client.id] 175 | 176 | for i = 1, #p + 1 do 177 | if i == #p + 1 or p[i].token == ev.data.params.token then 178 | p[i] = { 179 | token = ev.data.params.token, 180 | msg = ("[%3d%%] %s%s"):format( 181 | value.kind == "end" and 100 or value.percentage or 100, 182 | value.title or "", 183 | value.message and (" **%s**"):format(value.message) or "" 184 | ), 185 | done = value.kind == "end", 186 | } 187 | break 188 | end 189 | end 190 | 191 | local msg = {} ---@type string[] 192 | progress[client.id] = vim.tbl_filter(function(v) 193 | return table.insert(msg, v.msg) or not v.done 194 | end, p) 195 | 196 | local spinner = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" } 197 | vim.notify(table.concat(msg, "\n"), "info", { 198 | id = "lsp_progress", 199 | title = client.name, 200 | opts = function(notif) 201 | notif.icon = #progress[client.id] == 0 and " " 202 | or spinner[math.floor(vim.uv.hrtime() / (1e6 * 80)) % #spinner + 1] 203 | end, 204 | }) 205 | end, 206 | }) 207 | end, 208 | keys = { 209 | { 210 | ".", 211 | function() 212 | Snacks.scratch() 213 | end, 214 | desc = "Toggle Scratch Buffer", 215 | }, 216 | { 217 | "z", 218 | function() 219 | Snacks.zen() 220 | end, 221 | desc = "zen mode", 222 | }, 223 | { 224 | "b", 225 | function() 226 | Snacks.picker.buffers() 227 | end, 228 | desc = "Switch Buffer", 229 | }, 230 | { 231 | "fh", 232 | function() 233 | Snacks.picker.help() 234 | end, 235 | desc = "Help tags", 236 | }, 237 | { 238 | "tb", 239 | function() 240 | Snacks.picker.git_branches() 241 | end, 242 | desc = "Git branches", 243 | }, 244 | { 245 | "p", 246 | function() 247 | Snacks.picker.files() 248 | end, 249 | desc = "Find files", 250 | }, 251 | { 252 | "rs", 253 | function() 254 | Snacks.picker.resume() 255 | end, 256 | desc = "Resume picker", 257 | }, 258 | { 259 | "o", 260 | function() 261 | Snacks.picker.lsp_symbols() 262 | end, 263 | desc = "Document symbols", 264 | }, 265 | { 266 | "P", 267 | function() 268 | Snacks.picker.grep() 269 | end, 270 | desc = "Live grep", 271 | }, 272 | { 273 | "gB", 274 | function() 275 | local mode = vim.fn.mode() 276 | local is_visual = mode == "v" or mode == "V" or mode == "\22" 277 | local opts = { what = "permalink" } 278 | 279 | if is_visual then 280 | opts.line_start = vim.fn.line("'<") 281 | opts.line_end = vim.fn.line("'>") 282 | opts.open = function(url) 283 | vim.fn.setreg("+", url) 284 | vim.notify("Copied Git URL to clipboard", vim.log.levels.INFO) 285 | end 286 | end 287 | 288 | Snacks.gitbrowse(opts) 289 | end, 290 | mode = { "n", "v" }, 291 | desc = "Git Browse (permalink)", 292 | }, 293 | }, 294 | opts = { 295 | -- your configuration comes here 296 | -- or leave it empty to use the default settings 297 | -- refer to the configuration section below 298 | picker = { 299 | sources = { 300 | files = { 301 | hidden = true, 302 | ignored = false, 303 | exclude = { ".git/*", "node_modules/*", ".venv/*" }, 304 | }, 305 | grep = { 306 | hidden = true, 307 | ignored = false, 308 | exclude = { ".git/*", "node_modules/*", ".venv/*" }, 309 | }, 310 | buffers = { 311 | hidden = true, 312 | unloaded = true, 313 | current = false, 314 | sort_lastused = true, 315 | }, 316 | }, 317 | }, 318 | indent = { 319 | -- your indent configuration comes here 320 | -- or leave it empty to use the default settings 321 | -- refer to the configuration section below 322 | enabled = false, 323 | }, 324 | bigfile = { enabled = true }, 325 | quickfile = { enabled = true }, 326 | statuscolumn = { enabled = true }, 327 | words = { enabled = false }, 328 | gitbrowse = { 329 | what = "permalink", 330 | url_patterns = (function() 331 | local ok, secret = pcall(require, "secret") 332 | local domain = ok and secret.GITALB_URL 333 | local patterns = { 334 | [domain] = { 335 | branch = "/tree/{branch}?ref_type=commits", 336 | file = "/blob/{branch}/{file}?ref_type=commits#L{line_start}-{line_end}", 337 | permalink = "/blob/{commit}/{file}?ref_type=commits#L{line_start}-{line_end}", 338 | commit = "/commit/{commit}?ref_type=commits", 339 | }, 340 | } 341 | 342 | return patterns 343 | end)(), 344 | }, 345 | notifier = { 346 | enabled = true, 347 | }, 348 | }, 349 | }, 350 | { 351 | "jamessan/vim-gnupg", 352 | ft = { "gpg", "pgp", "asc" }, 353 | }, 354 | } 355 | --------------------------------------------------------------------------------