Compare commits

...

28 Commits

Author SHA1 Message Date
2c8524df9d fix finder highlight in grep 2026-02-03 11:12:59 +02:00
b84e46bda1 add helm lsp 2026-01-31 05:30:42 +02:00
65680cb255 add readme and yaml spec 2026-01-29 02:11:31 +02:00
f54bbc5676 finder fixed char render 2026-01-29 01:18:33 +02:00
70486dda84 create highlight group for filename in finder grep 2026-01-27 01:02:50 +02:00
d7122e9345 fix bugs in finder: stale cache, order results 2026-01-27 01:01:01 +02:00
2fdabfb056 add relative numbers and gitignore files in filetree 2026-01-27 00:36:14 +02:00
1b0b2ad50c feat: whitespace/indent markers 2026-01-20 08:09:27 +02:00
4419f2e5f3 markdown theme 2025-11-06 14:11:22 +02:00
efa84c2ee3 update 2025-11-03 06:26:00 +02:00
8687a1cf31 fix: rever mouse vert scroll 2025-10-26 15:33:01 +02:00
7f10891dcd feat: paq sync command 2025-10-26 09:14:51 +02:00
84dd394f31 fix/finder (#2)
Reviewed-on: #2
Co-authored-by: Tomas Mirchev <contact@tomastm.com>
Co-committed-by: Tomas Mirchev <contact@tomastm.com>
2025-10-26 06:35:47 +00:00
be67d7a67a feat: terminal events 2025-10-26 06:31:49 +02:00
3075a218b8 feat/pack (#1)
Reviewed-on: #1
Co-authored-by: Tomas Mirchev <contact@tomastm.com>
Co-committed-by: Tomas Mirchev <contact@tomastm.com>
2025-10-26 04:18:14 +00:00
2b1b3ebbf0 feat: language-manager 2025-10-24 02:21:21 +03:00
9bca643408 feat: tailwindcss 2025-10-23 20:44:51 +03:00
173ff5e47a feat: lsp 2025-10-23 20:16:45 +03:00
bb12a11cc0 feat: lazy, mason, ts 2025-10-23 05:08:38 +03:00
08c5a0536e mend 2025-10-22 17:57:07 +03:00
65ef4a6828 feat: markdown formatter 2025-10-22 17:53:14 +03:00
77d4250057 refactor: unify syntax langs 2025-10-22 17:17:24 +03:00
bcbd5c9faa update nvim-tree to fork 2025-10-22 03:10:12 +03:00
d7525c88d4 feat: new keymaps 2025-10-22 02:58:18 +03:00
804832e0c3 feat: tabline 2025-10-20 22:41:03 +03:00
d4ec924088 update lazy-lock 2025-10-20 21:31:29 +03:00
6cf0a92d91 fix: remove dev load 2025-10-20 21:28:16 +03:00
eeea996f0b update lazy-lock 2025-10-20 21:11:31 +03:00
40 changed files with 3247 additions and 887 deletions

15
docs/README.md Normal file
View File

@@ -0,0 +1,15 @@
# New Spec
For new LSP, add in `lua/modules/language-specs.lua` at `lsp = <name>`.
Name should match the mason registry one at: `https://github.com/mason-org/mason-registry/tree/main/packages`
1. Run `nvim --headless +InstallAll +qa` (it invalidates cache automatically)
2. Run ` nvim --headless +FetchLspConfigs +qa` -> It will download the nvim-lspconfig variant in `lsp/`
You may need to run: `pkill prettierd` (as it is running in background)
# Other commands
```
nvim --headless +Sync +qa # For packages/plugins
```

View File

@@ -1,13 +1,3 @@
TODO:
- wrap up invero theme in separate repo and proper colors?
- check plugins logins
- cache / create final result
- simplify coding: ts, lsp, lint, format (check other repos)
- how to download parsers and plugins alternative
- telescope alternative
- keymaps
- wrap up everything
```lua
--[[
Neovim Lua config: ways to set things
@@ -31,121 +21,125 @@ TODO:
## check macos fileS: https://github.com/dsully/dotfiles/blob/main/.data/macos-defaults/globals.yaml
# Used pacakges:
- rockspaces Metadata files describing how to build and install a Lua package.
- luarocks Package manager for Lua modules. (optional)
- tree-sitter Parser generator. Not needed except for using CLI. (optional)
- fd-find (fd) Alternative to `find`. (optional)
- ripgrep (rg) Line-oriented search tool. (recommended)
- rockspaces Metadata files describing how to build and install a Lua package.
- luarocks Package manager for Lua modules. (optional)
- tree-sitter Parser generator. Not needed except for using CLI. (optional)
- git Revision control system. (requirement)
- lazygit Terminal UI for git commands. (optional)
- fd-find (fd) Alternative to `find`. (optional)
- ripgrep (rg) Line-oriented search tool. (recommended)
- fzf Command-line fuzzy finder.
- bat "cat" but with colors
- curl Command-line for transferring data specified with URL syntax.
- wget Utility for downloading files from the Web.
- git Revision control system. (requirement)
- lazygit Terminal UI for git commands. (optional)
- fzf Command-line fuzzy finder.
- bat "cat" but with colors
- curl Command-line for transferring data specified with URL syntax.
- wget Utility for downloading files from the Web.
- make
- cc Collection of compilers.
- build-essential Meta-package that installs standard C/C++ libraries and headers.
These are needed to compile tree-sitter parsers. Run only on the first time.
cc (gcc, clang) C compiler. Usually it points to `clang` (on macos) or `gcc` (on linux).
g++ C++ compiler.
make Build automation tool from source code.
- cc Collection of compilers.
- build-essential Meta-package that installs standard C/C++ libraries and headers.
These are needed to compile tree-sitter parsers. Run only on the first time.
cc (gcc, clang) C compiler. Usually it points to `clang` (on macos) or `gcc` (on linux).
g++ C++ compiler.
make Build automation tool from source code.
- unzip Extraction utility for archives compressed in .zip.
- ca-certificates Provides a set of trusted Certificate Authority (CA) certificates.
- openssh-client Tools for connecting to remote servers securely over SSH.
- libssl-dev Development libraries and headers for OpenSSL.
- unzip Extraction utility for archives compressed in .zip.
- ca-certificates Provides a set of trusted Certificate Authority (CA) certificates.
- openssh-client Tools for connecting to remote servers securely over SSH.
- libssl-dev Development libraries and headers for OpenSSL.
- sudo
- tree
- jq
- man-db
- python3
- volta Node manager
- volta Node manager
- ncurses ncurses-dev ncurses-libs ncurses-terminfo \
- check: https://github.com/glepnir/nvim/blob/main/Dockerfile
# Currently installed
- plenary.nvim
- lazy.nvim
- nvim-treesitter
- neovim/nvim-lspconfig
- williamboman/mason.nvim
- williamboman/mason-lspconfig.nvim
- j-hui/fidget.nvim
- hrsh7th/cmp-nvim-lsp
- b0o/schemastore.nvim
- williamboman/mason.nvim
- williamboman/mason-lspconfig.nvim
- j-hui/fidget.nvim
- hrsh7th/cmp-nvim-lsp
- b0o/schemastore.nvim
- windwp/nvim-ts-autotag # auto close,rename tags
- nvim-autopairs # auto pair chars
- stevearc/conform.nvim # formatter
- nvim-cmp # completion
- cmp-path
- cmp-nvim-lsp
- cmp-path
- cmp-nvim-lsp
- nvim-tree.lua # file explorer
- telescope.nvim
- telescope-fzf-native.nvim
- telescope-ui-select.nvim
- plenary.nvim
- telescope-fzf-native.nvim
- telescope-ui-select.nvim
- plenary.nvim
- harpoon # tags
# Notes:
- in lsp change tsserver to vtsls
# New package definition
- Plugin and Package managers
- folke/lazy.nvim
- mason-org/mason.nvim
- TS
- nvim-treesitter
- nvim-treesitter-textobjects
- LSP
- neovim/nvim-lspconfig
- nvim-ts-autotag tag elements (`</>`)
- windwp/nvim-autopairs auto pairs
- blink.cmp autocompletion
- stevearc/conform.nvim autoformat
- mini.ai `a/i` motions
- Plugin and Package managers
- folke/lazy.nvim
- mason-org/mason.nvim
- TS
- nvim-treesitter
- nvim-treesitter-textobjects
- LSP
- neovim/nvim-lspconfig
- nvim-ts-autotag tag elements (`</>`)
- windwp/nvim-autopairs auto pairs
- blink.cmp autocompletion
- stevearc/conform.nvim autoformat
- mini.ai `a/i` motions
- mini.pairs
- mini.surround
- mfussenegger/nvim-lint
- nvim-lspconfig
- fzf-lua (replace telescope)
- ? indent guides
- lukas-reineke/indent-blankline.nvim
- snacks.indent
- mini.indentscope
- lukas-reineke/indent-blankline.nvim
- snacks.indent
- mini.indentscope
## Deps:
- SchemaStore.nvim
- mason-lspconfig.nvim
- mason.nvim
## Maybe:
- folke/ts-comments.nvim better comments
- grug-far.nvim find and replace
- markdown-preview.nvim side by side md (disabled in folke)
- toppair/peek.nvim another markdown preview?
- render-markdown.nvim inline viewer
- folke/ts-comments.nvim better comments
- grug-far.nvim find and replace
- markdown-preview.nvim side by side md (disabled in folke)
- toppair/peek.nvim another markdown preview?
- render-markdown.nvim inline viewer
- markview.nvim
- diffview.nvim
- octo.nvim edit and review GH issues and pr
- yanky.nvim better yank+put. has history
- inc-rename.nvim LSP renaming with visual feedback
- mini.basics defaults options
- mini.test run tests under cursor
- mini.diff inline diff
- mini.hipatters hilight patters and hex colors
- mini.move move chunks (like vscode)
- octo.nvim edit and review GH issues and pr
- yanky.nvim better yank+put. has history
- inc-rename.nvim LSP renaming with visual feedback
- mini.basics defaults options
- mini.test run tests under cursor
- mini.diff inline diff
- mini.hipatters hilight patters and hex colors
- mini.move move chunks (like vscode)
- undo tree (find a plugin)
## AI help
- jackMort/ChatGPT.nvim
- MunifTanjim/nui.nvim (dep)
- nvim-lua/plenary.nvim (dep)
@@ -155,6 +149,7 @@ TODO:
- milanglacier/minuet-ai.nvim (folke)
## Options
```
opt.backup = true
@@ -178,6 +173,7 @@ vim.keymap.set("n", "<C-c>", "ciw")
```
folke cmd
```lua
-- show cursor line only in active window
vim.api.nvim_create_autocmd({ "InsertLeave", "WinEnter" }, {
@@ -210,6 +206,7 @@ vim.api.nvim_create_autocmd("BufWritePre", {
```
Enable folding with TS:
```
vim.opt.foldmethod = "expr"
vim.opt.foldexpr = "nvim_treesitter#foldexpr()"

View File

@@ -1,29 +1,29 @@
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
if not (vim.uv or vim.loop).fs_stat(lazypath) then
local lazyrepo = 'https://github.com/folke/lazy.nvim.git'
local out =
vim.fn.system({ 'git', 'clone', '--filter=blob:none', '--branch=stable', lazyrepo, lazypath })
if vim.v.shell_error ~= 0 then
vim.api.nvim_echo({
{ 'Failed to clone lazy.nvim:\n', 'ErrorMsg' },
{ out, 'WarningMsg' },
{ '\nPress any key to exit...' },
}, true, {})
vim.fn.getchar()
os.exit(1)
end
if #vim.api.nvim_list_uis() == 0 then
require('setup')
return
end
vim.opt.rtp:prepend(lazypath)
require('config.options')
require('config.keymaps')
require('config.autocmds')
require('config.clipboard')
require('config.terminal')
require('custom.navigation')
require('lazy').setup({
spec = { { import = 'plugins' } },
install = { missing = false },
change_detection = { notify = false },
rocks = { enabled = false },
vim.env.PATH = vim.fn.stdpath('data') .. '/mason/bin:' .. vim.env.PATH
vim.filetype.add({
pattern = {
['.*/templates/.*%.ya?ml'] = 'helm',
['.*/manifests/.*%.ya?ml'] = 'helm',
['.*/crds/.*%.ya?ml'] = 'helm',
['.*/kubernetes/.*%.ya?ml'] = 'helm',
['.*/k8s/.*%.ya?ml'] = 'helm',
['.*/charts/.*%.ya?ml'] = 'helm',
},
})
function _G.see(val)
local lines = vim.split(vim.inspect(val), '\n')
vim.cmd('new')
vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
vim.bo.buftype = 'nofile'
vim.bo.bufhidden = 'wipe'
end
require('core.options')
require('core.keymaps')
require('core.events')

View File

@@ -1,12 +0,0 @@
{
"conform.nvim": { "branch": "master", "commit": "fbcb4fa7f34bfea9be702ffff481a8e336ebf6ed" },
"fzf-lua": { "branch": "main", "commit": "58ebb27333bd12cb497f27b7da07a677116bc0ef" },
"lazy.nvim": { "branch": "main", "commit": "1ea3c4085785f460fb0e46d2fe1ee895f5f9e7c1" },
"mason.nvim": { "branch": "main", "commit": "ad7146aa61dcaeb54fa900144d768f040090bff0" },
"nvim-autopairs": { "branch": "master", "commit": "7a2c97cccd60abc559344042fefb1d5a85b3e33b" },
"nvim-lint": { "branch": "master", "commit": "9da1fb942dd0668d5182f9c8dee801b9c190e2bb" },
"nvim-tree.lua": { "branch": "master", "commit": "321bc61580fd066b76861c32de3319c3a6d089e7" },
"nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" },
"nvim-ts-autotag": { "branch": "main", "commit": "c4ca798ab95b316a768d51eaaaee48f64a4a46bc" },
"rose-pine": { "branch": "main", "commit": "72a04c4065345b51b56aed4859ea1d884f734097" }
}

29
lsp/bashls.lua Normal file
View File

@@ -0,0 +1,29 @@
---@brief
---
--- https://github.com/bash-lsp/bash-language-server
---
--- `bash-language-server` can be installed via `npm`:
--- ```sh
--- npm i -g bash-language-server
--- ```
---
--- Language server for bash, written using tree sitter in typescript.
---@type vim.lsp.Config
return {
cmd = { 'bash-language-server', 'start' },
settings = {
bashIde = {
-- Glob pattern for finding and parsing shell script files in the workspace.
-- Used by the background analysis features across files.
-- Prevent recursive scanning which will cause issues when opening a file
-- directly in the home directory (e.g. ~/foo.sh).
--
-- Default upstream pattern is "**/*@(.sh|.inc|.bash|.command)".
globPattern = vim.env.GLOB_PATTERN or '*@(.sh|.inc|.bash|.command)',
},
},
filetypes = { 'bash', 'sh' },
root_markers = { '.git' },
}

100
lsp/clangd.lua Normal file
View File

@@ -0,0 +1,100 @@
---@brief
---
--- https://clangd.llvm.org/installation.html
---
--- - **NOTE:** Clang >= 11 is recommended! See [#23](https://github.com/neovim/nvim-lspconfig/issues/23).
--- - If `compile_commands.json` lives in a build directory, you should
--- symlink it to the root of your source tree.
--- ```
--- ln -s /path/to/myproject/build/compile_commands.json /path/to/myproject/
--- ```
--- - clangd relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html)
--- specified as compile_commands.json, see https://clangd.llvm.org/installation#compile_commandsjson
-- https://clangd.llvm.org/extensions.html#switch-between-sourceheader
local function switch_source_header(bufnr, client)
local method_name = 'textDocument/switchSourceHeader'
---@diagnostic disable-next-line:param-type-mismatch
if not client or not client:supports_method(method_name) then
return vim.notify(('method %s is not supported by any servers active on the current buffer'):format(method_name))
end
local params = vim.lsp.util.make_text_document_params(bufnr)
---@diagnostic disable-next-line:param-type-mismatch
client:request(method_name, params, function(err, result)
if err then
error(tostring(err))
end
if not result then
vim.notify('corresponding file cannot be determined')
return
end
vim.cmd.edit(vim.uri_to_fname(result))
end, bufnr)
end
local function symbol_info(bufnr, client)
local method_name = 'textDocument/symbolInfo'
---@diagnostic disable-next-line:param-type-mismatch
if not client or not client:supports_method(method_name) then
return vim.notify('Clangd client not found', vim.log.levels.ERROR)
end
local win = vim.api.nvim_get_current_win()
local params = vim.lsp.util.make_position_params(win, client.offset_encoding)
---@diagnostic disable-next-line:param-type-mismatch
client:request(method_name, params, function(err, res)
if err or #res == 0 then
-- Clangd always returns an error, there is no reason to parse it
return
end
local container = string.format('container: %s', res[1].containerName) ---@type string
local name = string.format('name: %s', res[1].name) ---@type string
vim.lsp.util.open_floating_preview({ name, container }, '', {
height = 2,
width = math.max(string.len(name), string.len(container)),
focusable = false,
focus = false,
title = 'Symbol Info',
})
end, bufnr)
end
---@class ClangdInitializeResult: lsp.InitializeResult
---@field offsetEncoding? string
---@type vim.lsp.Config
return {
cmd = { 'clangd' },
filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda' },
root_markers = {
'.clangd',
'.clang-tidy',
'.clang-format',
'compile_commands.json',
'compile_flags.txt',
'configure.ac', -- AutoTools
'.git',
},
capabilities = {
textDocument = {
completion = {
editsNearCursor = true,
},
},
offsetEncoding = { 'utf-8', 'utf-16' },
},
---@param init_result ClangdInitializeResult
on_init = function(client, init_result)
if init_result.offsetEncoding then
client.offset_encoding = init_result.offsetEncoding
end
end,
on_attach = function(client, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, 'LspClangdSwitchSourceHeader', function()
switch_source_header(bufnr, client)
end, { desc = 'Switch between source/header' })
vim.api.nvim_buf_create_user_command(bufnr, 'LspClangdShowSymbolInfo', function()
symbol_info(bufnr, client)
end, { desc = 'Show symbol info' })
end,
}

34
lsp/cssls.lua Normal file
View File

@@ -0,0 +1,34 @@
---@brief
---
--- https://github.com/hrsh7th/vscode-langservers-extracted
---
--- `css-languageserver` can be installed via `npm`:
---
--- ```sh
--- npm i -g vscode-langservers-extracted
--- ```
---
--- Neovim does not currently include built-in snippets. `vscode-css-language-server` only provides completions when snippet support is enabled. To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup.
---
--- ```lua
--- --Enable (broadcasting) snippet capability for completion
--- local capabilities = vim.lsp.protocol.make_client_capabilities()
--- capabilities.textDocument.completion.completionItem.snippetSupport = true
---
--- vim.lsp.config('cssls', {
--- capabilities = capabilities,
--- })
--- ```
---@type vim.lsp.Config
return {
cmd = { 'vscode-css-language-server', '--stdio' },
filetypes = { 'css', 'scss', 'less' },
init_options = { provideFormatter = true }, -- needed to enable formatting capabilities
root_markers = { 'package.json', '.git' },
settings = {
css = { validate = true },
scss = { validate = true },
less = { validate = true },
},
}

253
lsp/eslint.lua Normal file
View File

@@ -0,0 +1,253 @@
local utils = {}
function utils.root_markers_with_field(root_files, new_names, field, fname)
local path = vim.fn.fnamemodify(fname, ':h')
local found = vim.fs.find(new_names, { path = path, upward = true })
for _, f in ipairs(found or {}) do
-- Match the given `field`.
for line in io.lines(f) do
if line:find(field) then
root_files[#root_files + 1] = vim.fs.basename(f)
break
end
end
end
return root_files
end
function utils.insert_package_json(root_files, field, fname)
return utils.root_markers_with_field(
root_files,
{ 'package.json', 'package.json5' },
field,
fname
)
end
--- @brief
---
--- https://github.com/hrsh7th/vscode-langservers-extracted
---
--- `vscode-eslint-language-server` is a linting engine for JavaScript / Typescript.
--- It can be installed via `npm`:
---
--- ```sh
--- npm i -g vscode-langservers-extracted
--- ```
---
--- The default `on_attach` config provides the `LspEslintFixAll` command that can be used to format a document on save:
--- ```lua
--- local base_on_attach = vim.lsp.config.eslint.on_attach
--- vim.lsp.config("eslint", {
--- on_attach = function(client, bufnr)
--- if not base_on_attach then return end
---
--- base_on_attach(client, bufnr)
--- vim.api.nvim_create_autocmd("BufWritePre", {
--- buffer = bufnr,
--- command = "LspEslintFixAll",
--- })
--- end,
--- })
--- ```
---
--- See [vscode-eslint](https://github.com/microsoft/vscode-eslint/blob/55871979d7af184bf09af491b6ea35ebd56822cf/server/src/eslintServer.ts#L216-L229) for configuration options.
---
--- Messages handled in lspconfig: `eslint/openDoc`, `eslint/confirmESLintExecution`, `eslint/probeFailed`, `eslint/noLibrary`
---
--- Additional messages you can handle: `eslint/noConfig`
---
--- ### Monorepo support
---
--- `vscode-eslint-language-server` supports monorepos by default. It will automatically find the config file corresponding to the package you are working on. You can use different configs in different packages.
--- This works without the need of spawning multiple instances of `vscode-eslint-language-server`.
--- You can use a different version of ESLint in each package, but it is recommended to use the same version of ESLint in all packages. The location of the ESLint binary will be determined automatically.
---
--- /!\ When using flat config files, you need to use them across all your packages in your monorepo, as it's a global setting for the server.
local lsp = vim.lsp
local eslint_config_files = {
'.eslintrc',
'.eslintrc.js',
'.eslintrc.cjs',
'.eslintrc.yaml',
'.eslintrc.yml',
'.eslintrc.json',
'eslint.config.js',
'eslint.config.mjs',
'eslint.config.cjs',
'eslint.config.ts',
'eslint.config.mts',
'eslint.config.cts',
}
---@type vim.lsp.Config
return {
cmd = { 'vscode-eslint-language-server', '--stdio' },
filetypes = {
'javascript',
'javascriptreact',
'javascript.jsx',
'typescript',
'typescriptreact',
'typescript.tsx',
'vue',
'svelte',
'astro',
'htmlangular',
},
workspace_required = true,
on_attach = function(client, bufnr)
vim.api.nvim_buf_create_user_command(0, 'LspEslintFixAll', function()
client:request_sync('workspace/executeCommand', {
command = 'eslint.applyAllFixes',
arguments = {
{
uri = vim.uri_from_bufnr(bufnr),
version = lsp.util.buf_versions[bufnr],
},
},
}, nil, bufnr)
end, {})
end,
root_dir = function(bufnr, on_dir)
-- The project root is where the LSP can be started from
-- As stated in the documentation above, this LSP supports monorepos and simple projects.
-- We select then from the project root, which is identified by the presence of a package
-- manager lock file.
local root_markers =
{ 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb', 'bun.lock' }
-- Give the root markers equal priority by wrapping them in a table
root_markers = vim.fn.has('nvim-0.11.3') == 1 and { root_markers, { '.git' } }
or vim.list_extend(root_markers, { '.git' })
-- We fallback to the current working directory if no project root is found
local project_root = vim.fs.root(bufnr, root_markers) or vim.fn.getcwd()
-- We know that the buffer is using ESLint if it has a config file
-- in its directory tree.
--
-- Eslint used to support package.json files as config files, but it doesn't anymore.
-- We keep this for backward compatibility.
local filename = vim.api.nvim_buf_get_name(bufnr)
local eslint_config_files_with_package_json =
utils.insert_package_json(eslint_config_files, 'eslintConfig', filename)
local is_buffer_using_eslint = vim.fs.find(eslint_config_files_with_package_json, {
path = filename,
type = 'file',
limit = 1,
upward = true,
stop = vim.fs.dirname(project_root),
})[1]
if not is_buffer_using_eslint then
return
end
on_dir(project_root)
end,
-- Refer to https://github.com/Microsoft/vscode-eslint#settings-options for documentation.
settings = {
validate = 'on',
packageManager = nil,
useESLintClass = false,
experimental = {
useFlatConfig = false,
},
codeActionOnSave = {
enable = false,
mode = 'all',
},
format = true,
quiet = false,
onIgnoredFiles = 'off',
rulesCustomizations = {},
run = 'onType',
problems = {
shortenToSingleLine = false,
},
-- nodePath configures the directory in which the eslint server should start its node_modules resolution.
-- This path is relative to the workspace folder (root dir) of the server instance.
nodePath = '',
-- use the workspace folder location or the file location (if no workspace folder is open) as the working directory
workingDirectory = { mode = 'auto' },
codeAction = {
disableRuleComment = {
enable = true,
location = 'separateLine',
},
showDocumentation = {
enable = true,
},
},
},
before_init = function(_, config)
-- The "workspaceFolder" is a VSCode concept. It limits how far the
-- server will traverse the file system when locating the ESLint config
-- file (e.g., .eslintrc).
local root_dir = config.root_dir
if root_dir then
config.settings = config.settings or {}
config.settings.workspaceFolder = {
uri = root_dir,
name = vim.fn.fnamemodify(root_dir, ':t'),
}
-- Support flat config files
-- They contain 'config' in the file name
local flat_config_files = vim.tbl_filter(function(file)
return file:match('config')
end, eslint_config_files)
for _, file in ipairs(flat_config_files) do
local found_files = vim.fn.globpath(root_dir, file, true, true)
-- Filter out files inside node_modules
local filtered_files = {}
for _, found_file in ipairs(found_files) do
if string.find(found_file, '[/\\]node_modules[/\\]') == nil then
table.insert(filtered_files, found_file)
end
end
if #filtered_files > 0 then
config.settings.experimental = config.settings.experimental or {}
config.settings.experimental.useFlatConfig = true
break
end
end
-- Support Yarn2 (PnP) projects
local pnp_cjs = root_dir .. '/.pnp.cjs'
local pnp_js = root_dir .. '/.pnp.js'
if vim.uv.fs_stat(pnp_cjs) or vim.uv.fs_stat(pnp_js) then
local cmd = config.cmd
config.cmd = vim.list_extend({ 'yarn', 'exec' }, cmd)
end
end
end,
handlers = {
['eslint/openDoc'] = function(_, result)
if result then
vim.ui.open(result.url)
end
return {}
end,
['eslint/confirmESLintExecution'] = function(_, result)
if not result then
return
end
return 4 -- approved
end,
['eslint/probeFailed'] = function()
vim.notify('[lspconfig] ESLint probe failed.', vim.log.levels.WARN)
return {}
end,
['eslint/noLibrary'] = function()
vim.notify('[lspconfig] Unable to find ESLint library.', vim.log.levels.WARN)
return {}
end,
},
}

25
lsp/helm_ls.lua Normal file
View File

@@ -0,0 +1,25 @@
---@brief
---
--- https://github.com/mrjosh/helm-ls
---
--- Helm Language server. (This LSP is in early development)
---
--- `helm Language server` can be installed by following the instructions [here](https://github.com/mrjosh/helm-ls).
---
--- The default `cmd` assumes that the `helm_ls` binary can be found in `$PATH`.
---
--- If need Helm file highlight use [vim-helm](https://github.com/towolf/vim-helm) plugin.
---@type vim.lsp.Config
return {
cmd = { 'helm_ls', 'serve' },
filetypes = { 'helm', 'yaml.helm-values' },
root_markers = { 'Chart.yaml' },
capabilities = {
workspace = {
didChangeWatchedFiles = {
dynamicRegistration = true,
},
},
},
}

36
lsp/html.lua Normal file
View File

@@ -0,0 +1,36 @@
---@brief
---
--- https://github.com/hrsh7th/vscode-langservers-extracted
---
--- `vscode-html-language-server` can be installed via `npm`:
--- ```sh
--- npm i -g vscode-langservers-extracted
--- ```
---
--- Neovim does not currently include built-in snippets. `vscode-html-language-server` only provides completions when snippet support is enabled.
--- To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup.
---
--- The code-formatting feature of the lsp can be controlled with the `provideFormatter` option.
---
--- ```lua
--- --Enable (broadcasting) snippet capability for completion
--- local capabilities = vim.lsp.protocol.make_client_capabilities()
--- capabilities.textDocument.completion.completionItem.snippetSupport = true
---
--- vim.lsp.config('html', {
--- capabilities = capabilities,
--- })
--- ```
---@type vim.lsp.Config
return {
cmd = { 'vscode-html-language-server', '--stdio' },
filetypes = { 'html', 'templ' },
root_markers = { 'package.json', '.git' },
settings = {},
init_options = {
provideFormatter = true,
embeddedLanguages = { css = true, javascript = true },
configurationSection = { 'html', 'css', 'javascript' },
},
}

View File

@@ -1,14 +1,85 @@
---@brief
---
--- https://github.com/luals/lua-language-server
---
--- Lua language server.
---
--- `lua-language-server` can be installed by following the instructions [here](https://luals.github.io/#neovim-install).
---
--- The default `cmd` assumes that the `lua-language-server` binary can be found in `$PATH`.
---
--- If you primarily use `lua-language-server` for Neovim, and want to provide completions,
--- analysis, and location handling for plugins on runtime path, you can use the following
--- settings.
---
--- ```lua
--- vim.lsp.config('lua_ls', {
--- on_init = function(client)
--- if client.workspace_folders then
--- local path = client.workspace_folders[1].name
--- if
--- path ~= vim.fn.stdpath('config')
--- and (vim.uv.fs_stat(path .. '/.luarc.json') or vim.uv.fs_stat(path .. '/.luarc.jsonc'))
--- then
--- return
--- end
--- end
---
--- client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, {
--- runtime = {
--- -- Tell the language server which version of Lua you're using (most
--- -- likely LuaJIT in the case of Neovim)
--- version = 'LuaJIT',
--- -- Tell the language server how to find Lua modules same way as Neovim
--- -- (see `:h lua-module-load`)
--- path = {
--- 'lua/?.lua',
--- 'lua/?/init.lua',
--- },
--- },
--- -- Make the server aware of Neovim runtime files
--- workspace = {
--- checkThirdParty = false,
--- library = {
--- vim.env.VIMRUNTIME
--- -- Depending on the usage, you might want to add additional paths
--- -- here.
--- -- '${3rd}/luv/library'
--- -- '${3rd}/busted/library'
--- }
--- -- Or pull in all of 'runtimepath'.
--- -- NOTE: this is a lot slower and will cause issues when working on
--- -- your own configuration.
--- -- See https://github.com/neovim/nvim-lspconfig/issues/3189
--- -- library = {
--- -- vim.api.nvim_get_runtime_file('', true),
--- -- }
--- }
--- })
--- end,
--- settings = {
--- Lua = {}
--- }
--- })
--- ```
---
--- See `lua-language-server`'s [documentation](https://luals.github.io/wiki/settings/) for an explanation of the above fields:
--- * [Lua.runtime.path](https://luals.github.io/wiki/settings/#runtimepath)
--- * [Lua.workspace.library](https://luals.github.io/wiki/settings/#workspacelibrary)
---
---@type vim.lsp.Config
return {
cmd = { "lua-language-server" },
filetypes = { "lua" },
cmd = { 'lua-language-server' },
filetypes = { 'lua' },
root_markers = {
".luarc.json",
".luarc.jsonc",
".luacheckrc",
".stylua.toml",
"stylua.toml",
"selene.toml",
"selene.yml",
".git",
'.luarc.json',
'.luarc.jsonc',
'.luacheckrc',
'.stylua.toml',
'stylua.toml',
'selene.toml',
'selene.yml',
'.git',
},
}

65
lsp/pyright.lua Normal file
View File

@@ -0,0 +1,65 @@
---@brief
---
--- https://github.com/microsoft/pyright
---
--- `pyright`, a static type checker and language server for python
local function set_python_path(command)
local path = command.args
local clients = vim.lsp.get_clients {
bufnr = vim.api.nvim_get_current_buf(),
name = 'pyright',
}
for _, client in ipairs(clients) do
if client.settings then
client.settings.python = vim.tbl_deep_extend('force', client.settings.python, { pythonPath = path })
else
client.config.settings = vim.tbl_deep_extend('force', client.config.settings, { python = { pythonPath = path } })
end
client:notify('workspace/didChangeConfiguration', { settings = nil })
end
end
---@type vim.lsp.Config
return {
cmd = { 'pyright-langserver', '--stdio' },
filetypes = { 'python' },
root_markers = {
'pyproject.toml',
'setup.py',
'setup.cfg',
'requirements.txt',
'Pipfile',
'pyrightconfig.json',
'.git',
},
settings = {
python = {
analysis = {
autoSearchPaths = true,
useLibraryCodeForTypes = true,
diagnosticMode = 'openFilesOnly',
},
},
},
on_attach = function(client, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightOrganizeImports', function()
local params = {
command = 'pyright.organizeimports',
arguments = { vim.uri_from_bufnr(bufnr) },
}
-- Using client.request() directly because "pyright.organizeimports" is private
-- (not advertised via capabilities), which client:exec_cmd() refuses to call.
-- https://github.com/neovim/neovim/blob/c333d64663d3b6e0dd9aa440e433d346af4a3d81/runtime/lua/vim/lsp/client.lua#L1024-L1030
client.request('workspace/executeCommand', params, nil, bufnr)
end, {
desc = 'Organize Imports',
})
vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightSetPythonPath', set_python_path, {
desc = 'Reconfigure pyright with the provided python path',
nargs = 1,
complete = 'file',
})
end,
}

19
lsp/sqls.lua Normal file
View File

@@ -0,0 +1,19 @@
---@brief
---
--- https://github.com/sqls-server/sqls
---
--- ```lua
--- vim.lsp.config('sqls', {
--- cmd = {"path/to/command", "-config", "path/to/config.yml"};
--- ...
--- })
--- ```
--- Sqls can be installed via `go install github.com/sqls-server/sqls@latest`. Instructions for compiling Sqls from the source can be found at [sqls-server/sqls](https://github.com/sqls-server/sqls).
---@type vim.lsp.Config
return {
cmd = { 'sqls' },
filetypes = { 'sql', 'mysql' },
root_markers = { 'config.yml' },
settings = {},
}

163
lsp/tailwindcss.lua Normal file
View File

@@ -0,0 +1,163 @@
local utils = {}
function utils.root_markers_with_field(root_files, new_names, field, fname)
local path = vim.fn.fnamemodify(fname, ':h')
local found = vim.fs.find(new_names, { path = path, upward = true })
for _, f in ipairs(found or {}) do
-- Match the given `field`.
for line in io.lines(f) do
if line:find(field) then
root_files[#root_files + 1] = vim.fs.basename(f)
break
end
end
end
return root_files
end
function utils.insert_package_json(root_files, field, fname)
return utils.root_markers_with_field(
root_files,
{ 'package.json', 'package.json5' },
field,
fname
)
end
---@brief
--- https://github.com/tailwindlabs/tailwindcss-intellisense
---
--- Tailwind CSS Language Server can be installed via npm:
---
--- npm install -g @tailwindcss/language-server
---@type vim.lsp.Config
return {
cmd = { 'tailwindcss-language-server', '--stdio' },
-- filetypes copied and adjusted from tailwindcss-intellisense
filetypes = {
-- html
'aspnetcorerazor',
'astro',
'astro-markdown',
'blade',
'clojure',
'django-html',
'htmldjango',
'edge',
'eelixir', -- vim ft
'elixir',
'ejs',
'erb',
'eruby', -- vim ft
'gohtml',
'gohtmltmpl',
'haml',
'handlebars',
'hbs',
'html',
'htmlangular',
'html-eex',
'heex',
'jade',
'leaf',
'liquid',
'markdown',
'mdx',
'mustache',
'njk',
'nunjucks',
'php',
'razor',
'slim',
'twig',
-- css
'css',
'less',
'postcss',
'sass',
'scss',
'stylus',
'sugarss',
-- js
'javascript',
'javascriptreact',
'reason',
'rescript',
'typescript',
'typescriptreact',
-- mixed
'vue',
'svelte',
'templ',
},
settings = {
tailwindCSS = {
validate = true,
lint = {
cssConflict = 'warning',
invalidApply = 'error',
invalidScreen = 'error',
invalidVariant = 'error',
invalidConfigPath = 'error',
invalidTailwindDirective = 'error',
recommendedVariantOrder = 'warning',
},
classAttributes = {
'class',
'className',
'class:list',
'classList',
'ngClass',
},
includeLanguages = {
eelixir = 'html-eex',
elixir = 'phoenix-heex',
eruby = 'erb',
heex = 'phoenix-heex',
htmlangular = 'html',
templ = 'html',
},
},
},
before_init = function(_, config)
if not config.settings then
config.settings = {}
end
if not config.settings.editor then
config.settings.editor = {}
end
if not config.settings.editor.tabSize then
config.settings.editor.tabSize = vim.lsp.util.get_effective_tabstop()
end
end,
workspace_required = true,
root_dir = function(bufnr, on_dir)
local root_files = {
-- Generic
'tailwind.config.js',
'tailwind.config.cjs',
'tailwind.config.mjs',
'tailwind.config.ts',
'postcss.config.js',
'postcss.config.cjs',
'postcss.config.mjs',
'postcss.config.ts',
-- Django
'theme/static_src/tailwind.config.js',
'theme/static_src/tailwind.config.cjs',
'theme/static_src/tailwind.config.mjs',
'theme/static_src/tailwind.config.ts',
'theme/static_src/postcss.config.js',
-- Fallback for tailwind v4, where tailwind.config.* is not required anymore
'.git',
}
local fname = vim.api.nvim_buf_get_name(bufnr)
root_files = utils.insert_package_json(root_files, 'tailwindcss', fname)
root_files =
utils.root_markers_with_field(root_files, { 'mix.lock', 'Gemfile.lock' }, 'tailwind', fname)
on_dir(vim.fs.dirname(vim.fs.find(root_files, { path = fname, upward = true })[1]))
end,
}

96
lsp/vtsls.lua Normal file
View File

@@ -0,0 +1,96 @@
---@brief
---
--- https://github.com/yioneko/vtsls
---
--- `vtsls` can be installed with npm:
--- ```sh
--- npm install -g @vtsls/language-server
--- ```
---
--- To configure a TypeScript project, add a
--- [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html)
--- or [`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) to
--- the root of your project.
---
--- ### Vue support
---
--- Since v3.0.0, the Vue language server requires `vtsls` to support TypeScript.
---
--- ```
--- -- If you are using mason.nvim, you can get the ts_plugin_path like this
--- -- For Mason v1,
--- -- local mason_registry = require('mason-registry')
--- -- local vue_language_server_path = mason_registry.get_package('vue-language-server'):get_install_path() .. '/node_modules/@vue/language-server'
--- -- For Mason v2,
--- -- local vue_language_server_path = vim.fn.expand '$MASON/packages' .. '/vue-language-server' .. '/node_modules/@vue/language-server'
--- -- or even
--- -- local vue_language_server_path = vim.fn.stdpath('data') .. "/mason/packages/vue-language-server/node_modules/@vue/language-server"
--- local vue_language_server_path = '/path/to/@vue/language-server'
--- local vue_plugin = {
--- name = '@vue/typescript-plugin',
--- location = vue_language_server_path,
--- languages = { 'vue' },
--- configNamespace = 'typescript',
--- }
--- vim.lsp.config('vtsls', {
--- settings = {
--- vtsls = {
--- tsserver = {
--- globalPlugins = {
--- vue_plugin,
--- },
--- },
--- },
--- },
--- filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
--- })
--- ```
---
--- - `location` MUST be defined. If the plugin is installed in `node_modules`, `location` can have any value.
--- - `languages` must include vue even if it is listed in filetypes.
--- - `filetypes` is extended here to include Vue SFC.
---
--- You must make sure the Vue language server is setup. For example,
---
--- ```
--- vim.lsp.enable('vue_ls')
--- ```
---
--- See `vue_ls` section and https://github.com/vuejs/language-tools/wiki/Neovim for more information.
---
--- ### Monorepo support
---
--- `vtsls` supports monorepos by default. It will automatically find the `tsconfig.json` or `jsconfig.json` corresponding to the package you are working on.
--- This works without the need of spawning multiple instances of `vtsls`, saving memory.
---
--- It is recommended to use the same version of TypeScript in all packages, and therefore have it available in your workspace root. The location of the TypeScript binary will be determined automatically, but only once.
---@type vim.lsp.Config
return {
cmd = { 'vtsls', '--stdio' },
init_options = {
hostInfo = 'neovim',
},
filetypes = {
'javascript',
'javascriptreact',
'javascript.jsx',
'typescript',
'typescriptreact',
'typescript.tsx',
},
root_dir = function(bufnr, on_dir)
-- The project root is where the LSP can be started from
-- As stated in the documentation above, this LSP supports monorepos and simple projects.
-- We select then from the project root, which is identified by the presence of a package
-- manager lock file.
local root_markers = { 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb', 'bun.lock' }
-- Give the root markers equal priority by wrapping them in a table
root_markers = vim.fn.has('nvim-0.11.3') == 1 and { root_markers, { '.git' } }
or vim.list_extend(root_markers, { '.git' })
-- We fallback to the current working directory if no project root is found
local project_root = vim.fs.root(bufnr, root_markers) or vim.fn.getcwd()
on_dir(project_root)
end,
}

83
lsp/yamlls.lua Normal file
View File

@@ -0,0 +1,83 @@
---@brief
---
--- https://github.com/redhat-developer/yaml-language-server
---
--- `yaml-language-server` can be installed via `yarn`:
--- ```sh
--- yarn global add yaml-language-server
--- ```
---
--- To use a schema for validation, there are two options:
---
--- 1. Add a modeline to the file. A modeline is a comment of the form:
---
--- ```
--- # yaml-language-server: $schema=<urlToTheSchema|relativeFilePath|absoluteFilePath}>
--- ```
---
--- where the relative filepath is the path relative to the open yaml file, and the absolute filepath
--- is the filepath relative to the filesystem root ('/' on unix systems)
---
--- 2. Associated a schema url, relative , or absolute (to root of project, not to filesystem root) path to
--- the a glob pattern relative to the detected project root. Check `:checkhealth vim.lsp` to determine the resolved project
--- root.
---
--- ```lua
--- vim.lsp.config('yamlls', {
--- ...
--- settings = {
--- yaml = {
--- ... -- other settings. note this overrides the lspconfig defaults.
--- schemas = {
--- ["https://json.schemastore.org/github-workflow.json"] = "/.github/workflows/*",
--- ["../path/relative/to/file.yml"] = "/.github/workflows/*",
--- ["/path/from/root/of/project"] = "/.github/workflows/*",
--- },
--- },
--- }
--- })
--- ```
---
--- Currently, kubernetes is special-cased in yammls, see the following upstream issues:
--- * [#211](https://github.com/redhat-developer/yaml-language-server/issues/211).
--- * [#307](https://github.com/redhat-developer/yaml-language-server/issues/307).
---
--- To override a schema to use a specific k8s schema version (for example, to use 1.18):
---
--- ```lua
--- vim.lsp.config('yamlls', {
--- ...
--- settings = {
--- yaml = {
--- ... -- other settings. note this overrides the lspconfig defaults.
--- schemas = {
--- ["https://raw.githubusercontent.com/yannh/kubernetes-json-schema/refs/heads/master/v1.32.1-standalone-strict/all.json"] = "/*.k8s.yaml",
--- ... -- other schemas
--- },
--- },
--- }
--- })
--- ```
---@type vim.lsp.Config
return {
cmd = { 'yaml-language-server', '--stdio' },
filetypes = { 'yaml', 'yaml.docker-compose', 'yaml.gitlab', 'yaml.helm-values' },
root_markers = { '.git' },
settings = {
-- https://github.com/redhat-developer/vscode-redhat-telemetry#how-to-disable-telemetry-reporting
redhat = { telemetry = { enabled = false } },
-- formatting disabled by default in yaml-language-server; enable it
yaml = {
format = { enable = true },
validate = false, -- Disable all schema validation
},
},
on_init = function(client)
--- https://github.com/neovim/nvim-lspconfig/pull/4016
--- Since formatting is disabled by default if you check `client:supports_method('textDocument/formatting')`
--- during `LspAttach` it will return `false`. This hack sets the capability to `true` to facilitate
--- autocmd's which check this capability
client.server_capabilities.documentFormattingProvider = true
end,
}

View File

@@ -1,49 +0,0 @@
-- Automatically create a scratch buffer if Neovim starts with no files
vim.api.nvim_create_autocmd('VimEnter', {
callback = function()
-- Only trigger if no file arguments are passed
if vim.fn.argc() == 0 then
vim.cmd('enew')
vim.bo.buftype = 'nofile'
vim.bo.bufhidden = 'wipe'
vim.bo.swapfile = false
end
end,
})
-- Highlight when yanking (copying) text
vim.api.nvim_create_autocmd('TextYankPost', {
callback = function()
vim.highlight.on_yank()
end,
})
-- Disable comment continuation only when using 'o'/'O', but keep it for <Enter>
vim.api.nvim_create_autocmd('FileType', {
pattern = '*',
callback = function()
vim.opt_local.formatoptions:remove('o')
end,
})
-- Show cursor line only in active window
vim.api.nvim_create_autocmd({ 'WinEnter', 'InsertLeave' }, {
callback = function()
if vim.w.auto_cursorline then
vim.wo.cursorline = true
vim.w.auto_cursorline = nil
end
end,
})
vim.api.nvim_create_autocmd({ 'WinLeave', 'InsertEnter' }, {
callback = function()
if vim.bo.filetype == 'NvimTree' then
return
end
if vim.wo.cursorline then
vim.w.auto_cursorline = true
vim.wo.cursorline = false
end
end,
})

View File

@@ -1,25 +0,0 @@
if vim.env.CONTAINER then
vim.g.clipboard = {
name = 'osc52',
copy = {
['+'] = require('vim.ui.clipboard.osc52').copy('+'),
['*'] = require('vim.ui.clipboard.osc52').copy('*'),
},
paste = {
['+'] = require('vim.ui.clipboard.osc52').paste('+'),
['*'] = require('vim.ui.clipboard.osc52').paste('*'),
},
}
end
vim.schedule(function()
vim.opt.clipboard = 'unnamedplus'
end)
-- TEMP: Check if it helps with edge cases
vim.api.nvim_create_user_command('FixClipboard', function()
vim.cmd('lua require("vim.ui.clipboard.osc52")')
vim.schedule(function()
vim.notify('Clipboard provider reloaded (OSC52)')
end)
end, {})

View File

@@ -1,54 +0,0 @@
local map = vim.keymap.set
map('n', '<leader>q', vim.diagnostic.setloclist)
map({ 'i', 'c' }, 'jk', '<Esc>')
map('n', '<Esc>', '<cmd>nohlsearch<CR>')
-- Prevent overriding the register
map('n', 'x', '"_x')
-- Window Navigation
map('n', '<C-h>', '<C-w>h')
map('n', '<C-l>', '<C-w>l')
map('n', '<C-j>', '<C-w>j')
map('n', '<C-k>', '<C-w>k')
-- Tab management
map('n', '<Leader>tn', ':tabnew<CR>')
map('n', '<Leader>tc', ':tabclose<CR>')
map('n', '<Leader>tl', ':tabnext<CR>')
map('n', '<Leader>th', ':tabprevious<CR>')
map('n', '<Leader>tm.', ':tabmove +1<CR>')
map('n', '<Leader>tm,', ':tabmove -1<CR>')
for i = 1, 9 do
map('n', string.format('<Leader>%d', i), string.format('%dgt', i))
end
-- Buffer Management
-- map('n', '<Leader>bl', ':ls<CR>')
-- map('n', '<Leader>bd', ':bdelete<CR>')
-- map('n', ']b', ':bnext<CR>')
-- map('n', '[b', ':bprevious<CR>')
-- map('n', '<Leader>bb', ':b<Space>')
-- map('n', '<Leader>bo', ':bufdo bd|1bd<CR>')
-- Terminal
map('n', '<leader>tt', ':TermDefault<CR>')
map('n', '<leader>tr', ':TermRelative<CR>')
map('n', '<leader>ts', ':TermSplit<CR>')
map('n', '<leader>tv', ':TermVSplit<CR>')
-- Terminal mode mappings
local tn = '<C-\\><C-n>'
map('t', '<Esc>', tn)
map('t', 'jk', tn)
map('t', '<C-w>', tn .. '<C-w>')
map('t', '<C-h>', '<cmd>wincmd h<CR>')
map('t', '<C-j>', '<cmd>wincmd j<CR>')
map('t', '<C-k>', '<cmd>wincmd k<CR>')
map('t', '<C-l>', '<cmd>wincmd l<CR>')
-- File explorer
vim.keymap.set('n', '<leader>e', '<cmd>NvimTreeToggle<CR>')
vim.keymap.set('n', '<leader>E', '<cmd>NvimTreeOpen<CR>')

View File

@@ -1,62 +0,0 @@
local term_group = vim.api.nvim_create_augroup('custom-term-open', { clear = true })
vim.api.nvim_create_autocmd('TermOpen', {
group = term_group,
callback = function()
vim.opt_local.number = false
vim.opt_local.relativenumber = false
vim.opt_local.scrolloff = 0
vim.bo.filetype = 'terminal'
vim.cmd.startinsert()
end,
})
-- Close all terminal buffers before quitting
vim.api.nvim_create_autocmd('QuitPre', {
group = vim.api.nvim_create_augroup('shoutoff_terminals', { clear = true }),
callback = function()
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].buftype == 'terminal' then
vim.api.nvim_buf_delete(buf, { force = true })
end
end
end,
})
-- Insert when re-entering a terminal window (after switching back)
vim.api.nvim_create_autocmd('BufEnter', {
group = term_group,
pattern = 'term://*',
callback = function()
if vim.bo.buftype == 'terminal' and vim.fn.mode() ~= 'i' then
vim.cmd.startinsert()
end
end,
})
local function open_default()
vim.cmd('terminal')
end
local function open_relative()
local shell = vim.o.shell or 'zsh'
local dir = vim.fn.expand('%:p:h')
vim.cmd(string.format('edit term://%s//%s', dir, shell))
end
local function open_split()
vim.cmd('new')
vim.cmd('wincmd J')
vim.api.nvim_win_set_height(0, 12)
vim.wo.winfixheight = true
vim.cmd('term')
end
local function open_vertical()
vim.cmd('vsplit')
vim.cmd('term')
end
vim.api.nvim_create_user_command('TermDefault', open_default, {})
vim.api.nvim_create_user_command('TermRelative', open_relative, {})
vim.api.nvim_create_user_command('TermSplit', open_split, {})
vim.api.nvim_create_user_command('TermVSplit', open_vertical, {})

111
lua/core/events.lua Normal file
View File

@@ -0,0 +1,111 @@
require('modules.theme')
require('modules.terminal')
local api = vim.api
local au = api.nvim_create_autocmd
local group = api.nvim_create_augroup('core.events', { clear = true })
-- Automatically create a scratch buffer if Neovim starts with no files
au('VimEnter', {
group = group,
callback = function()
-- Only trigger if no file arguments are passed
if vim.fn.argc() == 0 then
vim.cmd('enew')
vim.bo.buftype = 'nofile'
vim.bo.bufhidden = 'wipe'
vim.bo.swapfile = false
end
end,
})
-- Highlight when yanking (copying) text
au('TextYankPost', {
group = group,
callback = function()
vim.highlight.on_yank({ timeout = 200 })
end,
})
-- Disable comment continuation only when using 'o'/'O', but keep it for <Enter>
au('FileType', {
group = group,
pattern = '*',
callback = function()
vim.opt_local.formatoptions:remove('o')
end,
})
-- Show cursor line only in active window
au({ 'WinEnter', 'InsertLeave' }, {
group = group,
callback = function()
if vim.w.auto_cursorline then
vim.wo.cursorline = true
vim.w.auto_cursorline = nil
end
end,
})
au({ 'WinLeave', 'InsertEnter' }, {
group = group,
callback = function()
-- Keep it on NvimTree to show current file
if vim.bo.filetype == 'NvimTree' then
return
end
if vim.wo.cursorline then
vim.w.auto_cursorline = true
vim.wo.cursorline = false
end
end,
})
-- Autocompletion
au('LspAttach', {
group = group,
callback = function(event)
local client = vim.lsp.get_client_by_id(event.data.client_id)
if not client then
return
end
-- Enable native completion
if client:supports_method('textDocument/completion') then
vim.lsp.completion.enable(true, client.id, event.buf, { autotrigger = true })
end
end,
})
vim.lsp.handlers['textDocument/completion'] = function(err, result, ctx, config)
if err or not result then
return
end
for _, item in ipairs(result.items or result) do
if item.kind then
local kind = vim.lsp.protocol.CompletionItemKind[item.kind] or ''
item.menu = '[' .. kind .. ']'
end
end
return vim.lsp.completion._on_completion_result(err, result, ctx, config)
end
au('InsertEnter', {
group = group,
once = true,
callback = function()
require('nvim-ts-autotag').setup()
require('nvim-autopairs').setup()
end,
})
au('UIEnter', {
group = group,
once = true,
callback = function()
vim.schedule(function()
require('modules.navigation')
require('plugins.language-manager').setup()
require('modules.diagnostics')
end)
end,
})

88
lua/core/keymaps.lua Normal file
View File

@@ -0,0 +1,88 @@
-- Helper functions
local function map(mode, lhs, rhs)
vim.keymap.set(mode, lhs, rhs, { silent = true })
end
local function cmd(str)
return '<cmd>' .. str .. '<CR>'
end
-- QOL
map('i', 'jk', '<Esc>')
map('i', '<C-c>', '<Esc>')
map('n', '<Esc>', cmd('nohlsearch'))
map('n', 'q:', '<nop>')
vim.keymap.set('n', 'J', 'mzJ`z')
vim.keymap.set('n', 'n', 'nzzzv')
vim.keymap.set('n', 'N', 'Nzzzv')
vim.keymap.set('x', 'J', ":m '>+1<CR>gv=gv")
vim.keymap.set('x', 'K', ":m '<-2<CR>gv=gv")
vim.keymap.set('n', '<leader>s', [[:%s/\<<C-r><C-w>\>/<C-r><C-w>/g<Left><Left><Left>]])
-- Easy to use registers
map('x', '<leader>p', '"_dP')
map({ 'n', 'x' }, '<leader>y', '"+y')
map('n', '<leader>Y', '"+y$')
map({ 'n', 'x' }, '<leader>d', '"_d')
map({ 'n', 'x' }, 'x', '"_x')
-- Window navigation
map('n', '<C-h>', '<C-w>h')
map('n', '<C-l>', '<C-w>l')
map('n', '<C-j>', '<C-w>j')
map('n', '<C-k>', '<C-w>k')
-- Tab management
map('n', ']t', cmd('tabnext'))
map('n', '[t', cmd('tabprevious'))
map('n', '<leader>tt', cmd('tabnew'))
map('n', '<leader>tn', cmd('tabnew'))
map('n', '<leader>tc', cmd('tabclose'))
map('n', '<Leader>tl', cmd('tabmove +1'))
map('n', '<Leader>th', cmd('tabmove -1'))
for i = 1, 9 do
map('n', string.format('<Leader>t%d', i), string.format('%dgt', i))
end
-- Buffer management
map('n', ']b', cmd('bnext'))
map('n', '[b', cmd('bprevious'))
map('n', '<leader>bl', cmd('ls'))
map('n', '<leader>bd', cmd(':bp | bd #'))
map('n', '<leader>bo', cmd('%bd|e#')) -- close all except current
map('n', '<leader>bb', '<C-^>') -- toggle between buffers
-- Terminal
map('n', '<leader>xx', cmd('TermDefault'))
map('n', '<leader>xr', cmd('TermRelative'))
map('n', '<leader>xs', cmd('TermSplit'))
map('n', '<leader>xv', cmd('TermVSplit'))
map('t', '<Esc>', '<C-\\><C-n>')
map('t', '<C-w>h', [[<C-\><C-n><C-w>h]])
map('t', '<C-w>j', [[<C-\><C-n><C-w>j]])
map('t', '<C-w>k', [[<C-\><C-n><C-w>k]])
map('t', '<C-w>l', [[<C-\><C-n><C-w>l]])
map('t', '<C-w>c', [[<C-\><C-n><cmd>bd!<CR>]])
map('t', '<C-w><C-w>', [[<C-\><C-n><C-w>w]])
-- File explorer
map('n', '<leader>e', cmd('NvimTreeToggle'))
map('n', '<leader>E', cmd('NvimTreeOpen'))
-- Diagnostics
map('n', ']d', function()
vim.diagnostic.jump({ count = 1, float = true })
end)
map('n', '[d', function()
vim.diagnostic.jump({ count = -1, float = true })
end)
map('n', '<leader>q', vim.diagnostic.setloclist)
map('n', '<leader>d', vim.diagnostic.open_float)
map('n', 'K', vim.lsp.buf.hover)
map('n', 'gd', vim.lsp.buf.definition)
map('n', 'gr', vim.lsp.buf.references)
map('n', '<C-s>', vim.lsp.buf.signature_help)

View File

@@ -16,11 +16,14 @@ vim.g.loaded_vimballPlugin = 1
vim.g.loaded_matchit = 1
vim.g.loaded_2html_plugin = 1
vim.g.loaded_rrhelper = 1
vim.g.loaded_tutor_mode_plugin = 1
vim.g.loaded_spellfile_plugin = 1
vim.g.loaded_logipat = 1
vim.g.loaded_rplugin = 1
vim.g.loaded_netrw = 1 -- use nvim-tree instead
vim.g.loaded_netrwPlugin = 1
-- UI
vim.g.health = { style = 'float' }
vim.g.have_nerd_font = true
vim.opt.termguicolors = false
@@ -30,10 +33,13 @@ vim.opt.colorcolumn = '+0'
vim.opt.signcolumn = 'no'
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.cursorline = true
vim.opt.cursorline = false
vim.opt.ruler = false
vim.opt.winborder = 'rounded'
vim.opt.guicursor = 'n-v-i-c:block'
vim.opt.ruler = false
vim.opt.list = true
vim.opt.listchars = { leadmultispace = '', tab = '', trail = '·' }
vim.opt.laststatus = 3
vim.opt.statusline = '── %f %h%w%m%r %= [%l,%c-%L] ──'
vim.opt.fillchars = {
@@ -64,14 +70,14 @@ vim.opt.smartindent = true -- Automatically inserts indents in code blocks (for
-- Scroll and mouse
vim.opt.scrolloff = 10
vim.opt.sidescrolloff = 5
vim.opt.mousescroll = 'hor:1,ver:5'
vim.opt.mousescroll = 'hor:1,ver:1'
vim.opt.mouse = 'a' -- Enable mouse support
-- Search
vim.opt.ignorecase = true
vim.opt.smartcase = true -- Override ignorecase if search contains upper case chars
vim.opt.inccommand = 'split' -- Live substitution preview
vim.opt.completeopt = { 'menu,menuone,noselect' }
vim.opt.completeopt = { 'fuzzy', 'menuone', 'popup', 'noselect' }
-- Splits
vim.opt.splitright = true
@@ -82,8 +88,23 @@ vim.opt.undofile = true
vim.opt.swapfile = false
-- Tweaks
vim.opt.updatetime = 1000
vim.opt.updatetime = 50
vim.opt.timeout = true
vim.opt.ttimeout = true
vim.opt.timeoutlen = 500
vim.opt.ttimeoutlen = 10
-- Clipboard
if vim.env.CONTAINER then
vim.g.clipboard = {
name = 'osc52',
copy = {
['+'] = require('vim.ui.clipboard.osc52').copy('+'),
['*'] = require('vim.ui.clipboard.osc52').copy('*'),
},
paste = {
['+'] = require('vim.ui.clipboard.osc52').paste('+'),
['*'] = require('vim.ui.clipboard.osc52').paste('*'),
},
}
end

View File

@@ -1,323 +0,0 @@
-- Minimal fuzzy finder + content search for Neovim 0.11+
-- Optional: `fdfind` or `fd` for file listing, and `rg` (ripgrep) for text search.
local Fuzzy = {}
--------------------------------------------------------------------
-- 🧩 Helpers
--------------------------------------------------------------------
-- Collect all files (try fdfind/fd first, then globpath)
local function get_file_list()
local handle = io.popen('fdfind --type f 2>/dev/null || fd --type f 2>/dev/null')
if handle then
local result = handle:read('*a')
handle:close()
if result and result ~= '' then
return vim.split(result, '\n', { trimempty = true })
end
end
return vim.fn.globpath('.', '**/*', false, true)
end
-- Create floating input + result windows
local function open_float(prompt)
local input_buf = vim.api.nvim_create_buf(false, true)
local result_buf = vim.api.nvim_create_buf(false, true)
-- mark both buffers as scratch/unlisted
for _, b in ipairs({ input_buf, result_buf }) do
vim.bo[b].bufhidden = 'wipe'
vim.bo[b].buflisted = false
vim.bo[b].swapfile = false
end
vim.bo[input_buf].buftype = 'prompt'
vim.bo[result_buf].buftype = 'nofile'
local width = math.floor(vim.o.columns * 0.7)
local height = 20
local row = math.floor((vim.o.lines - height) / 2)
local col = math.floor((vim.o.columns - width) / 2)
local input_win = vim.api.nvim_open_win(input_buf, true, {
relative = 'editor',
row = row,
col = col,
width = width,
height = 1,
style = 'minimal',
border = 'rounded',
})
vim.fn.prompt_setprompt(input_buf, prompt)
local result_win = vim.api.nvim_open_win(result_buf, false, {
relative = 'editor',
row = row + 2,
col = col,
width = width,
height = height - 2,
style = 'minimal',
border = 'single',
})
return input_buf, result_buf, input_win, result_win
end
--------------------------------------------------------------------
-- 🔵 Highlight current selection
--------------------------------------------------------------------
function Fuzzy:highlight_selection()
if not self.result_buf then
return
end
if not self.ns_id then
self.ns_id = vim.api.nvim_create_namespace('FuzzyHighlight')
end
vim.api.nvim_buf_clear_namespace(self.result_buf, self.ns_id, 0, -1)
if self.matches and self.matches[self.cursor] then
local rel_cursor = self.cursor - (self.scroll or 0)
if rel_cursor >= 1 and rel_cursor <= self.page_size then
vim.api.nvim_buf_set_extmark(self.result_buf, self.ns_id, rel_cursor - 1, 0, {
end_line = rel_cursor,
hl_group = 'Visual',
hl_eol = true,
})
end
end
end
--------------------------------------------------------------------
-- 🔴 Close all floating windows
--------------------------------------------------------------------
function Fuzzy.close()
local wins = { Fuzzy.input_win, Fuzzy.result_win }
for _, win in ipairs(wins) do
if win and vim.api.nvim_win_is_valid(win) then
vim.api.nvim_win_close(win, true)
end
end
Fuzzy.active = false
end
--------------------------------------------------------------------
-- 🟢 File finder
--------------------------------------------------------------------
function Fuzzy.open()
if Fuzzy.active then
Fuzzy.close()
end
Fuzzy.active = true
Fuzzy.files = get_file_list()
Fuzzy.matches = Fuzzy.files
Fuzzy.cursor = 1
Fuzzy.scroll = 0
Fuzzy.page_size = 50
Fuzzy.input_buf, Fuzzy.result_buf, Fuzzy.input_win, Fuzzy.result_win = open_float('Search: ')
local function render_results()
local total = #Fuzzy.matches
if total == 0 then
vim.api.nvim_buf_set_lines(Fuzzy.result_buf, 0, -1, false, { '-- no matches --' })
return
end
local start_idx = Fuzzy.scroll + 1
local end_idx = math.min(start_idx + Fuzzy.page_size - 1, total)
local display = {}
for i = start_idx, end_idx do
display[#display + 1] = Fuzzy.matches[i]
end
vim.api.nvim_buf_set_lines(Fuzzy.result_buf, 0, -1, false, display)
Fuzzy:highlight_selection()
end
local function update_results(text)
if text == '' then
Fuzzy.matches = Fuzzy.files
else
Fuzzy.matches = vim.fn.matchfuzzy(Fuzzy.files, text)
end
Fuzzy.cursor, Fuzzy.scroll = 1, 0
render_results()
end
vim.api.nvim_create_autocmd({ 'TextChangedI', 'TextChangedP' }, {
buffer = Fuzzy.input_buf,
callback = function()
local text = vim.fn.getline('.'):gsub('^Search:%s*', '')
update_results(text)
end,
})
vim.keymap.set('i', '<C-n>', function()
if Fuzzy.cursor < #Fuzzy.matches then
Fuzzy.cursor = Fuzzy.cursor + 1
if Fuzzy.cursor > Fuzzy.scroll + Fuzzy.page_size then
Fuzzy.scroll = Fuzzy.scroll + 1
end
render_results()
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<C-p>', function()
if Fuzzy.cursor > 1 then
Fuzzy.cursor = Fuzzy.cursor - 1
if Fuzzy.cursor <= Fuzzy.scroll then
Fuzzy.scroll = math.max(Fuzzy.scroll - 1, 0)
end
render_results()
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<CR>', function()
local choice = Fuzzy.matches[Fuzzy.cursor]
if choice then
Fuzzy.close()
vim.cmd.edit(vim.fn.fnameescape(choice))
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<Esc>', Fuzzy.close, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<C-c>', Fuzzy.close, { buffer = Fuzzy.input_buf })
vim.keymap.set('n', '<Esc>', Fuzzy.close, { buffer = Fuzzy.input_buf })
vim.keymap.set('n', 'q', Fuzzy.close, { buffer = Fuzzy.input_buf })
vim.cmd.startinsert()
end
--------------------------------------------------------------------
-- 🟣 Ripgrep-based content search (scrolling + match highlighting)
--------------------------------------------------------------------
function Fuzzy.open_grep()
if Fuzzy.active then
Fuzzy.close()
end
Fuzzy.active = true
Fuzzy.input_buf, Fuzzy.result_buf, Fuzzy.input_win, Fuzzy.result_win = open_float('Grep: ')
Fuzzy.matches, Fuzzy.cursor, Fuzzy.scroll = {}, 1, 0
Fuzzy.page_size = 50
Fuzzy.ns_id = vim.api.nvim_create_namespace('FuzzyHighlight')
local function render_results(query)
local total = #Fuzzy.matches
if total == 0 then
vim.api.nvim_buf_set_lines(Fuzzy.result_buf, 0, -1, false, { '-- no matches --' })
return
end
local start_idx = Fuzzy.scroll + 1
local end_idx = math.min(start_idx + Fuzzy.page_size - 1, total)
local display = {}
for i = start_idx, end_idx do
display[#display + 1] = Fuzzy.matches[i]
end
vim.api.nvim_buf_set_lines(Fuzzy.result_buf, 0, -1, false, display)
vim.api.nvim_buf_clear_namespace(Fuzzy.result_buf, Fuzzy.ns_id, 0, -1)
-- highlight selection
local rel_cursor = math.min(Fuzzy.cursor - Fuzzy.scroll, #display)
vim.api.nvim_buf_set_extmark(Fuzzy.result_buf, Fuzzy.ns_id, rel_cursor - 1, 0, {
end_line = rel_cursor,
hl_group = 'Visual',
hl_eol = true,
})
-- highlight query matches
if query and query ~= '' then
local pattern = vim.pesc(query)
for i, line in ipairs(display) do
for s, e in line:gmatch('()' .. pattern .. '()') do
vim.api.nvim_buf_set_extmark(Fuzzy.result_buf, Fuzzy.ns_id, i - 1, s - 1, {
end_col = e - 1,
hl_group = 'Search',
})
end
end
end
end
local function run_grep(query)
if query == '' then
vim.api.nvim_buf_set_lines(Fuzzy.result_buf, 0, -1, false, { '-- type to search --' })
return
end
local handle = io.popen('rg --vimgrep --hidden --smart-case ' .. vim.fn.shellescape(query))
if not handle then
return
end
local result = handle:read('*a')
handle:close()
Fuzzy.matches = vim.split(result, '\n', { trimempty = true })
Fuzzy.cursor, Fuzzy.scroll = 1, 0
render_results(query)
end
vim.api.nvim_create_autocmd({ 'TextChangedI', 'TextChangedP' }, {
buffer = Fuzzy.input_buf,
callback = function()
local text = vim.fn.getline('.'):gsub('^Grep:%s*', '')
run_grep(text)
end,
})
vim.keymap.set('i', '<C-n>', function()
if Fuzzy.cursor < #Fuzzy.matches then
Fuzzy.cursor = Fuzzy.cursor + 1
if Fuzzy.cursor > Fuzzy.scroll + Fuzzy.page_size then
Fuzzy.scroll = Fuzzy.scroll + 1
end
local query = vim.fn.getline('.'):gsub('^Grep:%s*', '')
render_results(query)
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<C-p>', function()
if Fuzzy.cursor > 1 then
Fuzzy.cursor = Fuzzy.cursor - 1
if Fuzzy.cursor <= Fuzzy.scroll then
Fuzzy.scroll = math.max(Fuzzy.scroll - 1, 0)
end
local query = vim.fn.getline('.'):gsub('^Grep:%s*', '')
render_results(query)
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<CR>', function()
local line = Fuzzy.matches[Fuzzy.cursor]
if line then
local parts = vim.split(line, ':')
local file, lnum = parts[1], tonumber(parts[2]) or 1
Fuzzy.close()
vim.cmd.edit(vim.fn.fnameescape(file))
vim.api.nvim_win_set_cursor(0, { lnum, 0 })
end
end, { buffer = Fuzzy.input_buf })
vim.keymap.set('i', '<Esc>', function()
Fuzzy.close()
end, { buffer = Fuzzy.input_buf })
vim.cmd.startinsert()
end
--------------------------------------------------------------------
-- 🧩 Commands & Keymaps
--------------------------------------------------------------------
vim.api.nvim_create_user_command('FuzzyLive', function()
Fuzzy.open()
end, {})
vim.api.nvim_create_user_command('FuzzyGrep', function()
Fuzzy.open_grep()
end, {})
vim.keymap.set('n', '<leader>f', function()
vim.cmd.FuzzyLive()
end, { desc = 'Open fuzzy file finder' })
vim.keymap.set('n', '<leader>g', function()
vim.cmd.FuzzyGrep()
end, { desc = 'Search file contents with ripgrep' })
return Fuzzy

View File

@@ -0,0 +1,42 @@
-- Diagnostics
local special_sources = {
lua_ls = 'lua',
}
vim.diagnostic.config({
underline = true,
severity_sort = true,
virtual_text = {
format = function(diagnostic)
local src = diagnostic.source and (special_sources[diagnostic.source] or diagnostic.source)
if src then
return string.format('%s: %s', src, diagnostic.message)
end
return diagnostic.message
end,
},
float = {
border = 'rounded',
header = '',
format = function(diagnostic)
local src = diagnostic.source and (special_sources[diagnostic.source] or diagnostic.source)
if src then
return string.format('%s: %s', src, diagnostic.message)
end
return diagnostic.message
end,
},
})
-- Override the virtual text diagnostic handler so that the most severe diagnostic is shown first.
local show_handler = vim.diagnostic.handlers.virtual_text.show
assert(show_handler)
local hide_handler = vim.diagnostic.handlers.virtual_text.hide
vim.diagnostic.handlers.virtual_text = {
show = function(ns, bufnr, diagnostics, opts)
table.sort(diagnostics, function(diag1, diag2)
return diag1.severity > diag2.severity
end)
return show_handler(ns, bufnr, diagnostics, opts)
end,
hide = hide_handler,
}

View File

@@ -0,0 +1,48 @@
local M = {}
-- vim.filetype.add({
-- pattern = {
-- ['.*/templates/.*%.ya?ml'] = 'yaml.helm-values',
-- ['.*/templates/.*%.tpl'] = 'yaml.helm-values',
-- },
-- })
-- vim.api.nvim_create_autocmd({ 'BufNewFile', 'BufRead' }, {
-- pattern = '**/templates/**/*.y?ml',
-- callback = function()
-- vim.bo.filetype = 'yaml.helm-values'
-- end,
-- })
--
function M.get()
return {
-- {
-- ft = 'helm',
-- ts = 'helm',
-- lsp = 'helm-ls',
-- },
{
ft = 'yaml',
ts = 'yaml',
lsp = 'yaml-language-server',
format = { 'prettierd', 'prettier' },
},
{ ts = { 'yaml', 'toml', 'sql', 'diff', 'dockerfile', 'gitcommit', 'gitignore' } },
{ ts = { 'c', 'cpp', 'go', 'rust', 'python' } },
{ ft = 'markdown', ts = { 'markdown', 'markdown_inline' }, format = 'prettier' },
{ ft = 'bash', lsp = 'bash-language-server', lint = 'shellcheck', format = 'shfmt' },
{ ft = 'lua', lsp = 'lua-language-server', lint = 'luacheck', format = 'stylua' },
{ ft = { 'json', 'jsonc' }, lsp = 'json-lsp' },
{ ft = 'html', lsp = 'html-lsp' },
{ ft = 'css', lsp = { 'css-lsp', 'tailwindcss-language-server' } },
{
ft = { 'javascript', 'typescript', 'javascriptreact', 'typescriptreact' },
ts = { 'javascript', 'typescript', 'tsx' },
lsp = { 'vtsls', 'eslint-lsp' },
format = { 'prettierd', 'prettier' },
},
}
end
return M

View File

@@ -0,0 +1,12 @@
require('plugins.filetree')
local finder = require('plugins.finder')
finder.setup({
exclude_patterns = { 'node_modules', 'dist', 'build', '.git', '.cache', '.turbo', '*-lock.json' },
use_disk_cache = true,
follow_symlinks = true,
})
vim.keymap.set('n', '<leader>f', finder.files)
vim.keymap.set('n', '<leader>g', finder.grep)
-- vim.keymap.set('n', '<leader>fc', finder.clear_cache)
-- vim.keymap.set('n', '<leader>fD', finder.diagnose)

67
lua/modules/terminal.lua Normal file
View File

@@ -0,0 +1,67 @@
local api = vim.api
local au = api.nvim_create_autocmd
local group = api.nvim_create_augroup('triimd.term', { clear = true })
-- Custom terminal
au('TermOpen', {
group = group,
callback = function()
vim.opt_local.number = false
vim.opt_local.relativenumber = false
vim.opt_local.scrolloff = 0
vim.bo.filetype = 'terminal'
vim.cmd.startinsert()
end,
})
-- Insert when re-entering a terminal window (after switching back)
au('BufEnter', {
group = group,
pattern = 'term://*',
callback = function()
if vim.bo.buftype == 'terminal' and vim.fn.mode() ~= 'i' then
vim.cmd.startinsert()
end
end,
})
-- Close all terminal buffers before quitting
au('QuitPre', {
group = group,
callback = function()
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].buftype == 'terminal' then
vim.api.nvim_buf_delete(buf, { force = true })
end
end
end,
})
local commands = {
TermDefault = function()
vim.cmd('terminal')
end,
TermRelative = function()
local shell = vim.o.shell or 'zsh'
local dir = vim.fn.expand('%:p:h')
vim.cmd(string.format('edit term://%s//%s', dir, shell))
end,
TermSplit = function()
vim.cmd('new')
vim.cmd('wincmd J')
vim.api.nvim_win_set_height(0, 12)
vim.wo.winfixheight = true
vim.cmd('term')
end,
TermVSplit = function()
vim.cmd('vsplit')
vim.cmd('term')
end,
}
for name, fn in pairs(commands) do
vim.api.nvim_create_user_command(name, fn, {})
end

54
lua/modules/theme.lua Normal file
View File

@@ -0,0 +1,54 @@
local M = {}
function M.load_theme()
require('invero').setup({
highlights = function(c, tool)
c.bg_float = tool(152)
return {
FinderPath = { fg = c.muted },
Whitespace = { fg = c.outline_light },
ModeMsg = { fg = c.yellow, bg = c.none, bold = true },
WinSeparator = { fg = c.outline, bg = c.base },
StatusLine = { fg = c.outline, bg = c.base, bold = false },
StatusLineNC = { fg = c.text, bg = c.base, bold = false },
TabLine = { fg = c.muted, bg = c.black },
TabLineSel = { fg = c.base, bg = c.black, bold = true },
TabLineFill = { bg = c.black },
Pmenu = { fg = c.text, bg = c.surface },
PmenuSel = { fg = c.text, bg = c.accent_light },
QuickFixLine = { fg = c.accent, bg = c.none, bold = true },
Special = { fg = c.syntax, bg = c.none, bold = false, italic = true },
['@lsp'] = { fg = c.syntax, bg = c.none },
['@variable'] = { fg = c.syntax, bg = c.none },
['@markup.list.unchecked.markdown'] = {
fg = c.syntax,
bg = c.none,
bold = false,
italic = false,
},
['@markup.list.checked.markdown'] = {
fg = c.syntax,
bg = c.none,
bold = false,
italic = false,
},
}
end,
})
vim.o.background = 'light'
vim.cmd.colorscheme('invero')
end
vim.api.nvim_create_user_command('ReloadInvero', function()
package.loaded['invero'] = nil
package.loaded['modules.theme'] = nil
require('invero').invalidate_cache()
require('modules.theme').load_theme()
end, {})
M.load_theme()
require('plugins.tabline').setup()
return M

View File

@@ -1,26 +0,0 @@
return {
'triimdev/invero.nvim',
lazy = false,
priority = 1000,
dev = true,
config = function()
vim.api.nvim_create_user_command('ReloadInvero', function()
require('invero').invalidate_cache()
vim.cmd('Lazy reload invero.nvim')
end, {})
require('invero').setup({
highlights = function(c, tool)
c.bg_float = tool(152)
return {
WinSeparator = { fg = c.outline, bg = c.base },
StatusLine = { fg = c.outline, bg = c.base },
StatusLineNC = { fg = c.text, bg = c.base, bold = true },
}
end,
})
vim.o.background = 'light'
vim.cmd.colorscheme('invero')
end,
}

View File

@@ -46,103 +46,78 @@ local function my_on_attach(bufnr)
vim.keymap.set('n', 'U', api.tree.reload, opts)
end
return {
'nvim-tree/nvim-tree.lua',
version = '*',
dev = true,
opts = {
on_attach = my_on_attach,
view = { signcolumn = 'no' },
actions = { file_popup = { open_win_config = { border = 'rounded' } } },
renderer = {
root_folder_label = false,
-- root_folder_label = function(path)
-- return '-- ' .. vim.fn.fnamemodify(path, ':t') .. ' --'
-- end,
special_files = {},
require('nvim-tree').setup({
on_attach = my_on_attach,
view = { signcolumn = 'no' },
actions = { file_popup = { open_win_config = { border = 'rounded' } } },
renderer = {
root_folder_label = false,
special_files = {},
highlight_hidden = 'all',
highlight_clipboard = 'all',
highlight_hidden = 'all',
highlight_clipboard = 'all',
indent_markers = {
enable = true,
inline_arrows = false,
icons = { corner = '', none = '', bottom = ' ' },
indent_markers = {
enable = true,
inline_arrows = false,
icons = { corner = '', none = '', bottom = ' ' },
},
icons = {
bookmarks_placement = 'after',
git_placement = 'after',
show = {
file = false,
folder = false,
folder_arrow = false,
git = true,
modified = false,
hidden = false,
diagnostics = false,
bookmarks = true,
},
icons = {
bookmarks_placement = 'after',
git_placement = 'after',
show = {
file = false,
folder = false,
folder_arrow = false, -- KEEP FALSE
git = true,
modified = false,
hidden = false,
diagnostics = false,
bookmarks = true,
glyphs = {
git = {
unstaged = '',
staged = '',
unmerged = '',
renamed = '',
untracked = '',
deleted = '',
ignored = '',
},
glyphs = {
-- default = '•',
default = ' ',
symlink = '',
bookmark = '󰆤',
modified = '',
hidden = '󰜌',
folder = {
arrow_closed = '',
arrow_open = '',
default = '',
open = '',
empty = '',
empty_open = '',
symlink = '',
symlink_open = '',
},
git = {
unstaged = '', -- '✗',
staged = '',
unmerged = '',
renamed = '',
untracked = '',
deleted = '', -- '󰧧',
ignored = '',
},
},
},
},
hijack_cursor = true,
prefer_startup_root = true,
update_focused_file = {
enable = true,
update_root = { enable = true, ignore_list = {} },
exclude = false,
},
modified = { enable = true, show_on_dirs = true, show_on_open_dirs = true },
filters = {
enable = true,
git_ignored = true,
dotfiles = false,
git_clean = false,
no_buffer = false,
no_bookmark = false,
custom = {},
exclude = {},
},
filesystem_watchers = {
enable = true,
debounce_delay = 50,
ignore_dirs = {
'/.git',
'/.DS_Store',
'/build',
'/dist',
'/public',
'/node_modules',
'/target',
},
},
},
}
hijack_cursor = true,
prefer_startup_root = true,
update_focused_file = {
enable = true,
update_root = { enable = true, ignore_list = {} },
exclude = false,
},
modified = { enable = true, show_on_dirs = true, show_on_open_dirs = true },
filters = {
enable = true,
git_ignored = false,
dotfiles = false,
git_clean = false,
no_buffer = false,
no_bookmark = false,
custom = {},
exclude = {},
},
filesystem_watchers = {
enable = true,
debounce_delay = 50,
ignore_dirs = {
'/.git',
'/.DS_Store',
'/build',
'/dist',
'/public',
'/node_modules',
'/target',
},
},
})

1046
lua/plugins/finder.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,359 @@
local utils = require('utils')
local M = {
ts = {},
lsp = {},
lint = {},
format = {},
}
M.group = vim.api.nvim_create_augroup('language-manager', { clear = true })
local cache_path = vim.fn.stdpath('cache') .. '/language-manager.json'
local function wrap(item)
if type(item) == 'string' then
return { item }
elseif type(item) == 'table' then
return item
else
return {}
end
end
local function create_set()
local seen = {}
return function(ref, item)
if not seen[ref] then
seen[ref] = {}
end
if item and not seen[ref][item] then
seen[ref][item] = true
return true
end
return false
end
end
local function read_file(path)
local f = io.open(path, 'r')
if not f then
return nil
end
local content = f:read('*a')
f:close()
return content
end
local function write_file(path, content)
local f = io.open(path, 'w')
if not f then
return false
end
f:write(content)
f:close()
return true
end
local function to_json(tbl)
local ok, result = pcall(vim.json.encode, tbl)
return ok and result or nil
end
local function from_json(str)
local ok, result = pcall(vim.json.decode, str)
return ok and result or nil
end
local function hash_spec(tbl)
local encoded = to_json(tbl) or ''
if vim.fn.exists('*sha256') == 1 then
return vim.fn.sha256(encoded)
else
local tmp = vim.fn.tempname()
write_file(tmp, encoded)
local handle = io.popen('openssl dgst -sha256 ' .. tmp)
local result = handle and handle:read('*a') or ''
if handle then
handle:close()
end
return result:match('([a-f0-9]+)') or ''
end
end
local function save_cache(data)
local encoded = to_json(data)
if encoded then
write_file(cache_path, encoded)
end
end
local function load_cache()
local raw = read_file(cache_path)
if not raw then
return nil
end
return from_json(raw)
end
-- ======== Spec Builder ========
local function create_spec()
local S = {}
local unique = create_set()
local specs = {}
function S.set(item, group)
specs[group] = item
end
function S.get()
return specs
end
function S.add(list, ...)
local groups = { ... }
local ref = table.concat(groups, '.')
local pointer = specs
local last_i = #groups
for i = 1, last_i do
local group = groups[i]
if i == last_i then
for _, item in ipairs(wrap(list)) do
if unique(ref, item) then
pointer[group] = pointer[group] or {}
table.insert(pointer[group], item)
end
end
else
pointer[group] = pointer[group] or {}
pointer = pointer[group]
end
end
end
return S
end
-- ======== Spec Generation ========
local function get_mason_registry()
vim.cmd.packadd('mason.nvim')
require('mason').setup()
local registry = require('mason-registry')
registry.refresh()
return registry
end
function M.generate_specs(specs_raw)
local install_spec = create_spec()
local specs = create_spec()
local registry = get_mason_registry()
local lsp_map = {}
for _, spec in ipairs(specs_raw) do
if type(spec) == 'string' then
spec = { ft = spec }
end
spec.ts = spec.ts or spec.ft
specs.add(spec.ts, 'ts_parsers')
install_spec.add(spec.lsp, 'code_tools')
local resolved_lsps = {}
for _, language_server in ipairs(wrap(spec.lsp)) do
if registry.has_package(language_server) then
local pkg = registry.get_package(language_server)
if pkg.spec and pkg.spec.neovim and pkg.spec.neovim.lspconfig then
local lspconfig_name = pkg.spec and pkg.spec.neovim and pkg.spec.neovim.lspconfig
lsp_map[lspconfig_name] = language_server
table.insert(resolved_lsps, lspconfig_name)
else
print('Package found but not lspconfig name: ' .. language_server)
end
else
print('Package not found: ' .. language_server)
end
end
specs.add(resolved_lsps, 'language_servers')
install_spec.add(spec.lint, 'code_tools')
install_spec.add(spec.format, 'code_tools')
for _, ft in ipairs(wrap(spec.ft)) do
specs.add(spec.lint, 'linters_by_ft', ft)
specs.add(spec.format, 'formatters_by_ft', ft)
end
end
local result = specs.get()
result.lsp_map = lsp_map
return result, install_spec.get()
end
-- ======== Cache ========
function M.load_specs()
local cache = load_cache()
if cache then
M.general = cache.spec
else
local specs_raw = require('modules.language-specs').get()
M.general, M.mason = M.generate_specs(specs_raw)
save_cache({ hash = hash_spec(specs_raw), spec = M.general })
end
return M.general, M.mason
end
function M.invalidate_cache()
local ok = os.remove(cache_path)
if ok then
vim.notify('Language manager cache invalidated', vim.log.levels.INFO)
else
vim.notify('No cache to invalidate or failed to delete', vim.log.levels.WARN)
end
M.general = nil
M.mason = nil
end
function M.ts.install()
vim.cmd.packadd('nvim-treesitter')
local ts_install = require('nvim-treesitter.install').ensure_installed_sync
ts_install(M.general.ts_parsers)
end
function M.mason_install()
local packages = M.mason.code_tools
local registry = get_mason_registry()
local pending = #packages
local result = utils.await(function(resolve)
for _, name in ipairs(packages) do
local pkg = registry.get_package(name)
if pkg:is_installed() then
print('Mason package already installed: ' .. name)
pending = pending - 1
if pending == 0 then
resolve(true)
end
else
print('Mason package installing: ' .. name)
pkg:install({}, function(success, error)
if success then
print('Mason package installed: ' .. name)
else
print('Mason package failed: ' .. name)
print(' > Error: ' .. vim.inspect(error))
end
pending = pending - 1
if pending == 0 then
resolve(true)
end
end)
end
end
end, 5 * 60 * 1000, 200)
if not result.ok or pending ~= 0 then
print('\n!! >> Exited timeout, possible clean up needed!')
print(' > status: ' .. result.ok)
print(' > pending: ' .. pending)
end
end
-- ======== Public API ========
function M.install()
print('\n> Starting ts parsers install')
M.ts.install()
print('\n> Starting mason install: lsp, lint, format')
M.mason_install()
end
function M.ts.setup()
require('nvim-treesitter.configs').setup({
highlight = { enable = true },
incremental_selection = { enable = true },
})
end
function M.lsp.setup()
for _, lsp_name in ipairs((M.general and M.general.language_servers) or {}) do
vim.lsp.enable(lsp_name)
end
vim.api.nvim_buf_create_user_command(0, 'LspInfo', function()
vim.cmd('checkhealth vim.lsp')
end, {})
end
function M.lint.setup()
vim.api.nvim_create_autocmd({ 'BufReadPre', 'BufNewFile' }, {
group = M.group,
once = true,
callback = function()
local lint = require('lint')
lint.linters_by_ft = M.general.linters_by_ft
function M.debounce(ms, fn)
local timer = vim.uv.new_timer()
return function(...)
local argv = { ... }
timer:start(ms, 0, function()
timer:stop()
vim.schedule_wrap(fn)(unpack(argv))
end)
end
end
function M.lint()
if vim.bo.modifiable then
lint.try_lint()
end
end
vim.api.nvim_create_autocmd({ 'BufReadPost', 'InsertLeave', 'TextChanged' }, {
group = vim.api.nvim_create_augroup('language-manager.lint', { clear = true }),
callback = M.debounce(100, M.lint),
})
vim.api.nvim_create_autocmd('BufEnter', {
group = M.group,
callback = function(args)
local bufnr = args.buf
local ft = vim.bo[bufnr].filetype
local linters = lint.linters_by_ft[ft]
if linters then
vim.api.nvim_buf_create_user_command(bufnr, 'LintInfo', function()
print('Linters for ' .. ft .. ': ' .. table.concat(linters, ', '))
end, {})
end
end,
})
end,
})
end
function M.format.setup()
require('conform').setup({
formatters_by_ft = (M.general and M.general.formatters_by_ft) or {},
default_format_opts = { stop_after_first = true, lsp_format = 'fallback' },
format_on_save = { timeout_ms = 500 },
})
end
function M.setup()
M.load_specs()
M.ts.setup()
M.lsp.setup()
M.lint.setup()
M.format.setup()
end
return M

View File

@@ -1,128 +0,0 @@
vim.keymap.set('n', '<leader>d', vim.diagnostic.open_float, { noremap = true, silent = true })
vim.diagnostic.config({
update_in_insert = false,
virtual_text = {
prefix = '', -- remove annoying ▎ etc
format = function(diagnostic)
if diagnostic.source then
return string.format('[%s] %s', diagnostic.source, diagnostic.message)
end
return diagnostic.message
end,
},
float = {
border = 'rounded',
source = true, -- show source in floating window too
},
severity_sort = true,
})
vim.lsp.enable({ 'lua_ls' })
vim.lsp.enable({ 'json_ls' })
return {
{ 'mason-org/mason.nvim', config = true },
{ 'windwp/nvim-ts-autotag', config = true },
{ 'windwp/nvim-autopairs', event = 'InsertEnter', config = true },
-- { 'saghen/blink.cmp', version = '1.*' },
{
'nvim-treesitter/nvim-treesitter',
build = ':TSUpdate',
main = 'nvim-treesitter.configs',
opts = {
highlight = { enable = true },
incremental_selection = { enable = true },
textobjects = { enable = true },
ensure_installed = {
-- Documentation
'vim',
'vimdoc',
'markdown',
'markdown_inline',
-- Data
'gitcommit',
'gitignore',
'dockerfile',
'diff',
'json',
'jsonc',
-- Scripting
'bash',
'lua',
'sql',
-- Programming
'c',
'cpp',
'go',
'rust',
'python',
-- Web
'html',
'css',
'javascript',
'typescript',
'tsx',
},
},
},
{
'mfussenegger/nvim-lint',
event = { 'BufReadPre', 'BufNewFile' },
opts = {
linters_by_ft = {
lua = { 'luacheck' },
python = { 'ruff' },
javascript = { 'eslint_d' },
},
},
config = function(_, opts)
local lint = require('lint')
lint.linters_by_ft = opts.linters_by_ft
vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, {
group = vim.api.nvim_create_augroup('lint_autocmd', { clear = true }),
callback = function()
lint.try_lint()
end,
})
end,
},
{
'stevearc/conform.nvim',
event = { 'BufWritePre' },
opts = {
-- Automatically format on save
format_on_save = {
timeout_ms = 500,
lsp_format = 'fallback', -- Use LSP when no formatter is configured
},
-- Formatters per filetype
default_format_opts = { stop_after_first = true },
formatters_by_ft = {
lua = { 'stylua' },
sh = { 'shfmt' },
swift = { 'swift_format' },
python = { 'isort', 'black' },
json = { 'jq' },
javascript = { 'prettierd', 'prettier' },
javascriptreact = { 'prettierd', 'prettier' },
typescript = { 'prettierd', 'prettier' },
typescriptreact = { 'prettierd', 'prettier' },
},
},
config = function(_, opts)
require('conform').setup(opts)
-- Create a command to format manually
vim.api.nvim_create_user_command('Format', function()
require('conform').format({
async = true,
lsp_format = 'fallback',
})
end, { desc = 'Format current buffer' })
end,
},
}

83
lua/plugins/tabline.lua Normal file
View File

@@ -0,0 +1,83 @@
local M = {}
-- Helper to get label for each tab page
local function tab_label(n)
local buflist = vim.fn.tabpagebuflist(n)
local winnr = vim.fn.tabpagewinnr(n)
local bufname = vim.fn.bufname(buflist[winnr])
if bufname == '' then
bufname = '[No Name]'
else
bufname = vim.fn.fnamemodify(bufname, ':t') -- tail only
end
-- Determine window count reliably
local win_count = vim.fn.tabpagewinnr(n, '$')
-- Check if any buffer in the tab is modified
local modified = false
for _, buf in ipairs(buflist) do
if vim.fn.getbufvar(buf, '&modified') == 1 then
modified = true
break
end
end
-- Construct label according to rules:
-- single clean: File
-- single edited: +:File
-- multi clean: 2:File
-- multi edited: 2+:File
if win_count == 1 then
if modified then
bufname = '+:' .. bufname
end
else
local prefix = tostring(win_count)
if modified then
prefix = prefix .. '+'
end
bufname = prefix .. ':' .. bufname
end
-- Truncate overly long names
if #bufname > 20 then
bufname = bufname:sub(1, 17) .. ''
end
return bufname
end
-- Main tabline builder
function M.tabline()
local s = ''
local num_tabs = vim.fn.tabpagenr('$')
for i = 1, num_tabs do
-- Highlight current tab
if i == vim.fn.tabpagenr() then
s = s .. '%#TabLineSel#'
else
s = s .. '%#TabLine#'
end
-- Mouse click target
s = s .. '%' .. i .. 'T'
-- Label
s = s .. ' ' .. tab_label(i) .. ' '
end
-- Fill empty space
s = s .. '%#TabLineFill#%T'
return s
end
function M.setup()
vim.opt.showtabline = 1
vim.opt.tabline = "%!v:lua.require'plugins.tabline'.tabline()"
end
return M

102
lua/setup/init.lua Normal file
View File

@@ -0,0 +1,102 @@
local function clone_package_manager()
local path = vim.fn.stdpath('data') .. '/site/pack/paqs/opt/paq-nvim'
if not vim.uv.fs_stat(path) then
local repo = 'https://github.com/savq/paq-nvim.git'
local cmd = { 'git', 'clone', '--depth=1', repo, path }
local result = vim.system(cmd):wait()
if result.code == 0 then
print('Package manager installed correctly')
end
end
end
local function load_paq()
vim.cmd.packadd('paq-nvim')
local paq = require('paq')
local packages = require('setup.packages').get()
paq:setup({ lock = vim.fn.stdpath('config') .. '/paq-lock.json' })(packages)
return paq
end
local function install_packages()
local done = false
vim.api.nvim_create_autocmd('User', {
pattern = 'PaqDoneInstall',
once = true,
callback = function()
done = true
end,
})
local paq = load_paq()
paq.install()
local to_install = paq.query('to_install')
if #to_install == 0 then
return
end
vim.wait(60000, function()
return done
end, 200)
if not done then
print('Paq installation timeout or failed')
else
print('Paq installation completed')
end
end
local function install_languages()
vim.cmd.packadd('mason.nvim')
require('mason').setup()
local lm = require('plugins.language-manager')
lm.invalidate_cache()
lm.load_specs()
lm.install()
end
vim.api.nvim_create_user_command('InstallAll', function()
print('> Starting clone package manager...')
clone_package_manager()
print('\n> Starting installing packages...')
install_packages()
print('\n> Starting installing languages: ts parsers, language servers, linters, formatters...')
install_languages()
print('\n=== Install Finished ===\n\n')
end, {})
vim.api.nvim_create_user_command('Sync', function()
local paq = load_paq()
paq:sync()
end, {})
vim.api.nvim_create_user_command('FetchLspConfigs', function()
-- local base_url = 'https://raw.githubusercontent.com/neovim/nvim-lspconfig/master/lsp/'
local base_url = 'https://raw.githubusercontent.com/neovim/nvim-lspconfig/refs/heads/master/lsp/'
local lm = require('plugins.language-manager')
lm.invalidate_cache()
local general = lm.load_specs()
local lsp_dir = vim.fs.joinpath(vim.fn.getcwd(), 'lsp')
vim.fn.mkdir(lsp_dir, 'p')
for _, name in ipairs(general.language_servers or {}) do
local file = vim.fs.joinpath(lsp_dir, name .. '.lua')
if vim.fn.filereadable(file) == 0 then
local url = base_url .. name .. '.lua'
local cmd = string.format('curl -fsSL -o %q %q', file, url)
vim.fn.system(cmd)
if vim.v.shell_error ~= 0 then
vim.notify('Failed to fetch ' .. name .. '.lua', vim.log.levels.ERROR)
vim.fn.delete(file)
else
vim.notify('Fetched ' .. name .. '.lua', vim.log.levels.INFO)
end
else
vim.notify('Skipped existing ' .. name .. '.lua', vim.log.levels.INFO)
end
end
end, { desc = 'Fetch default LSP configs into ./lsp in cwd' })

20
lua/setup/packages.lua Normal file
View File

@@ -0,0 +1,20 @@
local M = {}
function M.get()
return {
{ 'savq/paq-nvim', opt = true },
{ 'https://github.com/mason-org/mason.nvim', opt = true },
{ 'https://github.com/triimd/invero.nvim' },
{ 'https://gitea.tomastm.com/tomas.mirchev/nvim-tree.lua', version = 'master' },
{ 'https://github.com/windwp/nvim-ts-autotag' },
{ 'https://github.com/windwp/nvim-autopairs' },
{ 'https://github.com/nvim-treesitter/nvim-treesitter', version = 'master' },
{ 'https://github.com/mfussenegger/nvim-lint' },
{ 'https://github.com/stevearc/conform.nvim' },
}
end
return M

24
lua/utils.lua Normal file
View File

@@ -0,0 +1,24 @@
-- utils.lua
local M = {}
function M.await(fn, timeout, interval)
local done = false
local ok, data
-- Wrap resolve in vim.schedule so it runs on main loop
fn(function(success, result)
vim.schedule(function()
done = true
ok = success
data = result
end)
end)
vim.wait(timeout, function()
return done
end, interval)
return { ok = ok or false, data = data }
end
return M

1
paq-lock.json Normal file
View File

@@ -0,0 +1 @@
{"nvim-ts-autotag":{"status":1,"dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-ts-autotag","name":"nvim-ts-autotag","url":"https://github.com/windwp/nvim-ts-autotag","hash":""},"nvim-autopairs":{"status":1,"dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-autopairs","name":"nvim-autopairs","url":"https://github.com/windwp/nvim-autopairs","hash":""},"conform.nvim":{"status":1,"dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/conform.nvim","name":"conform.nvim","url":"https://github.com/stevearc/conform.nvim","hash":""},"nvim-tree.lua":{"status":1,"dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-tree.lua","name":"nvim-tree.lua","url":"https://gitea.tomastm.com/tomas.mirchev/nvim-tree.lua","hash":""},"invero.nvim":{"status":1,"dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/invero.nvim","name":"invero.nvim","url":"https://github.com/triimd/invero.nvim","hash":""},"mason.nvim":{"status":1,"dir":"/home/tomas/.local/share/nvim/site/pack/paqs/opt/mason.nvim","name":"mason.nvim","url":"https://github.com/mason-org/mason.nvim","hash":""},"nvim-lint":{"status":1,"dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-lint","name":"nvim-lint","url":"https://github.com/mfussenegger/nvim-lint","hash":""},"paq-nvim":{"status":0,"dir":"/home/tomas/.local/share/nvim/site/pack/paqs/opt/paq-nvim","name":"paq-nvim","url":"https://github.com/savq/paq-nvim.git","hash":"971344d1fe1fd93580961815e7b7c8853c3605e4"},"nvim-treesitter":{"status":1,"dir":"/home/tomas/.local/share/nvim/site/pack/paqs/start/nvim-treesitter","name":"nvim-treesitter","url":"https://github.com/nvim-treesitter/nvim-treesitter","hash":""}}