Skip to content

🎨 Apply your pywal/wallust colorscheme to Neovim automatically.

License

Notifications You must be signed in to change notification settings

RedsXDD/neopywal.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🎨 (Neo)pywal for (Neo)vim

Neopywal.nvim is a Neovim colorscheme plugin that automatically fetches and applies the colors that are auto generated by Pywal. It also is an improved and maintained version of Pywal.nvim, which aimed to be an updated version of wal.vim.

Note

As April 26, 2024, Pywal is officially deprecated, so it's not recommended to use it. You can look for alternatives that will work with Neopywal.nvim on the section Pywal Alternatives.

01
02
03
04

Table of Contents

  1. Features
  2. Installation
  3. Usage
    1. Alternative Variants
    2. Note on Light Theme
  4. Configuration
    1. Alternative Palettes
    2. Customizing Colors
    3. Customizing Highlights
    4. Fileformats
    5. Plugins
  5. Compilation
  6. Importing Colors
  7. Utilities
    1. The Darken and Lighten Functions
    2. The Blend Function
  8. Pywal Alternatives
    1. Setting up Wallust
  9. How it Works
  10. Enjoy

Features

  • Highly configurable with ability to change color definitions and highlight groups.
  • True color support.
  • Export table with color palette.
  • Fail safe color fallbacks if required palette files could not be loaded.
  • Supports Pywal and Wallust.
  • Support for LSP, treesitter and a bunch of plugins.
  • Enhanced syntax highlighting for fileformats (without using treesitter).
  • Compiled user's configuration for fast startup times.

Installation

lazy.nvim

{
    "RedsXDD/neopywal.nvim",
    name = "neopywal",
    lazy = false,
    priority = 1000,
    opts = {},
}

packer.nvim

use { "RedsXDD/neopywal.nvim", as = "neopywal" }

mini.deps

now(function()
    add({
        source = "RedsXDD/neopywal.nvim",
        name = "neopywal",
    })
end)

vim-plug

Plug "RedsXDD/neopywal.nvim", { "as": "neopywal" }

Usage

To activate the theme, add the following to your Neovim config:

local neopywal = require("neopywal")
neopywal.setup()
vim.cmd.colorscheme("neopywal")

Or call the colorscheme with vim script:

colorscheme neopywal

Alternative Variants

Neopywal can also take advantage of Neovim's vim.o.background option (see :h background) to dynamically adjust the color palette on the fly. This allows you to switch between a light and dark colorscheme, even when Pywal generates a dark palette.

colorscheme neopywal-dark
" or
colorscheme neopywal-light

Note that, by default, when loading the colorscheme with the standard :colorscheme neopywal command, Neopywal will automatically detect and load the corresponding colorscheme variant based on the current value of vim.o.background.

Note on Light Theme

When loading the "light" theme variant, Neopywal won't generate any new colorscheme palette. Instead, it loads the existing palette (used by the neopywal-dark variant) and inverts the background and foreground color variables (see Importing Colors for more information). This may not produce the best results when comparing to an actual auto generated light theme variant, but it's generally good enough.

To use a genuine light theme with Neopywal, generate a new colorscheme with Pywal while using the -l flag.

$ wal -l -i /path/to/your/image

Note

Make sure to run :colorscheme neopywal or vim.cmd.colorscheme("neopywal"), otherwise the colorscheme won't be loaded.

Configuration

There is no need to call setup if you don't want to change the default options and settings.

require("neopywal").setup({
    -- Uses a template file `~/.cache/wallust/colors_neopywal.vim` instead of the
    -- regular pywal template at `~/.cache/wal/colors-wal.vim`.
    use_wallust = false,

    -- This option allows to specify where Neopywal should look for a ".vim" template file
    -- (e.g.: os.getenv("HOME") .. "/.cache/wal/custom_neopywal_template.vim").
    colorscheme_file = "",

    -- This option allows to use a custom built-in theme palettes like "catppuccin-mocha" or "tokyonight".
    -- To get the list of available themes take a look at `https://github.com/RedsXDD/neopywal.nvim#Alternative-Palettes`.
    -- Take note that this option takes precedence over `use_wallust` and `colorscheme_file`.
    use_palette = "",

    -- Sets the background color of certain highlight groups to be transparent.
    -- Use this when your terminal opacity is < 1.
    transparent_background = false,

    -- With this option you can overwrite all the base colors the colorscheme uses.
    -- For more information take a look at `https://github.com/RedsXDD/neopywal.nvim#Customizing-Colors`
    custom_colors = {},

    -- With this option you can overwrite any highlight groups set by the colorscheme.
    -- For more information take a look at `https://github.com/RedsXDD/neopywal.nvim#Customizing-Highlights`
    custom_highlights = {},

    -- Dims the background when another window is focused.
    dim_inactive = true,

    -- Apply colorscheme for Neovim's terminal (e.g. `g:terminal_color_0`).
    terminal_colors = true,

    -- Shows the '~' characters after the end of buffers.
    show_end_of_buffer = false,

    -- Shows the '|' split separator characters.
    -- It's worth noting that this options works better in conjunction with `dim_inactive`.
    show_split_lines = true,

    no_italic = false, -- Force no italic.
    no_bold = false, -- Force no bold.
    no_underline = false, -- Force no underline.
    no_undercurl = false, -- Force no undercurl.
    no_strikethrough = false, -- Force no strikethrough.

    -- Handles the styling of certain highlight groups (see `:h highlight-args`).
    styles = {
        comments = { "italic" },
        conditionals = { "italic" },
        loops = {},
        functions = {},
        keywords = {},
        includes = { "italic" },
        strings = {},
        variables = { "italic" },
        numbers = {},
        booleans = {},
        types = { "italic" },
        operators = {},
    },

    -- Setting this to false disables all default file format highlights.
    -- Useful if you want to enable specific file format options.
    -- Defaults to false when treesitter is enabled,
    -- unless manually enabled inside the `setup()` function.
    default_fileformats = true,

    -- Setting this to false disables all default plugin highlights.
    -- Useful if you want to enable specific plugin options.
    default_plugins = true,

    -- For more fileformats options please scroll down (https://github.com/RedsXDD/neopywal.nvim#Fileformats)
    fileformats = {
        c_cpp = true,
        c_sharp = true,
    },

    -- For more plugin options please scroll down (https://github.com/RedsXDD/neopywal.nvim#Plugins)
    plugins = {
        alpha = true,
        coc = false,
        mini = {
            cursorword = true,
            files = true,
        },
    },
})

Alternative Palettes

Unlike many famous Neovim colorschemes, Neopywal does not offer any alternative palette on it's own. Instead, it relies solely on the palette generated by Pywal at the time of using the plugin. However that gives Neopywal an advantage over other colorschemes, that being the extreme modularity with the palette used by the plugin.

You can easily use any well-known colorscheme palette with Neopywal without much effort. If you don't want to use an auto-generated Pywal palette based on a low-quality wallpaper, you can always opt for a richer palette like "catppuccin" or "tokyonight" at any time.

To achieve this, use the use_palette option with one of the following available colorscheme palette names:

  • catppuccin-{frappe,macchiato,mocha}
  • doomone
  • everforest-{soft,medium,hard}
  • gruvbox-{soft,dark,hard}
  • material and material-{darker,ocean,palenight}
  • monokaipro
  • nord
  • oceanic-next
  • onedark and onedark-{darker,vivid}
  • palenight
  • solarized
  • sonokai
  • tokyonight and tokyonight-storm
  • tommorow-night

To use any of the available built-in colorscheme palettes, simply specify one of the names from the list in the use_palette option. Note that this option takes precedence over the use_wallust and colorscheme_file options.

require("neopywal").setup({
        use_palette = "doomone",
    },
})

Names containing curly braces like catppuccin-{frappe,macchiato,mocha} indicate that there are multiple variants of that colorscheme palette. For example, the catppuccin colorscheme has three variants available:

require("neopywal").setup({
        use_palette = "catppuccin-frappe",
    },
})

