[
  {
    "path": ".gitignore",
    "content": "# ignore all personal configs I don't want to ship with this config:\n**/*personal.lua\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2024 Seongmin Lee\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# NativeVim\n\n![preview](https://github.com/boltlessengineer/nativevim/assets/60088301/7d0c6841-6e4c-43e0-8982-dc58328f484c)\n\n> NativeVim is a Neovim config without plugins\n\nNativeVim is **not**:\n- a distro[^1]\n- a plugin/package\n- or something that tries to reinvent famous plugins\n\nNativeVim **doesn't** include:\n- a package manager (e.g. `lazy.nvim` or `rocks.nvim`)\n- famous plugins like `nvim-lspconfig`, `nvim-cmp` and `nvim-treesitter`\n- and any other vim/neovim plugins\n\nNativeVim has features like:\n\n- basic LSP functionalities\n- TreeSitter Highlighting\n- completions\n\nand more!\n\n> [!CAUTION]\n> Since this config was developed to demonstrate the most native method, it may be slower or lack features than other configs.\n\n## Why?\n\nThis is an academical project to see if I can write Neovim config from scratch without any external plugins.\nSo people can understand the Neovim plugin ecosystem more and know what exact plugins they really need.\n\n> [!NOTE]\n> I'm not saying \"you don't need any of those plugins\". Most plugins out there have their own reasons to be used.\n> But if you're curious about the solution without them, this project is for you.\n\n## Requirement\n\n- Neovim v0.11+\n\n## How to use\n\nNativeVim doesn't support any plugin manager by default.\nJust clone it to `~/.config/nativevim` and use with `NVIM_APPNAME` environment variable.\n\n```sh\n# 1. clone it\ngit clone https://github.com/boltlessengineer/nativevim.git ~/.config/nativevim\n\n# 2. use it with NVIM_APPNAME\nNVIM_APPNAME=nativevim nvim\n```\n\n> [!NOTE]\n> NativeVim is just a Neovim config template designed to be read. It's just ~200 lines of lua code.\n> Take some time and read through the entire codebase to see how it works.\n> Feel free to open an issue if you have a different opinion about default config.\n\n## Lines of Code\n\n```\n--------------------------------------------------------------------------------\n Language             Files        Lines        Blank      Comment         Code\n--------------------------------------------------------------------------------\n Lua                      9          235           45           72          118\n Markdown                 1           69           21            0           48\n--------------------------------------------------------------------------------\n Total                   10          304           66           72          166\n--------------------------------------------------------------------------------\n```\n\n[^1]: unless you call [kickstart.nvim] a Neovim distro\n\n[kickstart.nvim]: https://github.com/nvim-lua/kickstart.nvim\n"
  },
  {
    "path": "init.lua",
    "content": "if vim.fn.has(\"nvim-0.11\") == 0 then\n    vim.notify(\"NativeVim only supports Neovim 0.11+\", vim.log.levels.ERROR)\n    return\nend\n\nrequire(\"core.options\")\nrequire(\"core.treesitter\")\nrequire(\"core.lsp\")\nrequire(\"core.statusline\")\n"
  },
  {
    "path": "lsp/gopls.lua",
    "content": "---@type vim.lsp.Config\nreturn {\n    cmd = { \"gopls\" },\n    root_markers = { \"go.work\", \"go.mod\", \".git\" },\n    filetypes = { \"go\", \"gomod\", \"gowork\", \"gotmpl\" },\n}\n"
  },
  {
    "path": "lsp/lua_ls.lua",
    "content": "---@type vim.lsp.Config\nreturn {\n    cmd = { \"lua-language-server\" },\n    root_markers = { \".luarc.json\", \".luarc.jsonc\", \".luacheckrc\", \".stylua.toml\", \"stylua.toml\", \"selene.toml\", \"selene.yml\", \".git\" },\n    filetypes = { \"lua\" },\n    on_init = require(\"util\").lua_ls_on_init,\n}\n"
  },
  {
    "path": "lsp/ts_ls.lua",
    "content": "---@type vim.lsp.Config\nreturn {\n    cmd = { \"typescript-language-server\", \"--stdio\" },\n    root_markers = { \"tsconfig.json\", \"jsconfig.json\", \"package.json\", \".git\" },\n    filetypes = { \"javascript\", \"javascriptreact\", \"javascript.jsx\", \"typescript\", \"typescriptreact\", \"typescript.tsx\" },\n    init_options = {\n        hostInfo = \"neovim\",\n    },\n}\n"
  },
  {
    "path": "lua/core/lsp.lua",
    "content": "-- :h lsp-config\n\n-- enable lsp completion\nvim.api.nvim_create_autocmd(\"LspAttach\", {\n    group = vim.api.nvim_create_augroup(\"UserLspAttach\", { clear = true }),\n    callback = function(ev)\n        vim.lsp.completion.enable(true, ev.data.client_id, ev.buf)\n    end,\n})\n\n-- enable configured language servers\n-- you can find server configurations from lsp/*.lua files\nvim.lsp.enable('gopls')\nvim.lsp.enable('lua_ls')\nvim.lsp.enable('ts_ls')\n"
  },
  {
    "path": "lua/core/options.lua",
    "content": "-- general options\nvim.o.completeopt = \"menu,menuone,popup,fuzzy\" -- modern completion menu\n\nvim.o.foldenable = true   -- enable fold\nvim.o.foldlevel = 99      -- start editing with all folds opened\nvim.o.foldmethod = \"expr\" -- use tree-sitter for folding method\nvim.o.foldexpr = \"v:lua.vim.treesitter.foldexpr()\"\n\n\n-- NOTE: Setting vim options can be opinionated.\n-- While options above are crucial to make this whole config work as expected,\n-- below are just list of options I think most users will satisfy.\n-- Feel free to modify as your preference.\n\n\nvim.o.termguicolors = true  -- enable rgb colors\n\nvim.o.cursorline = true     -- enable cursor line\n\nvim.o.number = true         -- enable line number\nvim.o.relativenumber = true -- and relative line number\n\nvim.o.signcolumn = \"yes\"    -- always show sign column\n\nvim.o.pumheight = 10        -- max height of completion menu\n\nvim.o.list = true           -- use special characters to represent things like tabs or trailing spaces\nvim.opt.listchars = {       -- NOTE: using `vim.opt` instead of `vim.o` to pass rich object\n    tab = \"▏ \",\n    trail = \"·\",\n    extends = \"»\",\n    precedes = \"«\",\n}\n\nvim.opt.diffopt:append(\"linematch:60\") -- second stage diff to align lines\n\nvim.o.confirm = true     -- show dialog for unsaved file(s) before quit\nvim.o.updatetime = 200   -- save swap file with 200ms debouncing\n\nvim.o.ignorecase = true  -- case-insensitive search\nvim.o.smartcase = true   -- , until search pattern contains upper case characters\n\nvim.o.smartindent = true -- auto-indenting when starting a new line\nvim.o.shiftround = true  -- round indent to multiple of 'shiftwidth'\nvim.o.shiftwidth = 0     -- 0 to follow the 'tabstop' value\nvim.o.tabstop = 4        -- tab width\n\nvim.o.undofile = true    -- enable persistent undo\nvim.o.undolevels = 10000 -- 10x more undo levels\n\n\n-- define <leader> and <localleader> keys\n-- you should use `vim.keycode` to translate keycodes or pass raw keycode values like `\" \"` instead of just `\"<space>\"`\nvim.g.mapleader = vim.keycode(\"<space>\")\nvim.g.maplocalleader = vim.keycode(\"<cr>\")\n\n-- remove netrw banner for cleaner looking\nvim.g.netrw_banner = 0\n"
  },
  {
    "path": "lua/core/statusline.lua",
    "content": "--[[ :h 'statusline'\nThis is default statusline value:\n\n```lua\nvim.o.statusline = \"%f %h%w%m%r%=%-14.(%l,%c%V%) %P\"\n```\n\nbelow is simple example of custom statusline using neovim APIs\n\nSee `:h 'statusline'` for more information about statusline.\n]]\n\n---Show attached LSP clients in `[name1, name2]` format.\n---Long server names will be modified. For example, `lua-language-server` will be shorten to `lua-ls`\n---Returns an empty string if there aren't any attached LSP clients.\n---@return string\nlocal function lsp_status()\n    local attached_clients = vim.lsp.get_clients({ bufnr = 0 })\n    if #attached_clients == 0 then\n        return \"\"\n    end\n    local names = vim.iter(attached_clients)\n        :map(function(client)\n            local name = client.name:gsub(\"language.server\", \"ls\")\n            return name\n        end)\n        :totable()\n    return \"[\" .. table.concat(names, \", \") .. \"]\"\nend\n\nfunction _G.statusline()\n    return table.concat({\n        \"%f\",\n        \"%h%w%m%r\",\n        \"%=\",\n        lsp_status(),\n        \" %-14(%l,%c%V%)\",\n        \"%P\",\n    }, \" \")\nend\n\nvim.o.statusline = \"%{%v:lua._G.statusline()%}\"\n"
  },
  {
    "path": "lua/core/treesitter.lua",
    "content": "--[[\n# How to install tree-sitter parsers manually?\n\nThere are two ways to install tree-sitter parsers\n\n- download from git repository\n    1. download parser to `'runtimepath'` from git repository (e.g. clone <https://github.com/serenadeai/tree-sitter-rust> to `~/.local/share/nvim/site/pack/*/start/tree-sitter-rust`)\n    2. write needed queries manually (e.g. `highlights.scm`, `folds.scm`)\n- install with luarocks\n    1. install parser with luarocks (e.g. `tree-sitter-css`)\n    2. add installed path to `'runtimepath'`\n\nFirst way is how `nvim-treesitter`'s `:TSInstall rust` works. `nvim-treesitter` also includes all needed queries for supported languages at this point (09-Jul-2024.)\n\nIf we do all manually, second way is more convenient because we don't need to manually write all needed queries for each languages.\n\n## 1. install parser with luarocks\n\n```console\nluarocks \\\n    --lua-version=5.1 \\\n    --tree=$HOME/.local/share/nvim/rocks \\\n    install tree-sitter-rust\n```\n\nWe need to specify local install path with `--tree` flag. Here, we are using `rocks` folder in `stdpath(\"data\")` (see `:h $XDG_DATA_HOME`.)\n\n## 2. add installed rock to `'packpath'`\n\nInstalled parser will be in `~/.local/share/nvim/rocks/lib/luarocks/rocks-5.1/tree-sitter-rust/0.0.27-1` where `0.0.27-1` is the installed version.\n\nAdd this path to `'packpath'` so that Neovim can recognize and register the parser and bundled queries.\n\n```console\n# create target packpath directory (`treesitter` is arbitrary)\nmkdir -p $HOME/.local/share/nvim/site/pack/treesitter/start\n\n# symlink installed rock to packpath\nln -sf $HOME/.local/share/nvim/rocks/lib/luarocks/rocks-5.1/tree-sitter-rust/0.0.27-1 $HOME/.local/share/nvim/site/pack/treesitter/start/tree-sitter-rust\n```\n\n## 3. start the parser in `FileType` AutoCommand\n\n```lua\nvim.api.nvim_create_autocmd(\"FileType\", {\n    callback = function(ev)\n        pcall(vim.treesitter.start)\n    end\n})\n```\n\nAdd this code in your config. Reopen the editor, and you are done.\n--]]\n\nvim.api.nvim_create_autocmd(\"FileType\", {\n    callback = function()\n        pcall(vim.treesitter.start)\n    end\n})\n"
  },
  {
    "path": "lua/util.lua",
    "content": "local M = {}\n\nfunction M.lua_ls_on_init(client)\n    local path = vim.tbl_get(client, \"workspace_folders\", 1, \"name\")\n    if not path then\n        return\n    end\n    -- override the lua-language-server settings for Neovim config\n    client.settings = vim.tbl_deep_extend('force', client.settings, {\n        Lua = {\n            runtime = {\n                version = 'LuaJIT'\n            },\n            -- Make the server aware of Neovim runtime files\n            workspace = {\n                checkThirdParty = false,\n                library = {\n                    vim.env.VIMRUNTIME\n                    -- Depending on the usage, you might want to add additional paths here.\n                    -- \"${3rd}/luv/library\"\n                    -- \"${3rd}/busted/library\",\n                }\n                -- or pull in all of 'runtimepath'. NOTE: this is a lot slower\n                -- library = vim.api.nvim_get_runtime_file(\"\", true)\n            }\n        }\n    })\nend\n\nreturn M\n"
  }
]