1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
--
-- Color scheme, custom highlights & per-window highlight namespaces
--
local solarized_colors = {
base03 = "#002b36",
base02 = "#073642",
base01 = "#586e75",
base00 = "#657b83",
base0 = "#839496",
base1 = "#93a1a1",
base2 = "#eee8d5",
base3 = "#fdf6e3",
yellow = "#b58900",
orange = "#cb4b16",
red = "#dc322f",
magenta = "#d33682",
violet = "#6c71c4",
blue = "#268bd2",
cyan = "#2aa198",
green = "#859900",
-- solarized.nvim "mix" tints: subtle highlight backgrounds, theme-specific
mix_base1 = "#2c4e56", -- dark (active cursor line)
mix_blue_light = "#e7ebe1", -- light (active cursor line)
mix_green = "#274c25", -- dark (inactive cursor line: muted green)
mix_magenta_light = "#f8e2d9", -- light (inactive cursor line: muted pink)
}
-- Per-window highlight namespaces: one for the focused window, one for the
-- unfocused windows. A window's active namespace decides its CursorLine color,
-- which is how the focused window is made obvious. Both namespaces must define
-- `dotfiles.Todo`: an extmark's hl_group is resolved against the window's
-- active namespace and does NOT fall back to the global namespace, so the TODO
-- highlight (placed in 50-extmarks.lua) only renders if the group exists in
-- whichever namespace the window currently uses.
local ns_active = vim.api.nvim_create_namespace("extmarks")
local ns_inactive = vim.api.nvim_create_namespace("extmarks.inactive")
local todo_hl = { bg = "Yellow", fg = "Black", bold = true }
vim.api.nvim_set_hl(ns_active, "dotfiles.Todo", todo_hl)
vim.api.nvim_set_hl(ns_inactive, "dotfiles.Todo", todo_hl)
-- Publish the extmark storage namespace and TODO group name for 50-extmarks.lua.
-- This file is named 40- (not 50-) so it is sourced before 50-extmarks.lua and
-- the contract below exists when that file reads it. Preserve the existing
-- `dotfiles` table (augroup).
local dotfiles = vim.g.dotfiles
dotfiles.todo_ns = ns_active
dotfiles.todo_hl = "dotfiles.Todo"
vim.g.dotfiles = dotfiles
-- Custom highlights in the global namespace, independent of the per-window ones
local function adjust_highlight()
if vim.g.colors_name == "solarized" then
vim.api.nvim_set_hl(0, "EndOfBuffer", { fg = solarized_colors.base0, update = true })
vim.api.nvim_set_hl(0, "MatchParen", { link = "CurSearch" })
vim.api.nvim_set_hl(0, "WinBarCwd", { fg = solarized_colors.blue, italic = true })
vim.api.nvim_set_hl(0, "WinBarFile", { italic = true })
vim.api.nvim_set_hl(0, "TabLine", { fg = solarized_colors.yellow, bold = true })
if vim.o.background == "light" then
vim.api.nvim_set_hl(0, "TabLineSel", { bg = "#edffd5", fg = solarized_colors.yellow, bold = true })
vim.api.nvim_set_hl(0, "Cursorline", { bg = "#edffd5" })
elseif vim.o.background == "dark" then
vim.api.nvim_set_hl(0, "TabLineSel", { bg = "#043624" })
vim.api.nvim_set_hl(0, "Cursorline", { bg = "#043624" })
end
end
end
-- Theme-aware cursor line, one focus hue (green on dark, magenta/pink on light)
-- at two intensities. CursorLineNr stays visible on closed folds (the number
-- column is NOT painted by Folded), so it carries the focus cue: active window
-- a muted "mix" of the hue, unfocused windows a bright bold badge of the same
-- hue. The cursor-line background backs this up: active a subtle neutral "mix"
-- tint (light enough to edit on, distinct from Folded), unfocused the muted
-- hue wash.
local function set_cursorline_hl()
local active, muted, badge
if vim.o.background == "light" then
active, muted = solarized_colors.mix_blue_light, solarized_colors.mix_magenta_light
badge = { bg = solarized_colors.magenta, fg = solarized_colors.base3, bold = true }
else
active, muted = solarized_colors.mix_base1, solarized_colors.mix_green
badge = { bg = solarized_colors.green, fg = solarized_colors.base03, bold = true }
end
vim.api.nvim_set_hl(ns_active, "CursorLine", { bg = active })
vim.api.nvim_set_hl(ns_active, "CursorLineNr", { bg = muted })
vim.api.nvim_set_hl(ns_inactive, "CursorLine", { bg = muted })
vim.api.nvim_set_hl(ns_inactive, "CursorLineNr", badge)
end
local function apply_highlights()
adjust_highlight()
set_cursorline_hl()
end
-- Single owner of every window's highlight namespace: the focused window gets
-- `ns_active`, all others `ns_inactive`. Reapplied to every window on each
-- focus change because WinLeave alone misses windows that existed at startup
-- or were restored from a session.
local function is_normal_win(win)
return vim.api.nvim_win_is_valid(win) and vim.api.nvim_win_get_config(win).relative == ""
end
local function update_focus_ns()
local cur = vim.api.nvim_get_current_win()
-- Focus in a floating window (completion, hover, ...) must not recolor the
-- split underneath; leave every window as it is.
if not is_normal_win(cur) then
return
end
for _, win in ipairs(vim.api.nvim_list_wins()) do
if is_normal_win(win) then
vim.api.nvim_win_set_hl_ns(win, (win == cur) and ns_active or ns_inactive)
end
end
end
-- Note: a closed fold's screen line is always drawn with `Folded` (see
-- `:help fold.txt` / hl-Folded); Neovim has no per-line override, so the
-- unfocused cursor line is not visible when it sits on a closed fold. This is
-- standard behavior (cursorline never renders on closed folds in any window)
-- and is accepted as-is.
local function next_colorscheme()
local colorschemes = vim.fn.getcompletion("", "color")
vim.g.colors_name = vim.g.colors_name or "default"
for i = 1, #colorschemes do
if colorschemes[i] == vim.g.colors_name then
vim.cmd.colorscheme(colorschemes[(i % #colorschemes) + 1])
vim.notify("Color scheme set to " .. vim.g.colors_name)
return
end
end
end
local function random_colorscheme()
local colorschemes = vim.fn.getcompletion("", "color")
vim.cmd.colorscheme(colorschemes[math.random(#colorschemes)])
vim.notify("Color scheme set to " .. vim.g.colors_name)
end
local function toggle_theme()
vim.opt.background = vim.o.background == "light" and "dark" or "light"
vim.notify("Color theme set to " .. vim.o.background)
end
-- Reapply custom highlights after the colorscheme loads and on theme change
vim.api.nvim_create_autocmd("ColorScheme", {
desc = "Reapply custom highlights",
group = vim.g.dotfiles.augroup,
callback = apply_highlights,
})
vim.api.nvim_create_autocmd("OptionSet", {
desc = "Reapply custom highlights on theme change",
pattern = "background",
group = vim.g.dotfiles.augroup,
callback = apply_highlights,
})
-- Keep the focused/unfocused cursor line correct as windows and focus change
vim.api.nvim_create_autocmd(
{ "VimEnter", "WinEnter", "WinNew", "WinClosed", "TabEnter", "SessionLoadPost", "FileType" },
{
desc = "Track the focused window for the cursor line",
group = vim.g.dotfiles.augroup,
callback = function()
-- Defer so the window list and current window have settled.
vim.schedule(update_focus_ns)
end,
}
)
vim.cmd.colorscheme("solarized") -- Default colorscheme
vim.opt.background = "dark" -- Default theme
apply_highlights()
vim.api.nvim_create_user_command("ColorsNext", next_colorscheme, { desc = "Load next color scheme" })
vim.api.nvim_create_user_command("ColorsRandom", random_colorscheme, { desc = "Load random color scheme" })
vim.api.nvim_create_user_command("ColorsThemeToggle", toggle_theme, { desc = "Toggle light/dark theme" })
|