-- or

require("neopywal").setup({
        use_palette = "catppuccin-macchiato",
    },
})

-- or

require("neopywal").setup({
        use_palette = "catppuccin-mocha",
    },
})

Customizing Colors

Color definitions can be overwritten using the custom_colors option:

Using a table:

require("neopywal").setup({
    -- Here's an example color template for the catppuccin colorscheme:
    custom_colors = {
        background = "#1E1E2E",
        foreground = "#CDD6F4",
        cursor = "#F5E0DC",
        color0 = "#45475A",
        color1 = "#F38BA8",
        color2 = "#A6E3A1",
        color3 = "#F9E2AF",
        color4 = "#89B4FA",
        color5 = "#F5C2E7",
        color6 = "#94E2D5",
        color7 = "#BAC2DE",
        color8 = "#585B70",
        color9 = "#F38BA8",
        color10 = "#A6E3A1",
        color11 = "#F9E2AF",
        color12 = "#89B4FA",
        color13 = "#F5C2E7",
        color14 = "#94E2D5",
        color15 = "#A6ADC8",
    },
})

Using a function:

require("neopywal").setup({
    custom_colors = function(C)
        return {
            background = C.background,
            foreground = C.foreground,
            cursor = C.cursor,
            color0 = C.color0,
            color1 = C.color1,
            color2 = C.color2,
            color3 = C.color3,
            color4 = C.color4,
            color5 = C.color5,
            color6 = C.color6,
            color7 = C.color7,
            color8 = C.color8,
            color9 = C.color9,
            color10 = C.color10,
            color11 = C.color11,
            color12 = C.color12,
            color13 = C.color13,
            color14 = C.color14,
            color15 = C.color15,
        }
    end,
})

You can also define your own color variables:

require("neopywal").setup({
    custom_colors = {
        red = "#ff0000"
        green = "#00ff00"
        blue = "#0000ff"
    },
})

Custom color variables will be automatically exported with the get_colors() function and can used normally when using the imported color palette.

There's also an additional set of color variables that are used for various highlights groups to make the Neopywal colors more consistent.

local C = require("neopywal").get_colors()
local U = require("neopywal.utils.color")

require("neopywal").setup({
    custom_colors = {
        -- Extras:
        dim_bg = U.darken(C.background, 5),
        comment = C.color8,
        cursorline = U.blend(C.background, C.foreground, 0.9),
        directory = C.color4,

        -- Diffs:
        diff_added = C.color2,
        diff_changed = C.color6,
        diff_removed = C.color1,
        diff_untracked = C.color5,

        -- LSP/Diagnostics:
        error = C.color1,
        hint = C.color6,
        info = C.foreground,
        unnecessary = C.color8,
        warn = U.blend(C.color1, C.color3, 0.5),
        ok = C.color2,
        inlay_hints = C.color8,

        -- Variable types:
        variable = C.color4, -- (preferred) any variable.
        constant = C.color3, -- (preferred) any constant
        string = C.foreground, -- a string constant: "this is a string"
        character = C.color3, -- a character constant: 'c', '\n'
        number = C.color5, -- a number constant: 234, 0xff
        boolean = C.color5, -- a boolean constant: TRUE, FALSE
        float = C.color5, -- a floating point constant: 2.3e10
        identifier = U.blend(C.color1, C.color3, 0.5), -- (preferred) any variable name
        func = C.color2, -- function name (also: methods for classes)

        -- Statements:
        statement = C.color1, -- (preferred) any statement
        conditional = C.color1, -- if, then, else, endif, switch, etc.
        loop = C.color1, -- for, do, while, etc.
        label = C.color1, -- case, default, etc.
        exception = C.color1, -- try, catch, throw
        operator = C.color1, -- "sizeof", "+", "*", etc.
        keyword = C.color1, -- any other keyword
        debug = C.color3, -- debugging statements.

        -- Preprocessors:
        preproc = C.color5, -- (preferred) generic Preprocessor
        include = C.color5, -- preprocessor #include
        define = C.color5, -- preprocessor #define
        macro = C.color5, -- same as Define
        precondit = C.color5, -- preprocessor #if, #else, #endif, etc.

        -- Type definitions:
        type = C.color6, -- (preferred) int, long, char, etc.
        structure = C.color6, -- struct, union, enum, etc.
        storageclass = C.color6, -- static, register, volatile, etc.
        typedef = C.color6, -- A typedef

        -- Special:
        special = C.color5, -- (preferred) any special symbol
        secialchar = C.color5, -- special character in a constant
        tag = U.blend(C.color1, C.color3, 0.5), -- you can use CTRL-] on this
        delimiter = C.foreground, -- character that needs attention
        specialcomment = C.color8, -- special things inside a comment
    },
})

