Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tenxsoydev/nx.nvim
Neovim API utility wrapper for more convenience with Lua keymaps, highlights, autocommands and options.
https://github.com/tenxsoydev/nx.nvim
lua neovim neovim-plugin nvim nvim-lua nvim-plugin utility
Last synced: 11 days ago
JSON representation
Neovim API utility wrapper for more convenience with Lua keymaps, highlights, autocommands and options.
- Host: GitHub
- URL: https://github.com/tenxsoydev/nx.nvim
- Owner: tenxsoydev
- License: apache-2.0
- Created: 2023-02-14T22:50:08.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-10-17T14:06:18.000Z (19 days ago)
- Last Synced: 2024-10-19T20:06:48.919Z (17 days ago)
- Topics: lua, neovim, neovim-plugin, nvim, nvim-lua, nvim-plugin, utility
- Language: Lua
- Homepage:
- Size: 47.9 KB
- Stars: 30
- Watchers: 2
- Forks: 1
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-neovim - tenxsoydev/nx.nvim - Neovim API utility wrapper for more convenience with Lua keymaps, highlights, autocommands and options. (Utility / Cursorline)
README
# nx.nvim
_Utility library to n^x your work with the nvim api._
**Features**
- [Keymaps](#nxmap)
- [Highlights](#nxhl)
- [Autocommands](#nxau)
- [Commands](#nxcmd)**Installation**
- [Getting Started](#getting-started)
## Features
All features maintain familiarity with their underlying base functions. Below is an overview of their differences and extended functionalities.
## nx.map
**Based on `vim.keymap.set()`**
```lua
vim.keymap.set('n', ';w', "w")
vim.keymap.set('n', ';q', "w", { desc = "Close Current Window" })
vim.keymap.set('', "j", "&wrap ? 'gj' : 'j'", { expr = true, silent = true })
vim.keymap.set('', "", "&wrap ? 'gj' : 'j'", { expr = true, silent = true })-- Can be written as
nx.map({
{ ";w", "w" },
{ ";q", "confirm quit", desc = "Close Current Window" },
{ { "j", "" }, "&wrap ? 'gj' : 'j'", "", expr = true, silent = true },
})
``````lua
-- Options like filetype and wk_label are not directly supported by vim.keymap.set
nx.map({
{ "ts", "set spell!", desc = "Toggle Spellcheck", wk_label = "Spellcheck" },
{ "tp", "MarkdownPreviewToggle", ft = "markdown", desc = "Toggle Markdown Preview" },
})
-- Wrapper options
nx.map({
-- Line Navigation
{ { "j", "" }, "&wrap ? 'gj' : 'j'", "" },
{ { "k", "" }, "&wrap ? 'gk' : 'k'", "" },
{ "$", "&wrap ? 'g$' : '$'", "" },
{ "^", "&wrap ? 'g^' : '^'", "" },
-- Enter insert mode at indentation level on empty lines
{ "i", "len(getline('.')) == 0 ? '\"_cc' : 'i'" },
}, { expr = true, silent = true })
})
```**Differences**
- Map single or multiple keymaps
- The only required values are index `[1]`: _lhs_ and `[2]`: _rhs_
- `mode`: defaults to `"n"` and instead of being passed as index `[1]` it is optional as `[3]` or `mode` key
- `opts`: are passed inline instead of in a separate table
- additional options:
- `wk_label`: to create which-key labels that should differ from the key's description
- `ft`: to create filetype specific mappings
- `{}`: to add options to all keymaps within a `nx.map()`
Detailed Examples Toggle visibility...
- ##### Feature overview
```lua
nx.map({ ";q", "confirm quit", desc = "Close Current Window" })
---@ ╰── set a single keymap
---@ ╭── or lists of keymaps
nx.map({
-- Line Navigation
---@ ╭── multiple lhs
{ { "j", "" }, "&wrap ? 'gj' : 'j'", "" },
{ { "k", "" }, "&wrap ? 'gk' : 'k'", "" },
{ "$", "&wrap ? 'g$' : '$'", "" },
{ "^", "&wrap ? 'g^' : '^'", "" },
-- Indentation
{ "i", function() return smart_indent "i" end },
{ "a", function() return smart_indent "a" end },
{ "A", function() return smart_indent "A" end },
}, { expr = true, silent = true })
---@ ╰── wrapper opts apply options to all entriesnx.map({
{ "", "", "i" },
{ "", "close", { "i", "x" } },
{ "q", "close", "x" },
---@ set filetype keymaps ──╮ (in {wrapper_opts} or for single keymaps)
}, { buffer = 0, ft = "DressingInput" })
```
- ##### Mode
Specify a `mode|mode[]` other than `"n"` as index `[3]` or `mode` key (inline or in `wrapper_opts`).
```lua
nx.map({
{ "", "", { "", "!" }, desc = "Enter" }
---@ ^= ╰── or ──╮
{ "", "", desc = "Enter", mode = { "", "!" } }
}, { mode = { "", "!" }) -- or in wrapper_opts (here it has to be the `mode` key)
```
- ##### Wrapper options
Add options to all entries in a list of keymaps _- inline keymap options are treated with higher priority and won't be overwritten by wrapper options_.
As an example, let's compare nx.map for setting [neovim/nvim-lspconfig#suggested-configuration](https://github.com/neovim/nvim-lspconfig/tree/v0.1.6?tab=readme-ov-file#suggested-configuration).```lua
---@ reference using the default vim.keymap.setlocal opts = { noremap=true, silent=true }
vim.keymap.set('n', 'e', vim.diagnostic.open_float, opts)
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts)
vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts)
vim.keymap.set('n', 'q', vim.diagnostic.setloclist, opts)local on_attach = function(client, bufnr)
local bufopts = { noremap=true, silent=true, buffer=bufnr }
vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, bufopts)
vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts)
vim.keymap.set('n', 'K', vim.lsp.buf.hover, bufopts)
vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, bufopts)
vim.keymap.set('n', '', vim.lsp.buf.signature_help, bufopts)
vim.keymap.set('n', 'wa', vim.lsp.buf.add_workspace_folder, bufopts)
vim.keymap.set('n', 'wr', vim.lsp.buf.remove_workspace_folder, bufopts)
vim.keymap.set('n', 'wl', function()
print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
end, bufopts)
vim.keymap.set('n', 'D', vim.lsp.buf.type_definition, bufopts)
vim.keymap.set('n', 'rn', vim.lsp.buf.rename, bufopts)
vim.keymap.set('n', 'ca', vim.lsp.buf.code_action, bufopts)
vim.keymap.set('n', 'gr', vim.lsp.buf.references, bufopts)
vim.keymap.set('n', 'f', function() vim.lsp.buf.format { async = true } end, bufopts)
end
``````lua
---@ nx.mapnx.map({
{ "e", vim.diagnostic.open_float },
{ "[d", vim.diagnostic.goto_prev },
{ "]d", vim.diagnostic.goto_next },
{ "q", vim.diagnostic.setloclist },
}, { noremap = true, silent = true })local on_attach = function(client, bufnr)
nx.map({
{ "gD", vim.lsp.buf.declaration },
{ "gd", vim.lsp.buf.definition },
{ "K", vim.lsp.buf.hover },
{ "gi", vim.lsp.buf.implementation },
{ "", vim.lsp.buf.signature_help },
{ "wa", vim.lsp.buf.add_workspace_folder },
{ "wr", vim.lsp.buf.remove_workspace_folder },
{ "wl", function() print(vim.inspect(vim.lsp.buf.list_workspace_folders())) end },
{ "D", vim.lsp.buf.type_definition },
{ "rn", vim.lsp.buf.rename },
{ "ca", vim.lsp.buf.code_action },
{ "gr", vim.lsp.buf.references },
{ "f", function() vim.lsp.buf.format { async = true } end },
}, { noremap = true, silent = true, buffer = bufnr })
end
```
- ##### Custom which-key labels
Register which-key labels that should differ from the mappings' description.
They can be a `string` literal, `"ignore"`(^=`"which_key_ignore"`), or `{ sub_desc = "" }` to exclude a pattern of the mappings `desc` key.
E.g.,Search
group
🟣 desc labels | 🔵 custom labels
E.g.,Toggle
group
🟣 desc labels | 🔵 custom labels
Preserve searchable description
e.g.::Telescope keymaps
The example below uses `wk_label` for a "`SnipRun`-keymap-family". It excludes the string `"SnipRun"` from being added to every entry on their which-key page.
```lua
---@ method 1: a custom `wk_label` per key
nx.map({
{ "Rc", "SnipClose", desc = "Close SnipRun", wk_label = "Close" },
{ "Rf", "%SnipRun", desc = "Run File" },
{ "Ri", "SnipInfo", desc = "SnipRun Info", wk_label = "Info" },
{ "Rm", "SnipReplMemoryClean", desc = "SnipRun Clean Memory", wk_label = "Clean Memory" },
{ "Rr", "SnipReset", desc = "Reset SnipRun", wk_label = "Reset" },
{ "Rx", "SnipTerminate", desc = "Terminate SnipRun", wk_label = "Terminate" },
{ "R", "'<,'>SnipRun", "v", desc = "SnipRun Range", wk_label = "Run Range" },
})---@ method 2: use `sub_desc` in `wrapper_opts` to remove `SnipRun` from all entries
nx.map({
{ "Rc", "SnipClose", desc = "Close SnipRun" },
{ "Rf", "%SnipRun", desc = "Run File" },
{ "Ri", "SnipInfo", desc = "SnipRun Info" },
{ "Rm", "SnipReplMemoryClean", desc = "SnipRun Clean Memory" },
{ "Rr", "SnipReset", desc = "Reset SnipRun" },
{ "Rx", "SnipTerminate", desc = "Terminate SnipRun" },
{ "RR", "'<,'>SnipRun", "v", desc = "SnipRun Range" },
}, { wk_label = { sub_desc = "SnipRun" } })
```
- ##### Type Annotations
Allow your language server to assist you with hovers, completions, and diagnostics.
function hover
field hover
cmp
diagnostic
This requires your runtime environment to be configured to include your plugin directories. An easy way is to have this automated using folke/neodev.nvim.
## nx.hl
**Based on `nvim_set_hl()`**
```lua
nx.hl({
{ "LineNr", fg = "DraculaComment:fg" },
{ "Normal", bg = "DraculaBg:bg" },
{ "BgDarker", bg = palette.bg .. ":#b-15" },
{ "BufferLineSeparatorShadow", fg = "TabLine:bg:#b-10", bg = "Normal:bg" } }
{ { "Directory", "MarkSign" }, link = "DraculaPurple" },
})
```**Differences**
- Set single or multiple highlights
- The only required values are index `[1]`: _hl_name_ and `bg|fg|link|…`: _value_
- `ns_id`: defaults to `0` and instead of being passed as index `[1]` it is optional as `[3]` or `ns_id` key
- `values`: are passed inline instead of in a separate table
- modifiers for values:
- `:bg|:fg`: to use single values of other highlights as color source instead of linking the whole group.
- `:#b`: to transform the brightness of a color
- `{}` to add values to all highlights within a `nx.hl()`
Detailed Examples Toggle visibility...
- ##### Feature overview
```lua
nx.hl({ "GitSignsCurrentLineBlame", fg = "Debug:fg", bg = "CursorLine:bg", italic = true })
---@ ╰── set a single highlight
---@ ╭── or lists of highlights
nx.hl({
{ "Hex", fg = "#9370DB" }, -- ╮
{ "ColorName", fg = "MediumPurple" }, ---@ ├ kinds of values already possible without nx.nvim
{ "Decimal", fg = 9662683 }, -- ╯
--
{ "Winbar", fg = "DraculaComment:fg" },
---@ ╭────╯ use single values from other highlight groups
{ "Normal", bg = "DraculaBg:bg" },
---@ use a color with transformed brightness ──╮ ╭─ darken
{ "BufferLineSeparatorShadow", fg = "TabLine:bg:#b-10", bg = "Normal:bg" } }
---@ e.g., with hex var ──╮ ╭─ brighten
{ "BgLight", bg = palette.bg .. ":#b+15" },
---@ ╭── multiple highlight names
{ { "Directory", "MarkSign" }, link = "DraculaPurple" },
}, { bold = true, italic = true })
---@ ╰── wrapper opts apply values to all entries
```
- ##### Wrapper options
Add values to all entries in a list of highlights _- inline values are treated with higher priority and won't be overwritten by wrapper options_.
```lua
nx.hl({
{ "NeoTreeTabActive", bg = "NeoTreeNormal:bg" },
{ "NeoTreeTabInactive", fg = "NeoTreeDimText:fg" }, -- ╮
{ "NeoTreeTabSeparatorInactive", fg = "TabLine:bg" }, -- ┤
}, { bg = "TabLine:bg" }) ---@ applies `bg` these -- ╯
```
## nx.au
**Based on `nvim_create_autocmd()`**
```lua
nx.au({
{ "BufWritePost", pattern = "options.lua", command = "source ", desc = "Execute files on save" },
{ "BufWritePre", command = "call mkdir(expand(':p:h'), 'p')", desc = "Create non-existent parents" },
})
nx.au({
{ "BufWinLeave", pattern = "*.*", command = "mkview" },
{ "BufWinEnter", pattern = "*.*", command = "silent! loadview" },
}, { create_group = "RememberFolds" })
```**Differences**
- Create single or multiple auto commands
- `opts`: are passed inline instead of in a separate table
- additional options:
- `create_group`: to create a group and add the `autocmd|autocmd[]` to that group
- `{}` to add values to all autocmds within a `nx.au()`
Detailed Examples Toggle visibility...
- ##### Feature Description
```lua
nx.au({ "FocusGained", pattern = "*.*", command = "checktime", desc = "Check if buffer changed outside of vim" })
---@ ╰── create a single autocommand
---@ ╭── or lists of autocommands
nx.au({
{ "BufWinLeave", pattern = "*.*", command = "mkview" },
{ "BufWinEnter", pattern = "*.*", command = "silent! loadview" },
}, { pattern = "*.*" })
---@ ╰── wrapper opts apply values to all entries without them
```
- ##### Autocommand groups
Besides the usual adding to existing autocommand groups using the `group` key, it is possible to create autocommand groups on the fly with the `create_group` key.
```lua
nx.au({
"BufWritePre",
-- group = "FormatOnSave", ---@ use `group` as usual to add the autocmd to an already existing group
create_group = "FormatOnSave", ---@ or create a new group while creating the autocmd
callback = function()
if next(vim.lsp.get_active_clients({ bufnr = 0 })) == nil then return end
vim.lsp.buf.format({ async = false })
end,
})
nx.au({
{ "BufWinLeave", pattern = "*.*", command = "mkview" },
{ "BufWinEnter", pattern = "*.*", command = "silent! loadview" },
---@ ╭── create an autocommand group in `wrapper_opts` and add all autocommands within this "nx.au()" call
}, { create_group = "RememberFolds" })
```
## nx.cmd
**Based on `nvim_create_user_command()`**
```lua
nx.cmd({
"LspFormat",
function() vim.lsp.buf.format({ async = true }) end,
bang = true,
desc = "Fromat the Current Buffer",
})
```**Differences**
- Create single or multiple commands
- The only required values are index `[1]`: _name_ and `[2]`: _command_
- `opts`: are passed inline instead of in a separate table
- `{}` to add values to all commands within a `nx.cmd()`
Detailed Examples Toggle visibility...
- ##### Feature Description
```lua
---@ ╭── create a single command
nx.cmd({ "ResetTerminal", function() vim.cmd("set scrollback=1 | sleep 10m | set scrollback=10000") end })
---@ ╭── or lists of commands
nx.cmd({
{ "LspFormat", function() vim.lsp.buf.format({ async = true }) end },
{ "LspToggleAutoFormat", function(opt) toggle_format_on_save(opt.args) end, nargs = "?" },
{ "ToggleBufferDiagnostics", function() toggle_buffer_diags(vim.fn.bufnr()) end },
}, { bang = true })
---@ ╰── wrapper opts apply options to all entries without them
```
## nx.set
There is also `nx.set` to assign multiple variables or options.
Next to an array of variables/settings, add the scope (`vim.g|vim.opt|vim.bo|...`) as a second parameter. If no scope is specified `vim.g` is used.
(This features function currently consists of just over 10 lines of code. It's not as extensive or well annotated, but feel free to use it if you like).
Details Toggle visibility...
- Variables
```lua
nx_set({
dracula_italic = 1,
dracula_bold = 1,
dracula_full_special_attrs_support = 1,
dracula_colorterm = 0,
})
-- common way:
vim.g.dracula_italic = 1
vim.g.dracula_bold = 1
vim.g.dracula_full_special_attrs_support = 1
vim.g.dracula_colorterm = 0
```- Options
```lua
nx.set({
-- General
clipboard = "unnamedplus", -- use system clipboard
mouse = "a", -- allow mouse in all modes
showmode = false, -- print vim mode on enter
termguicolors = true, -- set term gui colors
timeoutlen = 350, -- time to wait for a mapped sequence to complete
fillchars__append = [[eob: ,fold: ,foldopen:,foldsep: ,foldclose:›, vert:▏]],
listchars__append = [[space:⋅, trail:⋅, eol:↴]],
-- Auxiliary files
undofile = true, -- enable persistent undo
backup = false, -- create a backup file
swapfile = false, -- create a swap file
-- Command line
cmdheight = 0,
-- Completion menu
pumheight = 14, -- completion popup menu height
shortmess__append = "c", -- don't give completion-menu messages
-- Gutter
number = true, -- show line numbers
numberwidth = 3, -- number column width - default "4"
relativenumber = true, -- set relative line numbers
signcolumn = "yes:2", -- use fixed width signcolumn - prevents text shift when adding signs
-- Search
hlsearch = true, -- highlight matches in previous search pattern
ignorecase = true, -- ignore case in search patterns
smartcase = true, -- use smart case
-- ...
}, vim.opt)
```
## Getting Started
Install `"tenxsoydev/nx.nvim"` via your favorite plugin manager.
The only thing left to do then is to import the `nx` functions you want to use.
#### Examples
- Set it once as global variable, so it can be called anywhere in a configuration
```lua
-- if using a global variable, make sure it's set where it will be loaded before it's used in another place
_G.nx = require("nx")
-- use anywhere
nx.map({})
nx.au({})
nx.hl({})
``````lua
-- E.g., when using a plugin manger like lazy, add a high priority
require("lazy").setup({
-- ...
{ "tenxsoydev/nx.nvim", priority = 100, config = function() _G.nx = require "nx" end },
-- ...
})
``````lua
-- or if you prefer not to have the `nx` branding, use another vairable name
_G.v = require("nx")
-- use anywhere
v.map({})
v.au({})
v.hl({})
```- It's also possible to import single modules on demand
```lua
local map = require("nx.map")
local hl = require("nx.hl")
local au = require("nx.au")
```
### Reusability
To be easily composable, the utilities are written as single modules that can stand on their own. So if they can be helpful within the project you are working - and adding dependencies is too heavy - they are light copy pasta 🍝. In such cases, keeping a small reference of attribution warms the heart of your fellow developer.
## Contribution
There is always room for enhancement. Reach out if you experience any issues, would like to request a feature, or submit improvements. If you would like to tackle open issues - they are usually "help wanted" by nature. Leaving an emoji to show support for an idea that has already been requested also helps to prioritize community needs.
---
### Credits
- [nxvim](https://github.com/tenxsoydev/nxvim/)