A collection of useful Lua utilities for Neovim, extracted from SpaceVim.
- Color manipulation — Comprehensive color space conversions (RGB, HSL, HSV, CMYK, HWB, HEX, Linear, XYZ, Lab, LCH)
- Data structures — Dictionary, list, string, and TOML parsing utilities
- File operations — Filetype icons, path unification, file read/write, file/directory finding
- Highlight — Syntax group manipulation, separator highlighting, syntax inspection at cursor
- Interactive UI — Command-line prompt and menu system
- Vim/Neovim compatibility — Cross-platform API layer for Vim and Neovim
- Regex — Perl-style regex to Vim regex converter
- System detection — OS detection (Linux, Windows, macOS, Cygwin)
- Unicode — Spinner animations, messletters (circled letters/numbers, bubble numbers)
- Misc — Password generation, time formatting, language aliases, buffer/window management
Using nvim-plug
require('plug').add({
{ 'wsdjeg/utils.nvim' }
})Then run :PlugInstall utils.nvim.
Using luarocks
luarocks install utils.nvimUsing lazy.nvim
{
'wsdjeg/utils.nvim',
}Full color space conversion library. All values use the [0, 1] range (except HSL/HSV hue in degrees and CMYK in [0, 1]).
local color = require('utils.color')
-- RGB <-> HSL
local h, s, l = color.rgb2hsl(0.2, 0.4, 0.6)
local r, g, b = color.hsl2rgb(210, 0.5, 0.5)
-- RGB <-> HEX
local hex = color.rgb2hex(0.2, 0.4, 0.6) -- "#336699"
local r, g, b = color.hex2rgb('#336699')
-- RGB <-> HSV
local h, s, v = color.rgb2hsv(0.2, 0.4, 0.6)
-- RGB <-> CMYK
local c, m, y, k = color.rgb2cmyk(0.2, 0.4, 0.6)
-- RGB <-> HWB
local h, w, b = color.rgb2hwb(0.2, 0.4, 0.6)
-- RGB <-> Lab
local L, a, b = color.rgb2lab(0.2, 0.4, 0.6)
-- Lab <-> LCH
local L, C, H = color.lab2lch(50, 20, -10)Supported conversions: RGB, HSL, HSV, CMYK, HWB, HEX, Linear RGB, XYZ, Lab, LCH — all interchangeable.
String manipulation utilities.
local str = require('utils.data.string')
str.trim(' hello ') -- 'hello'
str.trim_start(' hello') -- 'hello'
str.trim_end('hello ') -- 'hello'
str.fill('hi', 10) -- 'hi '
str.fill_left('hi', 10) -- ' hi'
str.toggle_case('Hello') -- 'hELLO'
str.string2chars('abc') -- {'a', 'b', 'c'}
str.strcharpart('hello', 2, 4) -- 'll'TOML parser.
local toml = require('utils.data.toml')
local data = toml.parse([[
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
]])
-- data.title == "TOML Example"
-- data.owner.name == "Tom Preston-Werner"
-- Or parse from file
local data = toml.parse_file('config.toml')Dictionary utilities.
local dict = require('utils.data.dict')
local d = dict.make({'a', 'b', 'c'}, {1, 2, 3})
-- { a = 1, b = 2, c = 3 }List utilities.
local list = require('utils.data.list')
local v = list.pop({1, 2, 3}) -- 3 (removes and returns last element)File and path utilities.
local file = require('utils.file')
-- Get filetype icon
local icon = file.fticon('main.lua') -- ''
-- Path operations
local path = file.unify_path('./src/../lib') -- normalized path
local fname = file.path_to_fname('/a/b/c.lua') -- '_a_b_c_lua'
-- File read/write
local lines = file.read('output.log')
file.write('new line', 'output.log') -- append
file.override('content', 'output.log') -- overwrite
-- Find files/directories
local f = file.findfile('Makefile', '.')
local d = file.finddir('src', '.')Highlight group manipulation.
local hi = require('utils.highlight')
-- Get highlight group as dictionary
local group = hi.group2dict('Error')
-- Set highlight
hi.hi({
name = 'MyHighlight',
guifg = '#ff0000',
guibg = '#000000',
bold = 1,
})
-- Create separator highlights between two groups
hi.hi_separator('Normal', 'StatusLine')
-- Get syntax at cursor position (supports Treesitter & semantic tokens)
local name, hl = hi.syntax_at()Interactive command-line prompt with cursor support.
local prompt = require('utils.prompt')
prompt._prompt.mpt = 'input ==> '
prompt._handle_fly = function(input)
print('User typed: ' .. input)
end
prompt._onclose = function()
print('Prompt closed')
end
prompt.open()Interactive command-line menu.
local menu = require('utils.cmdlinemenu')
menu.menu({
{'Option 1', function() print('Selected 1') end},
{'Option 2', 'echo "Selected 2"'},
{'Option 3', function() print('Selected 3') end},
})Command-line argument parser.
local argv = require('utils.vim.argv')
local args = argv.parser('git commit -m "hello world"')
-- {'git', 'commit', '-m', 'hello world'}Buffer operations.
local buf = require('utils.vim.buffer')
local bufnr = buf.create_buf(false, true) -- create scratch buffer
buf.set_option(bufnr, 'buflisted', true)
local listed = buf.listed_buffers()
buf.open_pos('edit', 'file.lua', 10, 1) -- open at line 10, col 1Key code utilities.
local Key = require('utils.vim.keys')
local esc = Key.t('<Esc>') -- terminal escape code for <Esc>
local name = Key.nr2name(32) -- 'SPC'
local name = Key.char2name('<CR>') -- '<CR>'Convert Perl-style regex to Vim regex.
local regex = require('utils.vim.regex')
local vim_pattern = regex.parser('\\bword\\b', true)
-- Result: '\v<word>'Compatibility layer between Vim and Neovim.
local cmp = require('utils.vim.compatible')
cmp.has('nvim-0.10.0') -- 1 or 0
cmp.echo('Hello')
cmp.islist({1, 2, 3}) -- trueSet local buffer/window options (requires Neovim 0.8.0+).
local opt = require('utils.vim.option')
opt.setlocalopt(bufnr, winid, {
number = true,
wrap = false,
})Statusline builder with floating window support.
local sl = require('utils.vim.statusline')
-- Build a statusline string
local line = sl.build(
{'mode'}, {'file'}, '|', '|',
'filename', 'tag',
'StatusLine', 'StatusLineNC', 'StatusLineC',
'StatusLineZ', 80
)
-- Or show in a floating window
sl.open_float({{'Mode: NORMAL', 'Normal'}})Window utilities.
local win = require('utils.vim.window')
win.is_float(winid) -- check if window is floating
win.is_last_win() -- check if last non-floating windowOperating system detection.
local sys = require('utils.system')
sys.isWindows -- 1 or 0
sys.isLinux -- 1 or 0
sys.isOSX -- 1 or 0
sys.name() -- 'linux', 'windows', 'mac', or 'cygwin'
sys.isDarwin() -- 1 or 0
sys.fileformat() -- OS iconPassword generator.
local pwd = require('utils.password')
pwd.generate_simple(16) -- random 16-character alphanumeric stringTime utilities.
local time = require('utils.time')
time.current_time() -- "02:30 PM"
time.current_date() -- "Mon Jan 15"Filetype name aliases.
local lang = require('utils.language')
lang.get_alias('typescript') -- 'TypeScript'
lang.get_alias('python') -- 'Python'
lang.get_alias('typescriptreact') -- 'TypeScript React'Unicode symbol utilities.
local ml = require('utils.messletters')
ml.circled_letter('A') -- 'Ⓐ'
ml.circled_num(1, 0) -- '①'
ml.bubble_num(1, 0) -- '➊'
ml.index_num(2) -- '²'
ml.parenthesized_num(1) -- '⑴'
ml.num_period(1) -- '⒈'Terminal spinner animations.
local spinners = require('utils.unicode.spinners')
local s = spinners:new(function(icon)
vim.api.nvim_echo({{icon, 'Normal'}}, false, {})
end)
s:start() -- start animation
-- ...
s:stop() -- stop animation