Customizing Highlights

Highlight groups can be overwritten using custom_highlights option.

With an internal function:

require("neopywal").setup({
    custom_highlights = function(C)
        return {
            Comment = { fg = C.color3 }
            TabLineSel = { bg = C.color5 },
            FloatBorder = { bg = C.color1 },
            Pmenu = { bg = C.color6 },
        }
    end
})

Using an externally exported color palette.

local C = require("neopywal").get_colors()

require("neopywal").setup({
    custom_highlights = {
        Comment = { fg = C.color3 }
        TabLineSel = { bg = C.color5 },
        FloatBorder = { bg = C.color1 },
        Pmenu = { bg = C.color6 },
    }
})

Neopywal also allows to set a transparent color for highlight groups using the none color variable.

require("neopywal").setup({
    custom_highlights = function(C)
        return {
            Normal = { bg = C.none },
        }
    end
})

Fileformats

Neopywal provides theme support for extra syntax highlighting groups that do not use treesitter. This is useful for users that don't have treesitter installed but still want a somewhat decent syntax highlighting.

Some fileformats are enabled by default, you can control this behaviour with the default_fileformats option.

require("neopywal").setup({
    default_fileformats = false,
})

To enable/disable a supported fileformat you just need to set it to true/false.

require("neopywal").setup({
    fileformats = {
        c_cpp = true,
        c_sharp = true,
        clojure = true,
        cmake = true,
        common_lisp = true,
        css = true,
        dart = true,
        diff = true,
        elixir = true,
        erlang = true,
        git_commit = true,
        go = true,
        haskell = true,
        help = true,
        html = true,
        ini = true,
        java = true,
        javascript = true,
        javascript_react = true,
        json = true,
        kotlin = true,
        latex = true,
        less = true,
        lua = true,
        makefile = true,
        markdown = true,
        matlab = true,
        objectivec = true,
        ocaml = true,
        perl = true,
        php = true,
        powershell = true,
        python = true,
        restructuredtext = true,
        ruby = true,
        rust = true,
        sass = true,
        scala = true,
        shell = true,
        swift = true,
        toml = true,
        typescript = true,
        viml = true,
        xml = true,
        yaml = true,
        zsh = true,
    }
})

Plugins

Neopywal also provides theme support for other plugins in the Neovim ecosystem. To enable/disable a plugin you just need to set it to true/false.

require("neopywal").setup({
    plugins = {
        alpha = true,
        dashboard = false,
        git_gutter = true,
        indent_blankline = true,
        lazy = true,
        lazygit = true,
        noice = false,
        notify = true,
        nvim_cmp = true,
        mini = {
            hipatterns = true,
            indentscope = {
                enabled = false,
            },
            pick = true,
            starter = true,
        },
    },
})

Some plugins are enabled by default, you can control this behaviour with the default_plugins option.

require("neopywal").setup({
    default_plugins = false,
})

Below is a list of supported plugins and their corresponding configuration module.

Plugin Default
aerial.nvim
aerial = true
ale
ale = false
alpha-nvim
alpha = true
barbar.nvim
barbar = false
barbecue.nvim
Special

Update your Barbecue config to use the Neopywal theme:

local has_barbecue, barbecue = pcall(require, "barbecue")
if not has_barbecue then
    return
end

local has_neopywal, neopywal_barbecue = pcall(require, "neopywal.theme.plugins.barbecue")
if not has_neopywal then
    return
end

neopywal_barbecue.setup()

barbecue.setup({
    theme = "neopywal"
    -- The rest of your barbecue config ...
})

Notice that calling setup() is optional. You may pass a lua table in order to change style settings and any of groups from the Neopywal theme.

local neopywal_barbecue = require("neopywal.theme.plugins.barbecue")

neopywal_barbecue.setup({
    dim_background = false, -- Whether to dim the background.
    dim_context = true, -- Whether the context should be dimmed.
    dim_dirname = true, -- Whether the directory name should be dimmed.
    hide_separator = false, -- Whether to hide the separator character.
    basename_style = { "bold", "italic" },
    context_style = {},
    dirname_style = {},

    -- With this option you can overwrite any of the groups from the builtin theme.
    -- For more information take a look at `:h barbecue-recipes` and at
    -- `https://github.com/RedsXDD/neopywal.nvim#Customizing-Highlights`
    -- as this option works exactly the same as `custom_highlights`.
    theme = {},
})
beacon.nvim
beacon = {
    enabled = false,

    -- Can either be:
    --   - A color exported by "get_colors()" (e.g.: `color8`)
    --   - A hexadecimal color (e.g.: "#ff0000").
    --   - A function with an optional "C" parameter that returns one of the two options above.
    --     e.g: function(C) return C.color1 end
    color = "",
},
bufferline.nvim
Special

Update your bufferline config to use the Neopywal highlights:

[!Note] Bufferline needs to be loaded after setting up Neopywal or it will highlight incorrectly.

Configuration for packer.nvim users:

use "akinsho/bufferline.nvim" {
  after = "neopywal",
  config = function()
    require("bufferline").setup({
      highlights = require("neopywal.theme.plugins.bufferline").setup()
    })
  end
}

Configuration for lazy.nvim users:

{
    "RedsXDD/neopywal.nvim",
    name = "neopywal",
    lazy = false,
    priority = 1000, -- Neopywal loads first because it has higher priority.
},
{
    "akinsho/bufferline.nvim",
    config = function()
        require("bufferline").setup({
            highlights = require("neopywal.theme.plugins.bufferline").setup()
        })
    end
}

Overwriting highlights can be done inside the setup() function, see :h bufferline-highlights for detailed explanations:

local C = require("neopywal").get_colors()
bufferline.setup({
    highlights = require("neopywal.theme.plugins.bufferline").setup({
        fill = { bg = C.color1 },
        background = { fg = "#00ff00" },
    })
})
coc.nvim
coc = false

Setting enabled to true will also enable the LSP plugin.

lsp = true,

Note

coc.nvim by default links to the native LSP highlight groups so the configuration from the lsp option will also apply to coc.

colorful-winsep.nvim
colorful_winsep = {
    enabled = false,

    -- Can either be:
    --   - A color exported by "get_colors()" (e.g.: `color8`)
    --   - A hexadecimal color (e.g.: "#ff0000").
    --   - A function with an optional "C" parameter that returns one of the two options above.
    --     e.g: function(C) return C.color1 end
    color = "",
}
dashboard-nvim
dashboard = true
diffview.nvim
diffview = false
dropbar.nvim
dropbar = {
    enabled = false,
    colored_text = false, -- Whether to add color for kind's texts.
},
feline.nvim
Special

Update your Feline config to use the Neopywal components:

local has_feline, feline = pcall(require, "feline")
if not has_feline then
    return
end

local has_neopywal, neopywal_feline = pcall(require, "neopywal.theme.plugins.feline")
if not has_neopywal then
    return
end

neopywal_feline.setup()

feline.setup({
    components = neopywal_feline.get(),
})

Notice that calling setup() is optional. You may pass a lua table in order to change assets, settings and the colors per vim mode.

Here are the defaults:

local C = require("neopywal").get_colors()
local U = require("neopywal.utils.color")

local neopywal_feline = require("neopywal.theme.plugins.feline")

neopywal_feline.setup({
    assets = {
        left_separator = "ξ‚Ά",
        right_separator = "ξ‚΄",
        mode_icon = "",
        dir = "󰉋",
        file = "σ°ˆ™",
        lsp = {
            server = "σ°…‘",
            error = "",
            warning = "",
            info = "",
            hint = "",
        },
        git = {
            branch = "ξœ₯",
            added = "",
            changed = "ο…„",
            removed = "",
        },
    },
    mode_colors = {
        ["n"] = { "NORMAL", C.color4 },
        ["no"] = { "N-PENDING", C.color4 },
        ["i"] = { "INSERT", C.color6 },
        ["ic"] = { "INSERT", C.color6 },
        ["t"] = { "TERMINAL", C.color3 },
        ["v"] = { "VISUAL", C.color5 },
        ["V"] = { "V-LINE", C.color5 },
        ["οΏ½"] = { "V-BLOCK", C.color5 },
        ["R"] = { "REPLACE", C.color2 },
        ["Rv"] = { "V-REPLACE", C.color2 },
        ["s"] = { "SELECT", U.blend(C.color1, C.color3, 0.5) },
        ["S"] = { "S-LINE", U.blend(C.color1, C.color3, 0.5) },
        ["οΏ½"] = { "S-BLOCK", U.blend(C.color1, C.color3, 0.5) },
        ["c"] = { "COMMAND", C.color1 },
        ["cv"] = { "COMMAND", C.color1 },
        ["ce"] = { "COMMAND", C.color1 },
        ["r"] = { "PROMPT", C.foreground },
        ["rm"] = { "MORE", C.foreground },
        ["r?"] = { "CONFIRM", C.color2 },
        ["!"] = { "SHELL", C.color1 },
    },
    sett = {
        text = C.foreground,
        bkg = U.blend(C.color8, C.background, 0.3),
        diffs = U.blend(C.color8, C.background, 0.5),
        extras = C.foreground,
        curr_file = U.blend(C.color8, C.background, 0.5),
        curr_dir = C.color4,
        show_modified = false, -- Show if the file has been modified.

        -- Show the count of updatable plugins from lazy.nvim.
        -- Need to set checker.enabled = true in lazy.nvim first
        -- the icon is set in ui.icons.plugin in lazy.nvim.
        show_lazy_updates = false,
    },
    view = {
        lsp = {
            progress = true, -- If true the status bar will display an lsp progress indicator.
            name = false, -- If true the status bar will display the lsp servers name, otherwise it will display the text "Lsp".
            exclude_lsp_names = {}, -- Lsp server names that should not be displayed when name is set to true.
            separator = "|", -- The separator used when there are multiple lsp servers.
        },
    },
})

[!Warning] Currently feline doesn't officially support custom themes. In order for :colorscheme neopywal to work you could add this autocmd as a workaround:

vim.api.nvim_create_autocmd("ColorScheme", {
    pattern = "*",
    callback = function()
        package.loaded["feline"] = nil
        package.loaded["neopywal.theme.plugins.feline"] = nil
        require("feline").setup({
            components = require("neopywal.theme.plugins.feline").get(),
        })
    end,
})
fern.vim
fern = false
fidget.nvim
Special

Update your Fidget config to use Neopywal's highlight groups.

local has_fidget, fidget = pcall(require, "fidget")
if not has_fidget then
    return
end

local has_neopywal, neopywal_fidget = pcall(require, "neopywal.theme.plugins.fidget")
if not has_neopywal then
    return
end

-- This is what loads the highlight groups that are used inside Fidget's setup function.
neopywal_fidget.setup()

