Skip to content

Repository files navigation

color-tools.nvim

A dependency-free color highlighter and keyboard-driven color picker for Neovim. It understands modern CSS colors and resolves project-specific Tailwind CSS v3 and v4 palettes without executing project code.

CI License: GPL v3 or later

Video

color-tools-demo.mp4

Features

  • Incremental highlighting of visible colors with background, foreground, or virtual-text display.
  • CSS hex, named colors, RGB, HSL, HWB, Lab, LCH, Oklab, Oklch, predefined color() spaces, gradients, color-mix(), relative colors, and other conservatively resolvable CSS Color 4/5 expressions.
  • A keyboard-only floating picker for direct hex, RGB, HSL, Oklab, and Oklch literals, with RGB, HSL, HSV, Oklab, and Oklch editing modes.
  • Project-aware Tailwind CSS v3/v4 highlighting and palette picking, including custom colors, presets, imports, prefixes, important modifiers, and opacity.
  • Optional Tailwind LSP enrichment and clean coexistence with Neovim 0.12's built-in document-color rendering.
  • Automatic support for normal buffers and reused preview buffers from fff.nvim and Snacks.nvim.
  • No runtime dependencies, no project code execution, and no default global key mappings.

Requirements

  • Linux
  • Neovim 0.12+
  • A terminal with true-color support (:set termguicolors)

Installation

lazy.nvim

{
  "jake8655/color-tools.nvim",
  opts = {
    binds = {
      pick = "<leader>cp",
      insert = "<leader>ci",
      toggle = "<leader>ct",
    },
  },
}

Use version = "*" if you prefer stable releases over the latest commit.

vim.pack

vim.pack.add({ "https://github.com/jake8655/color-tools.nvim" })

require("color-tools").setup({
  binds = {
    pick = "<leader>cp",
    insert = "<leader>ci",
    toggle = "<leader>ct",
  },
})

Native packages

git clone https://github.com/jake8655/color-tools.nvim \
  "${XDG_DATA_HOME:-$HOME/.local/share}/nvim/site/pack/plugins/start/color-tools.nvim"
require("color-tools").setup()

Usage

Put the cursor on an editable color and run :ColorToolsPick. If no editable color is under the cursor, the picker inserts a new one. Use :ColorToolsInsert to always insert a new color.

The picker is keyboard-only. Its default controls are:

Key Action
j / k, arrow down / up Select the next / previous channel
h / l, arrow left / right Decrease / increase
[ / ] Fine decrease / increase
H / L Coarse decrease / increase
e Cycle editing space
o Cycle output format
r Reset
<CR> Confirm
<Esc> / q Cancel without changing the source buffer

Tailwind classes use the same picker surface to select family, shade, and opacity.

Configuration

The plugin highlights supported buffers by default but creates no ordinary mapping unless you request one:

require("color-tools").setup({
  binds = {
    pick = "<leader>cp",
    insert = "<leader>ci",
    toggle = "<leader>ct",
    refresh = "<leader>cr",
  },
  lsp = {
    document_color = {
      coexist = false, -- avoid a duplicate Neovim document-color overlay
    },
    tailwind = {
      enabled = true, -- enrich exact colors from an attached Tailwind LSP
    },
  },
  highlight = {
    enabled = true,
    style = "background", -- "background", "foreground", or "virtual"
    virtual_text = "",
    filetypes = {}, -- empty means every filetype
    buftypes = { "" },
  },
  picker = {
    edit_format = "rgb",
    output_format = "hex",
    default_color = "#ffffff",
    binds = {
      confirm = { "<CR>" },
      cancel = { "<Esc>", "q" },
      next_channel = { "j", "<Down>" },
      previous_channel = { "k", "<Up>" },
      increment = { "l", "<Right>" },
      decrement = { "h", "<Left>" },
      increment_fine = { "]" },
      decrement_fine = { "[" },
      increment_coarse = { "L" },
      decrement_coarse = { "H" },
      cycle_edit_format = { "e" },
      cycle_output_format = { "o" },
      reset = { "r" },
    },
  },
})

Set a picker action to false to leave it unmapped. Every top-level action also has a stable <Plug> mapping:

nmap <leader>cp <Plug>(color-tools-pick)
nmap <leader>ci <Plug>(color-tools-insert)
nmap <leader>ct <Plug>(color-tools-toggle)
nmap <leader>cr <Plug>(color-tools-refresh)

Commands and Lua API

Command Lua API
:ColorToolsPick require("color-tools").pick()
:ColorToolsInsert require("color-tools").insert()
:ColorToolsToggle require("color-tools").toggle()
:ColorToolsEnable require("color-tools").enable()
:ColorToolsDisable require("color-tools").disable()
:ColorToolsRefresh require("color-tools").refresh()

ColorToolsRefresh invalidates cached Tailwind palettes and refreshes all active color-tools buffers.

Limitations

  • Only direct hex, RGB, HSL, Oklab, and Oklch literals are editable. Named colors, color-mix(), Lab/LCH, variable-derived expressions, and other contextual forms are highlight-only.
  • Static analysis cannot reproduce the CSS cascade or arbitrary JavaScript and TypeScript execution. Unresolved values fail closed.
  • Tailwind preview buffers work without an LSP, but only the statically resolved palette is available there.
  • Linux is the currently tested and supported platform.

Contributing

Bug reports and pull requests are welcome. See CONTRIBUTING.md for the development workflow.

License

GPL v3 or later

About

Advanced, modern color highlighter and color picker for Neovim

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages