feat: my own neovim theme!

This commit is contained in:
Stevan Freeborn
2026-06-30 15:07:14 -05:00
commit a9d19660da
11 changed files with 659 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
local M = {}
M.options = {
styles = {
comments = { italic = true },
keywords = { italic = false },
functions = {},
variables = {},
types = {},
numbers = {},
operators = {},
strings = {},
conditionals = {},
loops = {},
},
}
function M.setup(opts)
M.options = vim.tbl_deep_extend("force", M.options, opts or {})
end
return M
+95
View File
@@ -0,0 +1,95 @@
local function get(p)
return {
Normal = { fg = p.fg_bright, bg = p.bg },
NormalFloat = { fg = p.fg_bright, bg = p.bg_dark },
NormalNC = { fg = p.fg, bg = p.bg },
EndOfBuffer = { fg = p.bg },
Cursor = { fg = p.bg, bg = p.fg_bright },
lCursor = { link = "Cursor" },
CursorIM = { link = "Cursor" },
CursorLine = { bg = p.bg_highlight },
CursorColumn = { bg = p.bg_highlight },
CursorLineNr = { fg = p.gold },
LineNr = { fg = p.fg_muted2 },
SignColumn = { bg = p.bg },
FoldColumn = { fg = p.fg_subtle, bg = p.bg },
Folded = { fg = p.fg_muted, bg = p.bg_highlight },
Pmenu = { fg = p.fg, bg = p.bg_dark },
PmenuSel = { fg = p.fg_bright, bg = p.deep_lavender },
PmenuSbar = { bg = p.bg_visual },
PmenuThumb = { bg = p.fg_subtle },
PmenuKind = { fg = p.lavender },
PmenuKindSel = { fg = p.fg_white, bg = p.deep_lavender },
PmenuExtra = { fg = p.fg_muted },
PmenuExtraSel = { fg = p.fg_bright },
Search = { fg = p.bg, bg = p.gold },
IncSearch = { fg = p.bg, bg = p.bright_gold },
CurSearch = { fg = p.bg, bg = p.bright_gold },
Substitute = { fg = p.bg, bg = p.coral },
Visual = { bg = p.accent_subtle },
VisualNOS = { bg = p.accent_subtle },
MatchParen = { bg = p.accent_muted },
ColorColumn = { bg = p.bg_highlight },
Conceal = { fg = p.fg_subtle },
SpellBad = { sp = p.coral, undercurl = true },
SpellCap = { sp = p.gold, undercurl = true },
SpellLocal = { sp = p.teal, undercurl = true },
SpellRare = { sp = p.lavender, undercurl = true },
StatusLine = { fg = p.fg, bg = p.bg_highlight },
StatusLineNC = { fg = p.fg_muted, bg = p.bg },
TabLine = { fg = p.fg_muted, bg = p.bg },
TabLineFill = { bg = p.bg },
TabLineSel = { fg = p.fg_bright, bg = p.bg_highlight },
WinSeparator = { fg = p.bg_border },
VertSplit = { fg = p.bg_border },
FloatBorder = { fg = p.lavender, bg = p.bg_dark },
FloatTitle = { fg = p.lavender },
NonText = { fg = p.bg_visual },
Whitespace = { fg = p.bg_visual },
SpecialKey = { fg = p.fg_subtle },
Question = { fg = p.lavender },
Title = { fg = p.lavender },
WarningMsg = { fg = p.gold },
ErrorMsg = { fg = p.coral },
MoreMsg = { fg = p.teal },
ModeMsg = { fg = p.fg },
WildMenu = { fg = p.bg, bg = p.lavender },
QuickFixLine = { bg = p.accent_subtle },
DiffAdd = { bg = p.success_muted },
DiffDelete = { bg = p.danger_muted },
DiffChange = { bg = p.attention_muted },
DiffText = { bg = p.attention_muted },
diffAdded = { fg = p.teal },
diffRemoved = { fg = p.coral },
diffFile = { fg = p.lavender },
diffNewFile = { fg = p.teal },
diffLine = { fg = p.fg_muted },
diffIndexLine = { fg = p.fg_muted },
Directory = { fg = p.lavender },
Debug = { fg = p.coral },
DebugPC = { bg = p.accent_subtle },
DebugBreakpoint = { fg = p.bg, bg = p.coral },
}
end
return { get = get }
+80
View File
@@ -0,0 +1,80 @@
local function get(p)
return {
DiagnosticError = { fg = p.coral },
DiagnosticWarn = { fg = p.gold },
DiagnosticInfo = { fg = p.lavender },
DiagnosticHint = { fg = p.fg_muted },
DiagnosticOk = { fg = p.teal },
DiagnosticVirtualTextError = { fg = p.coral },
DiagnosticVirtualTextWarn = { fg = p.gold },
DiagnosticVirtualTextInfo = { fg = p.lavender },
DiagnosticVirtualTextHint = { fg = p.fg_muted },
DiagnosticVirtualTextOk = { fg = p.teal },
DiagnosticUnderlineError = { sp = p.coral, undercurl = true },
DiagnosticUnderlineWarn = { sp = p.gold, undercurl = true },
DiagnosticUnderlineInfo = { sp = p.lavender, undercurl = true },
DiagnosticUnderlineHint = { sp = p.fg_muted, undercurl = true },
DiagnosticUnderlineOk = { sp = p.teal, undercurl = true },
DiagnosticFloatingError = { fg = p.coral },
DiagnosticFloatingWarn = { fg = p.gold },
DiagnosticFloatingInfo = { fg = p.lavender },
DiagnosticFloatingHint = { fg = p.fg_muted },
DiagnosticSignError = { fg = p.coral },
DiagnosticSignWarn = { fg = p.gold },
DiagnosticSignInfo = { fg = p.lavender },
DiagnosticSignHint = { fg = p.fg_muted },
DiagnosticSignOk = { fg = p.teal },
DiagnosticDeprecated = { sp = p.coral, strikethrough = true },
DiagnosticUnnecessary = { fg = p.fg_muted2 },
LspReferenceText = { bg = p.accent_subtle },
LspReferenceRead = { bg = p.accent_subtle },
LspReferenceWrite = { bg = p.accent_subtle },
LspSignatureActiveParameter = { fg = p.gold, bold = true },
LspInlayHint = { fg = p.fg_muted2, bg = p.bg_highlight },
LspCodeLens = { fg = p.fg_muted },
LspCodeLensSeparator = { fg = p.fg_muted },
LspInfoBorder = { fg = p.lavender },
-- Legacy LSP diagnostic groups
LspDiagnosticsDefaultError = { fg = p.coral },
LspDiagnosticsDefaultWarning = { fg = p.gold },
LspDiagnosticsDefaultInformation = { fg = p.lavender },
LspDiagnosticsDefaultHint = { fg = p.fg_muted },
LspDiagnosticsDefaultOk = { fg = p.teal },
LspDiagnosticsVirtualTextError = { fg = p.coral },
LspDiagnosticsVirtualTextWarning = { fg = p.gold },
LspDiagnosticsVirtualTextInformation = { fg = p.lavender },
LspDiagnosticsVirtualTextHint = { fg = p.fg_muted },
LspDiagnosticsUnderlineError = { sp = p.coral, undercurl = true },
LspDiagnosticsUnderlineWarning = { sp = p.gold, undercurl = true },
LspDiagnosticsUnderlineInformation = { sp = p.lavender, undercurl = true },
LspDiagnosticsUnderlineHint = { sp = p.fg_muted, undercurl = true },
LspDiagnosticsFloatingError = { fg = p.coral },
LspDiagnosticsFloatingWarning = { fg = p.gold },
LspDiagnosticsFloatingInformation = { fg = p.lavender },
LspDiagnosticsFloatingHint = { fg = p.fg_muted },
LspDiagnosticsSignError = { fg = p.coral },
LspDiagnosticsSignWarning = { fg = p.gold },
LspDiagnosticsSignInformation = { fg = p.lavender },
LspDiagnosticsSignHint = { fg = p.fg_muted },
-- Terminal colors
Terminal = { bg = p.bg },
healthError = { fg = p.coral },
healthSuccess = { fg = p.teal },
healthWarning = { fg = p.gold },
}
end
return { get = get }
+62
View File
@@ -0,0 +1,62 @@
local function get(p, config)
local styles = config.styles
local function st(style_opts)
local result = {}
if style_opts then
for k, v in pairs(style_opts) do
result[k] = v
end
end
return result
end
return {
Comment = vim.tbl_extend("force", { fg = p.fg_muted2 }, st(styles.comments)),
Constant = { fg = p.gold },
String = { fg = p.lavender },
Character = { fg = p.lavender },
Number = { fg = p.gold },
Boolean = { fg = p.gold },
Float = { fg = p.gold },
Identifier = { fg = p.fg_bright },
Function = vim.tbl_extend("force", { fg = p.deep_lavender }, st(styles.functions)),
Statement = vim.tbl_extend("force", { fg = p.coral }, st(styles.keywords)),
Conditional = vim.tbl_extend("force", { fg = p.coral }, st(styles.conditionals)),
Repeat = vim.tbl_extend("force", { fg = p.coral }, st(styles.loops)),
Label = { fg = p.coral },
Operator = vim.tbl_extend("force", { fg = p.gold }, st(styles.operators)),
Keyword = vim.tbl_extend("force", { fg = p.coral }, st(styles.keywords)),
Exception = { fg = p.coral },
PreProc = { fg = p.coral },
Include = { fg = p.coral },
Define = { fg = p.coral },
Macro = { fg = p.coral },
PreCondit = { fg = p.coral },
Type = vim.tbl_extend("force", { fg = p.teal }, st(styles.types)),
StorageClass = { fg = p.teal },
Structure = { fg = p.teal },
Typedef = { fg = p.teal },
Special = { fg = p.fg_bright },
SpecialChar = { fg = p.fg_bright },
Tag = { fg = p.teal },
Delimiter = { fg = p.fg_dim },
SpecialComment = { fg = p.fg_muted },
Underlined = { underline = true },
Bold = { bold = true },
Italic = { italic = true },
Error = { fg = p.coral },
Todo = { fg = p.gold, bg = p.bg },
}
end
return { get = get }
+130
View File
@@ -0,0 +1,130 @@
local function get(p, config)
local styles = config.styles
return {
["@comment"] = { fg = p.fg_muted2, italic = true },
["@comment.error"] = { fg = p.coral },
["@comment.warning"] = { fg = p.gold },
["@comment.todo"] = { fg = p.gold, bold = true },
["@comment.note"] = { fg = p.lavender, bold = true },
["@comment.hint"] = { fg = p.teal },
["@constant"] = { fg = p.gold },
["@constant.builtin"] = { fg = p.gold },
["@constant.macro"] = { fg = p.gold },
["@define"] = { fg = p.gold },
["@string"] = { fg = p.lavender },
["@string.documentation"] = { fg = p.lavender },
["@string.regexp"] = { fg = p.cyan },
["@string.escape"] = { fg = p.teal },
["@string.special"] = { fg = p.teal },
["@character"] = { fg = p.lavender },
["@character.special"] = { fg = p.teal },
["@number"] = { fg = p.gold },
["@number.float"] = { fg = p.gold },
["@boolean"] = { fg = p.gold },
["@function"] = { fg = p.deep_lavender },
["@function.builtin"] = { fg = p.gold },
["@function.call"] = { fg = p.deep_lavender },
["@function.macro"] = { fg = p.gold },
["@function.method"] = { fg = p.deep_lavender },
["@function.method.call"] = { fg = p.deep_lavender },
["@parameter"] = { fg = p.fg_bright },
["@parameter.reference"] = { fg = p.fg_bright },
["@field"] = { fg = p.fg_bright },
["@property"] = { fg = p.fg_bright },
["@symbol"] = { fg = p.fg_bright },
["@variable"] = { fg = p.fg_bright },
["@variable.builtin"] = { fg = p.coral },
["@variable.member"] = { fg = p.fg_bright },
["@variable.parameter"] = { fg = p.fg_bright },
["@type"] = { fg = p.teal },
["@type.builtin"] = { fg = p.teal },
["@type.definition"] = { fg = p.teal },
["@type.qualifier"] = { fg = p.teal },
["@keyword"] = { fg = p.coral },
["@keyword.function"] = { fg = p.coral },
["@keyword.return"] = { fg = p.coral },
["@keyword.operator"] = { fg = p.coral },
["@keyword.exception"] = { fg = p.coral },
["@keyword.modifier"] = { fg = p.coral },
["@keyword.repeat"] = { fg = p.coral },
["@keyword.storage"] = { fg = p.teal },
["@keyword.conditional"] = { fg = p.coral },
["@keyword.directive"] = { fg = p.coral },
["@keyword.directive.define"] = { fg = p.coral },
["@conditional"] = { fg = p.coral },
["@repeat"] = { fg = p.coral },
["@debug"] = { fg = p.coral },
["@label"] = { fg = p.fg_bright },
["@operator"] = { fg = p.gold },
["@punctuation.delimiter"] = { fg = p.fg_dim },
["@punctuation.bracket"] = { fg = p.fg },
["@punctuation.special"] = { fg = p.coral },
["@preproc"] = { fg = p.coral },
["@include"] = { fg = p.coral },
["@attribute"] = { fg = p.teal },
["@tag"] = { fg = p.teal },
["@tag.attribute"] = { fg = p.fg_bright },
["@tag.delimiter"] = { fg = p.fg_muted },
["@namespace"] = { fg = p.teal },
["@module"] = { fg = p.deep_lavender },
["@text"] = { fg = p.fg_bright },
["@text.strong"] = { bold = true },
["@text.emphasis"] = { italic = true },
["@text.underline"] = { underline = true },
["@text.strike"] = { strikethrough = true },
["@text.title"] = { fg = p.deep_lavender },
["@text.literal"] = { fg = p.lavender },
["@text.quote"] = { fg = p.fg_muted },
["@text.note"] = { fg = p.lavender },
["@text.warning"] = { fg = p.gold },
["@text.danger"] = { fg = p.coral },
["@text.diff.add"] = { fg = p.teal },
["@text.diff.delete"] = { fg = p.coral },
["@markup.heading"] = { fg = p.deep_lavender },
["@markup.heading.1"] = { fg = p.coral },
["@markup.heading.2"] = { fg = p.gold },
["@markup.heading.3"] = { fg = p.teal },
["@markup.heading.4"] = { fg = p.lavender },
["@markup.heading.5"] = { fg = p.deep_lavender },
["@markup.heading.6"] = { fg = p.lavender },
["@markup.list"] = { fg = p.fg_bright },
["@markup.list.checked"] = { fg = p.teal },
["@markup.list.unchecked"] = { fg = p.fg_muted },
["@markup.link"] = { fg = p.lavender, underline = true },
["@markup.link.url"] = { fg = p.lavender, underline = true },
["@markup.link.label"] = { fg = p.fg_bright },
["@markup.raw"] = { fg = p.fg_bright },
["@markup.raw.block"] = { fg = p.fg_bright },
["@markup.code"] = { fg = p.fg_bright },
["@markup.math"] = { fg = p.cyan },
["@markup.environment"] = { fg = p.fg_bright },
["@markup.environment.name"] = { fg = p.teal },
["@diff.plus"] = { fg = p.teal },
["@diff.minus"] = { fg = p.coral },
["@diff.delta"] = { fg = p.gold },
["@none"] = {},
}
end
return { get = get }
+56
View File
@@ -0,0 +1,56 @@
local M = {}
local did_setup = false
function M.setup(opts)
require("lavender-dimmed.config").setup(opts)
did_setup = true
end
function M.load()
if not did_setup then
M.setup()
end
local config = require("lavender-dimmed.config")
local palette = require("lavender-dimmed.palette").load()
local groups = {}
local group_modules = { "editor", "syntax", "treesitter", "lsp" }
for _, name in ipairs(group_modules) do
local g = require("lavender-dimmed.groups." .. name).get(palette, config.options)
for k, v in pairs(g) do
groups[k] = v
end
end
for group_name, group_opts in pairs(groups) do
vim.api.nvim_set_hl(0, group_name, group_opts)
end
local term_colors = {
"#282c34",
"#d47373",
"#7ec8c0",
"#d4c87a",
"#b39cd0",
"#a088c0",
"#76e3ea",
"#cdd9e5",
"#373e47",
"#e08585",
"#8dd8d0",
"#ddd491",
"#c8b8e0",
"#b39cd0",
"#b3f0ff",
"#e0e4e8",
}
for i, color in ipairs(term_colors) do
vim.g["terminal_color_" .. (i - 1)] = color
end
end
return M
+47
View File
@@ -0,0 +1,47 @@
local Color = {}
Color.__index = Color
function Color.new(hex)
local self = setmetatable({}, Color)
hex = hex:gsub("^#", "")
self.r = tonumber(hex:sub(1, 2), 16)
self.g = tonumber(hex:sub(3, 4), 16)
self.b = tonumber(hex:sub(5, 6), 16)
return self
end
function Color:to_css()
return string.format("#%02x%02x%02x", self.r, self.g, self.b)
end
function Color:blend(other, factor)
other = type(other) == "string" and Color.new(other) or other
return Color.new(
string.format(
"#%02x%02x%02x",
math.floor(self.r + (other.r - self.r) * factor + 0.5),
math.floor(self.g + (other.g - self.g) * factor + 0.5),
math.floor(self.b + (other.b - self.b) * factor + 0.5)
)
)
end
function Color:darken(amount)
return self:blend("#000000", amount)
end
function Color:lighten(amount)
return self:blend("#ffffff", amount)
end
function Color:saturate(factor)
local gray = math.floor(0.299 * self.r + 0.587 * self.g + 0.114 * self.b + 0.5)
local gray_color = Color.new(string.format("#%02x%02x%02x", gray, gray, gray))
return self:blend(gray_color, 1 - factor)
end
return setmetatable(Color, {
__call = function(_, hex)
return Color.new(hex)
end,
})
+52
View File
@@ -0,0 +1,52 @@
local M = {}
function M.load()
return {
terminal_bg = "#282c34",
bg_dark = "#1c2128",
bg_dimmer = "#22272e",
bg = "#282c34",
bg_highlight = "#2d333b",
bg_visual = "#373e47",
bg_border = "#444c56",
fg_subtle = "#545d68",
fg_muted2 = "#636e7b",
fg_muted = "#768390",
fg_dim = "#909dab",
fg = "#adbac7",
fg_bright = "#cdd9e5",
fg_white = "#e0e4e8",
lavender = "#b39cd0",
deep_lavender = "#a088c0",
bright_lavender = "#c8b8e0",
teal = "#7ec8c0",
bright_teal = "#8dd8d0",
gold = "#d4c87a",
bright_gold = "#ddd491",
coral = "#d47373",
bright_coral = "#e08585",
orange = "#cc6b2c",
cyan = "#76e3ea",
bright_cyan = "#b3f0ff",
pink = "#c96198",
purple = "#986ee2",
accent_muted = "#605972",
accent_subtle = "#3d3d4b",
success_muted = "#4a6a6c",
success_subtle = "#354349",
danger_muted = "#6d484d",
danger_subtle = "#42373d",
attention_muted = "#6d6a50",
attention_subtle = "#42433f",
}
end
return M