fidget.setup({
    progress = {
        display = {
            done_style = "FidgetDone",
            progress_style = "FigdetProgress",
            group_style = "FidgetGroup",
            icon_style = "FidgetIcon",
        },
    },
    notification = {
        view = {
            group_separator_hl = "FidgetSeparator",
        },
        window = {
            normal_hl = "FidgetNormal",

            -- You can use this option to adjust the background color opacity for the notification window.
            -- But it's recommended set this to "0" if you don't plan on changing any of the custom highlight groups.
            winblend = 0,
        },
    },
    -- The rest of your fidget config ...
})

Overriding highlight groups can be done inside the setup() function.

local neopywal_fidget = require("neopywal.theme.plugins.fidget")

local C = require("neopywal").get_colors()
local bg = require("neopywal.lib.config").options.transparent_background and C.none or C.dim_bg
neopywal_fidget.setup({
    FidgetDone = { bg = bg, fg = C.ok, styles = { "bold", "italic" } },
    FidgetGroup = { bg = bg, fg = C.foreground, styles = { "bold", "italic" } },
    FidgetIcon = { bg = bg, fg = C.color4, styles = { "bold", "italic" } },
    FidgetNormal = { bg = bg, fg = C.comment, styles = { "bold", "italic" } },
    FidgetProgress = { bg = bg, fg = C.color3, styles = { "bold", "italic" } },
    FidgetSeparator = { bg = bg, fg = C.comment, styles = { "bold", "italic" } },
})
flash.nvim
flash = {
    enabled = true,
    style = { "bold", "italic" }
}
fzf-lua
fzf = false
gitsigns.nvim
gitsigns = true
grug-far.nvim
grug_far = false
harpoon
harpoon = false
headlines.nvim
headlines = false
hop.nvim
hop = {
    enabled = false,
    style = { "bold", "italic" }
}
indent-blankline.nvim
indent_blankline = {
    enabled = true,
    colored_indent_levels = false,

    -- Can either be:
    --   - A color exported by "get_colors()" (e.g.: `color8`)
    --   - A hexadecimal color (e.g.: "#ff0000").
    --   - A function with an optional "C" parameter that returns one of the two options above.
    --     e.g: function(C) return C.color1 end
    scope_color = "",
}

colored_indent_levels enables character highlights per indent level. Follow the instructions here to set the latter up.

indentmini.nvim
indentmini = {
    enabled = false,

    -- These options either be:
    --   - A color exported by "get_colors()" (e.g.: `color8`)
    --   - A hexadecimal color (e.g.: "#ff0000").
    --   - A function with an optional "C" parameter that returns one of the two options above.
    --     e.g: function(C) return C.color1 end
    scope_color = "",
    current_scope_color = "",
},
lazy.nvim
lazy = true
lazygit.nvim
lazygit = true
leap.nvim
leap = {
    enabled = false,
    style = { "bold", "italic" }
}
lightline.vim
Special

Update your Lightline config to use the Neopywal theme:

lua << EOF
    local has_neopywal, neopywal_lightline = pcall(require, "neopywal.theme.plugins.lightline")
    if not has_neopywal then
        return
    end

    neopywal_lightline.setup()
EOF

let g:lightline = {'colorscheme': 'neopywal'}

Notice that calling setup() is optional. You may pass a lua table in order to change the colors per vim mode.

lua << EOF
    local neopywal_lightline = require("neopywal.theme.plugins.lightline")

    neopywal_lightline.setup({
        -- Any of the color values can either be:
        --   - A color exported by "get_colors()" (e.g.: `color8`)
        --   - A hexadecimal color (e.g.: "#ff0000").
        --   - A function with an optional "C" parameter that returns one of the two options above.
        --     e.g: function(C) return C.color1 end
        mode_colors = {
            normal = "color4",
            visual = "color5",
            insert = "color6",
            command = "color1",
            replace = "color2",
            terminal = "color3",
        },
    })
EOF
lir.nvim
lir = {
    enabled = false,
    git_status = false,
}
lspsaga.nvim
lspsaga = {
    enabled = false,
    dim_folder = true, -- Whether to dim the folder name on the winbar.
    dim_filename = true, -- Whether to dim the filename on the winbar.
    dim_separator = true, -- Whether to dim the separator character on the winbar.
    winbar_style = { "bold" },
},

For custom LSP kind icons and color:

require("lspsaga").setup({
    ui = {
        kind = require("neopywal.theme.plugins.lspsaga").get_kinds(),
    },
})
lualine.nvim
Special

Update your Lualine config to use the Neopywal theme:

local has_lualine, lualine = pcall(require, "lualine")
if not has_lualine then
    return
end

local has_neopywal, neopywal_lualine = pcall(require, "neopywal.theme.plugins.lualine")
if not has_neopywal then
    return
end

neopywal_lualine.setup()

lualine.setup({
    options = {
        theme = "neopywal"
        -- The rest of your lualine config ...
    }
})

Notice that calling setup() is optional. You may pass a lua table in order to change style settings and the colors per vim mode.

local neopywal_lualine = require("neopywal.theme.plugins.lualine")

neopywal_lualine.setup({
    -- Any of the color values can either be:
    --   - A color exported by "get_colors()" (e.g.: `color8`)
    --   - A hexadecimal color (e.g.: "#ff0000").
    --   - A function with an optional "C" parameter that returns one of the two options above.
    --     e.g: function(C) return C.color1 end
    mode_colors = {
        normal = "color4",
        visual = "color5",
        insert = "color6",
        command = "color1",
        replace = "color2",
        terminal = "color3",
    },
    styles = {
        a = { "bold" },
        b = { "bold" },
        c = { "bold" },
        x = { "bold" },
        y = { "bold" },
        z = { "bold" },
    },
})
markdown.nvim
markdown = false,
mason.nvim
mason = true,
mini.nvim
Special
Plugin Default
mini.animate
mini = {
    animate = true
}
mini.clue
mini = {
    clue = true
}
mini.completion
mini = {
    completion = {
        enabled = true,
        parameter_style = { "underline" },
    }
}
mini.cursorword
mini = {
    cursorword = {
        enabled = true,
        style = { "underline" },
    },
}
mini.deps
mini = {
    deps = true
}
mini.diff
mini = {
    diff = true
}
mini.files
mini = {
    files = true
}
mini.hipatterns
mini = {
    hipatterns = {
        enabled = true,
        style = {
            fixme = { "bold", "italic" },
            hack = { "bold", "italic" },
            note = { "bold", "italic" },
            todo = { "bold", "italic" },
        },
    },
}
mini.icons
mini = {
    icons = true
}
mini.indentscope
mini = {
    indentscope = {
        enabled = true,

        -- Can either be:
        --   - A color exported by "get_colors()" (e.g.: `color8`)
        --   - A hexadecimal color (e.g.: "#ff0000").
        --   - A function with an optional "C" parameter that returns one of the two options above.
        --     e.g: function(C) return C.color1 end
        scope_color = "",
    }
}
mini.jump
mini = {
    jump = {
        enabled = true,
        style = { "bold", "italic" },
    },
}
mini.jump2d
mini = {
    jump2d = {
        enabled = true,
        style = { "bold", "italic" },
    },
}
mini.map
mini = {
    map = true
}
mini.notify
mini = {
    notify = true
}
mini.operators
mini = {
    operators = true
}
mini.pick
mini = {
    pick = true
}
mini.starter
mini = {
    starter = true
}
mini.statusline
mini = {
    statusline = {
        enabled = true,

        -- Any of the color values can either be:
        --   - A color exported by "get_colors()" (e.g.: `color8`)
        --   - A hexadecimal color (e.g.: "#ff0000").
        --   - A function with an optional "C" parameter that returns one of the two options above.
        --     e.g: function(C) return C.color1 end
        mode_colors = {
            normal = "color4",
            visual = "color5",
            insert = "color6",
            command = "color1",
            replace = "color2",
            other = "color3", -- e.g.: terminal.
        },
    },
}
mini.surround
mini = {
    surround = true
}
mini.tabline
mini = {
    tabline = true
}
mini.test
mini = {
    test = true
}
mini.trailspace
mini = {
    trailspace = {
        enabled = true,

        -- Can either be:
        --   - A color exported by "get_colors()" (e.g.: `color8`)
        --   - A hexadecimal color (e.g.: "#ff0000").
        --   - A function with an optional "C" parameter that returns one of the two options above.
        --     e.g: function(C) return C.color1 end
        color = "",
    },
}
neogit
neogit = false
neotest
neotest = false
neo-tree.nvim
neotree = true
netrw
netrw = true
noice.nvim
noice = true
NormalNvim
NormalNvim = false
notifier.nvim
notifier = false
nvim-cmp
nvim_cmp = true
nvim-dap
dap = false
Special
local sign = vim.fn.sign_define

sign("DapBreakpoint", { text = "●", texthl = "DapBreakpoint", linehl = "", numhl = ""})
sign("DapBreakpointCondition", { text = "●", texthl = "DapBreakpointCondition", linehl = "", numhl = ""})
sign("DapLogPoint", { text = "β—†", texthl = "DapLogPoint", linehl = "", numhl = ""})
nvim-dap-ui
dap_ui = false
nvim-lspconfig
lsp = {
    enabled = true,
    virtual_text = {
        errors = { "bold", "italic" },
        hints = { "bold", "italic" },
        information = { "bold", "italic" },
        ok = { "bold", "italic" },
        warnings = { "bold", "italic" },
        unnecessary = { "bold", "italic" },
    },
    underlines = {
        errors = { "undercurl" },
        hints = { "undercurl" },
        information = { "undercurl" },
        ok = { "undercurl" },
        warnings = { "undercurl" },
    },
    inlay_hints = {
        background = true,
        style = { "bold", "italic" },
    },
},
nvim-navic
navic = {
    enabled = false,
    dim_text = false, -- Whether the text should be dimmed.
    hide_separator = false, -- Whether to hide the separator character.
    text_style = { "bold", "italic" },

    -- Can either be:
    --   - A color exported by "get_colors()" (e.g.: `color8`)
    --   - A hexadecimal color (e.g.: "#ff0000").
    --   - A function with an optional "C" parameter that returns one of the two options above.
    --     e.g: function(C) return C.color1 end
    bg_color = "",
},
Special
-- You NEED to enable highlight in nvim-navic setting or it won't work.
require("nvim-navic").setup({
    highlight = true
})

If you want to make background color similar to what's used on lualine/feline you can do the following:

require("neopywal").setup({
    plugins = {
        navic = {
            bg_color = function(C)
                local U = require("neopywal.utils.color")

                -- `0.5` would match the color used on lualine's "b" section.
                return U.blend(C.color8, C.background, 0.3)
            end
        }
    }
})
nvim-notify
notify = true
nvim-scrollbar
scrollbar = false
nvim-tree.lua
nvimtree = true
nvim-surround
surround = false
nvim-treesitter
treesitter = true
nvim-treesitter-context
ts_context = {
    enabled = true,
    dim_background = false,

    -- NOTE: This option only applies to the current context line.
    -- You may want to disable "underline" if you configured the "separator" option within ts_context.
    style = { "bold", "underline" },
},
nvim-ts-rainbow
ts_rainbow = false
nvim-ts-rainbow2
ts_rainbow2 = false
nvim-ufo
ufo = true
nvim-window-picker
window_picker = {
    enabled = false,

    -- Can either be:
    --   - A color exported by "get_colors()" (e.g.: `color8`)
    --   - A hexadecimal color (e.g.: "#ff0000").
    --   - A function with an optional "C" parameter that returns one of the two options above.
    --     e.g: function(C) return C.color1 end
    color = "",
},
octo.nvim
octo = false
overseer.nvim
overseer = false
pounce.nvim
pounce = {
    enabled = false,
    style = { "bold", "italic" }
}
rainbow-delimiters.nvim
rainbow = false
reactive.nvim
Special

Update your Reactive config to use the Neopywal theme:

local has_reactive, reactive = pcall(require, "reactive")
if not has_reactive then
    return
end

local has_neopywal, neopywal_reactive = pcall(require, "neopywal.theme.plugins.reactive")
if not has_neopywal then
    return
end

neopywal_reactive.setup()

reactive.setup({
    -- Note that there are 2 available presets, `cursor` and `cursorline`.
    load = { "neopywal-cursor", "neopywal-cursorline" }
    -- The rest of your reactive config ...
})

Notice that calling setup() is optional. You may pass a lua table in order to change the color settings per vim mode.

local neopywal_reactive = require("neopywal.theme.plugins.reactive")

neopywal_reactive.setup({
    -- A higher percentage means more vibrant mode colors,
    -- where "1" means to use "exactly" the mode color without any color transparency.
    color_percentage = 0.3,

    -- Any of the color values can either be:
    --   - A color exported by "get_colors()" (e.g.: `color8`)
    --   - A hexadecimal color (e.g.: "#ff0000").
    --   - A function with an optional "C" parameter that returns one of the two options above.
    --     e.g: function(C) return C.color1 end
    mode_colors = {
        visual = "color5",
        insert = "color6",
        replace = "color2",

        -- Normal mode operations.
        change = "color2",
        delete = "color1",
        pending = "color4",
        yank = "color3",
    },
})
symbols-outline.nvim

Note

This plugin has been archived by the author, consider using outline.nvim

symbols_outline = false
telekasten.nvim
telekasten = false
telescope.nvim
telescope = {
    enabled = true,
    -- style = "nvchad"
}
trouble.nvim
trouble = false,
undotree
undotree = true
vimwiki
vimwiki = false
vim-dadbod-ui
dadbod_ui = false
vim-airline
Special

Update your Airline config to use the Neopywal theme:

lua << EOF
    local has_neopywal, neopywal_airline = pcall(require, "neopywal.theme.plugins.airline")
    if not has_neopywal then
        return
    end

    neopywal_airline.setup()
EOF

let g:airline_theme = 'neopywal'

Notice that calling setup() is optional. You may pass a lua table in order to change style settings and the colors per vim mode.

lua << EOF
    local neopywal_airline = require("neopywal.theme.plugins.airline")

    neopywal_airline.setup({
        -- Any of the color values can either be:
        --   - A color exported by "get_colors()" (e.g.: `color8`)
        --   - A hexadecimal color (e.g.: "#ff0000").
        --   - A function with an optional "C" parameter that returns one of the two options above.
        --     e.g: function(C) return C.color1 end
        mode_colors = {
            normal = "color4",
            visual = "color5",
            insert = "color6",
            commandline = "color1",
            replace = "color2",
            terminal = "color3",
        },

        -- This is the same as `mode_colors` except it uses cterm numbers instead (see `:h cterm`)
        -- e.g.: "normal = 4" means "ctermfg=4".
        cterm_colors = {
            normal = 4,
            visual = 5,
            insert = 6,
            commandline = 1,
            replace = 2,
            terminal = 3,
        },
        styles = {
            a = { "bold" },
            b = { "bold" },
            c = { "bold" },
            x = { "bold" },
            y = { "bold" },
            z = { "bold" },
        },
    })
EOF
vim-clap
Special

Update your Clap config to use the Neopywal theme:

lua << EOF
    local has_neopywal, neopywal_clap = pcall(require, "neopywal.theme.plugins.clap")
    if not has_neopywal then
        return
    end

    neopywal_clap.setup()
EOF

let g:clap_theme = 'neopywal'

Notice that calling setup() is optional. You may pass a lua table in order to change style settings and the text colors.

lua << EOF
    local neopywal_clap = require("neopywal.theme.plugins.clap")

    neopywal_clap.setup({
        -- Any of the color values can either be:
        --   - A color exported by "get_colors()" (e.g.: `color8`)
        --   - A hexadecimal color (e.g.: "#ff0000").
        --   - A function with an optional "C" parameter that returns one of the two options above.
        --     e.g: function(C) return C.color1 end
        colors = {
            indicator = "color8", -- The text for the number of matches.
            spinner = "color2", -- The text representing the mode.
            selected = "color6", -- The text of the line of a selected item.
            current_selection = "color4", -- The text of the line of the currently selected item.
        },
        styles = {
            indicator = { "italic" }, -- The text for the number of matches.
            spinner = { "bold" }, -- The text representing the mode.
            selected = { "bold", "underline" }, -- The line for a selected item.
            current_selection = { "bold" }, -- The line for the currently selected item.
        },
    })
EOF
vim-gitgutter
git_gutter = true
vim-glyph-palette
glyph_palette = false
vim-illuminate
illuminate = {
    enabled = false,
    lsp = true,
    style = { "bold" },
},
vim-sandwich
sandwich = false
vim-sneak
sneak = {
    enabled = false,
    style = { "bold", "italic" },

    -- Can either be:
    --   - A color exported by "get_colors()" (e.g.: `color8`)
    --   - A hexadecimal color (e.g.: "#ff0000").
    --   - A function with an optional "C" parameter that returns one of the two options above.
    --     e.g: function(C) return C.color1 end
    sneak_color = "",
},
which-key.nvim
which_key = true
yanky.nvim
yanky = false

Compilation

Neopywal can pre-compute your configuration and store the results in a compiled lua file stored into the system's cache directory, which then gets loaded when the colorscheme is applied. This approach greatly improves performance and reduces the total execution time.

Note that you can always manually recompile Neopywal with the :NeopywalCompile command. But that shouldn't be needed since Neopywal is capable of automatically recompiling the colorscheme when any change is detected on the user configuration or when a new theme is generated by Pywal.

Importing colors

You can use the internal function get_colors() if you want to import the colors into a lua table:

local C = require("neopywal").get_colors()

This will import a lua table containing all the colors auto generated by Pywal as well as any custom colors defined the custom colors table.

Note

Calling get_color() before setup() can be done, however the exported colors table will always use the default ~/.cache/wal/colors-wal.vim template file (or use the fallback colors) and won't have any additional custom colors set by the custom_colors() option.

Note that the naming of some of them are not exactly clear if you're not used to the way Pywal exports them.

colors = {
    none       -- Use this keyword if you want a transparent color.
    background -- Main background color.
    foreground -- Main foreground color.
    cursor     -- Cursor color.
    color0     -- Black.
    color1     -- Red.
    color2     -- Green.
    color3     -- Yellow.
    color4     -- Blue.
    color5     -- Magenta.
    color6     -- Cyan.
    color7     -- White.
    color8     -- Bright black.
    color9     -- Bright red.
    color10    -- Bright green.
    color11    -- Bright yellow.
    color12    -- Bright blue.
    color13    -- Bright magenta.
    color14    -- Bright cyan.
    color15    -- Bright white.
}

Then you can apply the colors in a way similar to the one found in custom highlights.

Example

local C = require("neopywal").get_colors()

return {
    color_var1 = { C.color1 }
    color_var2 = { C.color2 }
    color_var3 = { C.color3 }
}

Utilities

Neopywal offers a neat set of utility functions that allows the user to improve the builtin Neopywal color palette without having to create new color definitions.

require("neopywal.utils.color").darken(color, factor)
require("neopywal.utils.color").lighten(color, factor)
require("neopywal.utils.color").blend(color1, color2, factor)

Note

All color parameters for the functions have to be in hexadecimal format.

The Darken and Lighten Functions

The darken() and lighten() functions are able to create new colors by darkening/lightening existing colors. Both functions take two parameters, the first one is the color you want to modify, the second is an integer that defines how much each color will be darken/lighten.

local C = require("neopywal").get_colors()
local U = require("neopywal.utils.color")

color_var1 = { U.lighten(C.color1, 30) }
color_var2 = { U.darken(C.color2, 30) }

The Blend Function

The blend() function combines two colors to create a new color that is a mixture of the two input colors. The function takes three parameters:

  • The first two parameters define the colors to be blended.
  • The third factor parameter is a number between 0 and 1 that determines the proportion of each color in the final output. Where 0 means "use the exact same color as the first parameter" and 1 means "use the exact same color as the second parameter".
local C = require("neopywal").get_colors()
local U = require("neopywal.utils.color")

color_var1 = { U.darken(C.color1, C.color3, 0) }
color_var2 = { U.darken(C.color1, C.color3, 1) }
color_var3 = { U.blend(C.color1, C.color3, 0.5) }

In that example:

  • color_var1 will be identical to C.color1.
  • color_var2 will be identical to C.color3.
  • color_var3 will be a 50/50 mix of C.color1 and C.color3.

Pywal Alternatives

As stated before, Pywal has been officially deprecated on April 26, 2024. So it's not recommend to use it.

One idea to mitigate that problem would be to use a fork that's feature compatible with Pywal, or that at very least exports the same color variables that are necessary for this plugin to work. There are two projects that i personally recommend as a Pywal replacement:

  1. Pywal16 by ellyes, which is a drop-in replacement for Pywal, so no extra work has to be done.
  2. Wallust by explosion-mental, which requires some additional configuration to work with Neopywal.

If you plan on using Wallust, here's a guide on how to set it up with Neopywal:

Setting up Wallust

After installing Wallust, you will need to create two files. The first is a template file that should be located on ~/.config/wallust/templates/colors_neopywal.vim, the second is the default configuration file for Wallust, which should be created at ~/.config/wallust/wallust.toml.

Here are the contents that should be copied of to them:

colors_neopywal.vim

let background = "{{background}}"
let foreground = "{{foreground}}"
let cursor = "{{cursor}}"
let color0 = "{{color0}}"
let color1 = "{{color1}}"
let color2 = "{{color2}}"
let color3 = "{{color3}}"
let color4 = "{{color4}}"
let color5 = "{{color5}}"
let color6 = "{{color6}}"
let color7 = "{{color7}}"
let color8 = "{{color8}}"
let color9 = "{{color9}}"
let color10 = "{{color10}}"
let color11 = "{{color11}}"
let color12 = "{{color12}}"
let color13 = "{{color13}}"
let color14 = "{{color14}}"
let color15 = "{{color15}}"

wallust.toml

neopywal.template = "templates/colors_neopywal.vim"
neopywal.target = "~/.cache/wallust/colors_neopywal.vim"

After that you need to enable the use_wallust option on you Neopywal configuration.

require("neopywal").setup({
    use_wallust = true,
})

Enabling this option makes Neopywal automatically read the template file that will be generated by Wallust on ~/.cache/wallust/colors_neopywal.vim, and with that Neopywal should work exactly the same as if you were using Pywal.

How it Works

Pywal automatically generates a file called colors-wal.vim in ~/.cache/wal/colors-wal.vim, the file contains all the colors variables that are necessary to create a color dictionary that can be used to generate a Neovim colorscheme. The file looks like this:

" Special
let wallpaper  = "/home/user/Pictures/wallpaper.png"
let background = "#1E1E2E"
let foreground = "#CDD6F4"
let cursor     = "#F5E0DC"

" Colors
let color0  = "#45475A"
let color1  = "#F38BA8"
let color2  = "#A6E3A1"
let color3  = "#F9E2AF"
let color4  = "#89B4FA"
let color5  = "#F5C2E7"
let color6  = "#94E2D5"
let color7  = "#BAC2DE"
let color8  = "#585B70"
let color9  = "#F38BA8"
let color10 = "#A6E3A1"
let color11 = "#F9E2AF"
let color12 = "#89B4FA"
let color13 = "#F5C2E7"
let color14 = "#94E2D5"
let color15 = "#A6ADC8"

All Neopywal does is reading the contents of the file and exportting them into a lua table that then is used to apply the highlight groups that build the colorscheme.

Enjoy

If you like this work you can give this project a star ⭐