11local M = {}
22
3- -- Helper to extract color from a highlight group
4- local function get_hl_color (hl_name , attr )
5- local hl = vim .api .nvim_get_hl (0 , { name = hl_name , link = false })
6- if hl and hl [attr ] then
3+ local function get_hl (name , attr )
4+ local ok , hl = pcall (vim .api .nvim_get_hl , 0 , { name = name , link = false })
5+ if ok and hl [attr ] then
76 return string.format (" #%06x" , hl [attr ])
87 end
9- return nil
108end
119
12- -- Helper to get foreground color with fallbacks
13- local function get_fg (primary , fallbacks )
14- local color = get_hl_color (primary , " fg" )
15- if color then
16- return color
17- end
18-
19- -- Try fallbacks
20- for _ , fb in ipairs (fallbacks or {}) do
21- color = get_hl_color (fb , " fg" )
22- if color then
23- return color
24- end
25- end
26-
27- -- Ultimate fallback based on background
28- return vim .o .background == " dark" and " #ffffff" or " #000000"
29- end
30-
31- -- Helper to get background color with fallbacks
32- local function get_bg (primary , fallbacks )
33- local color = get_hl_color (primary , " bg" )
34- if color then
35- return color
36- end
37-
38- -- Try fallbacks
39- for _ , fb in ipairs (fallbacks or {}) do
40- color = get_hl_color (fb , " bg" )
41- if color then
42- return color
10+ local function first_valid (...)
11+ for _ , val in ipairs ({ ... }) do
12+ if val then
13+ return val
4314 end
4415 end
45-
46- return " NONE"
4716end
4817
49- -- Extract colors from current colorscheme
5018function M .get_colors ()
51- -- Try to intelligently extract colors from existing highlight groups
52- -- This works with ANY colorscheme (Catppuccin, Gruvbox, Tokyo Night, Nord, etc.)
19+ local is_dark = vim .o .background == " dark"
5320
5421 return {
55- -- Semantic colors from common highlight groups
56- green = get_fg (" String" , { " Function" , " Keyword" , " Type" }),
57- red = get_fg (" Error" , { " ErrorMsg" , " DiagnosticError" , " DiffDelete" }),
58- yellow = get_fg (" Warning" , { " WarningMsg" , " DiagnosticWarn" , " Number" }),
59- blue = get_fg (" Function" , { " Identifier" , " Statement" , " Type" }),
60- cyan = get_fg (" Special" , { " Constant" , " Type" , " Identifier" }),
61- magenta = get_fg (" Keyword" , { " Statement" , " Constant" , " PreProc" }),
62-
63- -- UI colors
64- comment = get_fg (" Comment" , { " NonText" , " LineNr" }),
65- linenr = get_fg (" LineNr" , { " Comment" , " NonText" }),
66- normal = get_fg (" Normal" , {}),
67-
68- -- Tab colors
69- active_fg = get_fg (" TabLineSel" , { " Title" , " Function" , " Identifier" }),
70- active_bg = get_bg (" TabLineSel" , { " Normal" }),
71- inactive_fg = get_fg (" TabLine" , { " Comment" , " LineNr" }),
72- inactive_bg = get_bg (" TabLine" , { " Normal" }),
73-
74- -- Progress bar colors
75- progress_filled = get_fg (" Function" , { " Identifier" , " Type" }),
76- progress_empty = get_fg (" LineNr" , { " Comment" , " NonText" }),
77-
78- -- Language bar color
79- lang_bar = get_fg (" String" , { " Function" , " Type" }),
80-
81- -- Footer color
82- footer = get_fg (" Comment" , { " LineNr" , " NonText" }),
83-
84- -- Activity heatmap (GitHub-style intensity levels)
85- -- Use green shades with increasing intensity
86- activity_none = get_fg (" LineNr" , { " Comment" }), -- Very dim
87- activity_low = get_fg (" Comment" , { " LineNr" }), -- Dim
88- activity_med = get_fg (" String" , { " Function" }), -- Medium
89- activity_high = get_fg (" Function" , { " String" , " Type" }), -- Bright
22+ green = first_valid (
23+ get_hl (" @string" , " fg" ),
24+ get_hl (" String" , " fg" ),
25+ get_hl (" @function" , " fg" ),
26+ get_hl (" Function" , " fg" ),
27+ is_dark and " #a6e3a1" or " #40a02b"
28+ ),
29+
30+ red = first_valid (
31+ get_hl (" Error" , " fg" ),
32+ get_hl (" ErrorMsg" , " fg" ),
33+ get_hl (" @keyword" , " fg" ),
34+ get_hl (" DiagnosticError" , " fg" ),
35+ is_dark and " #f38ba8" or " #d20f39"
36+ ),
37+
38+ yellow = first_valid (
39+ get_hl (" @number" , " fg" ),
40+ get_hl (" Number" , " fg" ),
41+ get_hl (" WarningMsg" , " fg" ),
42+ get_hl (" @constant" , " fg" ),
43+ is_dark and " #f9e2af" or " #df8e1d"
44+ ),
45+
46+ blue = first_valid (
47+ get_hl (" @function" , " fg" ),
48+ get_hl (" Function" , " fg" ),
49+ get_hl (" Identifier" , " fg" ),
50+ get_hl (" @type" , " fg" ),
51+ is_dark and " #89b4fa" or " #1e66f5"
52+ ),
53+
54+ cyan = first_valid (
55+ get_hl (" @property" , " fg" ),
56+ get_hl (" Special" , " fg" ),
57+ get_hl (" @constant" , " fg" ),
58+ get_hl (" Constant" , " fg" ),
59+ is_dark and " #94e2d5" or " #179299"
60+ ),
61+
62+ magenta = first_valid (
63+ get_hl (" @keyword" , " fg" ),
64+ get_hl (" Keyword" , " fg" ),
65+ get_hl (" Statement" , " fg" ),
66+ get_hl (" @variable" , " fg" ),
67+ is_dark and " #cba6f7" or " #8839ef"
68+ ),
69+
70+ comment = first_valid (
71+ get_hl (" @comment" , " fg" ),
72+ get_hl (" Comment" , " fg" ),
73+ get_hl (" NonText" , " fg" ),
74+ is_dark and " #6c7086" or " #9ca0b0"
75+ ),
76+
77+ linenr = first_valid (
78+ get_hl (" LineNr" , " fg" ),
79+ get_hl (" @comment" , " fg" ),
80+ get_hl (" Comment" , " fg" ),
81+ is_dark and " #585b70" or " #acb0be"
82+ ),
83+
84+ normal = first_valid (get_hl (" Normal" , " fg" ), is_dark and " #cdd6f4" or " #4c4f69" ),
85+
86+ active_fg = first_valid (
87+ get_hl (" TabLineSel" , " fg" ),
88+ get_hl (" @function" , " fg" ),
89+ get_hl (" Function" , " fg" ),
90+ get_hl (" Title" , " fg" ),
91+ is_dark and " #89b4fa" or " #1e66f5"
92+ ),
93+
94+ active_bg = first_valid (get_hl (" TabLineSel" , " bg" ), get_hl (" CursorLine" , " bg" ), get_hl (" Visual" , " bg" )),
95+
96+ inactive_fg = first_valid (
97+ get_hl (" TabLine" , " fg" ),
98+ get_hl (" @comment" , " fg" ),
99+ get_hl (" Comment" , " fg" ),
100+ is_dark and " #6c7086" or " #9ca0b0"
101+ ),
102+
103+ inactive_bg = first_valid (get_hl (" TabLine" , " bg" ), get_hl (" Normal" , " bg" )),
104+
105+ progress_filled = first_valid (
106+ get_hl (" @function" , " fg" ),
107+ get_hl (" Function" , " fg" ),
108+ get_hl (" Identifier" , " fg" ),
109+ is_dark and " #89b4fa" or " #1e66f5"
110+ ),
111+
112+ progress_empty = first_valid (
113+ get_hl (" LineNr" , " fg" ),
114+ get_hl (" @comment" , " fg" ),
115+ get_hl (" Comment" , " fg" ),
116+ is_dark and " #585b70" or " #acb0be"
117+ ),
118+
119+ lang_bar = first_valid (
120+ get_hl (" @string" , " fg" ),
121+ get_hl (" String" , " fg" ),
122+ get_hl (" Function" , " fg" ),
123+ is_dark and " #a6e3a1" or " #40a02b"
124+ ),
125+
126+ footer = first_valid (
127+ get_hl (" @comment" , " fg" ),
128+ get_hl (" Comment" , " fg" ),
129+ get_hl (" LineNr" , " fg" ),
130+ is_dark and " #6c7086" or " #9ca0b0"
131+ ),
132+
133+ activity_none = first_valid (get_hl (" LineNr" , " fg" ), is_dark and " #45475a" or " #ccd0da" ),
134+
135+ activity_low = first_valid (get_hl (" @comment" , " fg" ), get_hl (" Comment" , " fg" ), is_dark and " #6c7086" or " #9ca0b0" ),
136+
137+ activity_med = first_valid (get_hl (" @string" , " fg" ), get_hl (" String" , " fg" ), is_dark and " #a6e3a1" or " #40a02b" ),
138+
139+ activity_high = first_valid (
140+ get_hl (" @function" , " fg" ),
141+ get_hl (" Function" , " fg" ),
142+ is_dark and " #89b4fa" or " #1e66f5"
143+ ),
90144 }
91145end
92146
93147function M .setup ()
94- local colors = M .get_colors ()
95-
96- -- Main semantic highlights
97- vim .api .nvim_set_hl (0 , " CodeMeGreen" , { fg = colors .green , bold = true })
98- vim .api .nvim_set_hl (0 , " CodeMeRed" , { fg = colors .red , bold = true })
99- vim .api .nvim_set_hl (0 , " CodeMeYellow" , { fg = colors .yellow , bold = true })
100- vim .api .nvim_set_hl (0 , " CodeMeBlue" , { fg = colors .blue , bold = true })
101- vim .api .nvim_set_hl (0 , " CodeMeCyan" , { fg = colors .cyan , bold = true })
102- vim .api .nvim_set_hl (0 , " CodeMeMagenta" , { fg = colors .magenta , bold = true })
103- vim .api .nvim_set_hl (0 , " CodeMeComment" , { fg = colors .comment })
104- vim .api .nvim_set_hl (0 , " CodeMeLineNr" , { fg = colors .linenr })
105-
106- -- Backwards compatibility aliases (old names)
148+ local c = M .get_colors ()
149+
150+ vim .api .nvim_set_hl (0 , " CodeMeGreen" , { fg = c .green , bold = true })
151+ vim .api .nvim_set_hl (0 , " CodeMeRed" , { fg = c .red , bold = true })
152+ vim .api .nvim_set_hl (0 , " CodeMeYellow" , { fg = c .yellow , bold = true })
153+ vim .api .nvim_set_hl (0 , " CodeMeBlue" , { fg = c .blue , bold = true })
154+ vim .api .nvim_set_hl (0 , " CodeMeCyan" , { fg = c .cyan , bold = true })
155+ vim .api .nvim_set_hl (0 , " CodeMeMagenta" , { fg = c .magenta , bold = true })
156+ vim .api .nvim_set_hl (0 , " CodeMeComment" , { fg = c .comment })
157+ vim .api .nvim_set_hl (0 , " CodeMeLineNr" , { fg = c .linenr })
158+ vim .api .nvim_set_hl (0 , " CodeMeTabActive" , { fg = c .active_fg , bg = c .active_bg , bold = true })
159+ vim .api .nvim_set_hl (0 , " CodeMeTabInactive" , { fg = c .inactive_fg , bg = c .inactive_bg })
160+ vim .api .nvim_set_hl (0 , " CodeMeProgressFilled" , { fg = c .progress_filled , bold = true })
161+ vim .api .nvim_set_hl (0 , " CodeMeProgressEmpty" , { fg = c .progress_empty })
162+ vim .api .nvim_set_hl (0 , " CodeMeLangBar" , { fg = c .lang_bar , bold = true })
163+ vim .api .nvim_set_hl (0 , " CodeMeFooter" , { fg = c .footer , italic = true })
164+ vim .api .nvim_set_hl (0 , " CodeMeActivityNone" , { fg = c .activity_none })
165+ vim .api .nvim_set_hl (0 , " CodeMeActivityLow" , { fg = c .activity_low })
166+ vim .api .nvim_set_hl (0 , " CodeMeActivityMed" , { fg = c .activity_med })
167+ vim .api .nvim_set_hl (0 , " CodeMeActivityHigh" , { fg = c .activity_high })
168+
169+ -- Backwards compatibility
107170 vim .api .nvim_set_hl (0 , " exgreen" , { link = " CodeMeGreen" })
108171 vim .api .nvim_set_hl (0 , " exred" , { link = " CodeMeRed" })
109172 vim .api .nvim_set_hl (0 , " exyellow" , { link = " CodeMeYellow" })
@@ -112,57 +175,13 @@ function M.setup()
112175 vim .api .nvim_set_hl (0 , " exmagenta" , { link = " CodeMeMagenta" })
113176 vim .api .nvim_set_hl (0 , " commentfg" , { link = " CodeMeComment" })
114177 vim .api .nvim_set_hl (0 , " linenr" , { link = " CodeMeLineNr" })
115-
116- -- Tab highlights
117- vim .api .nvim_set_hl (0 , " CodeMeTabActive" , {
118- fg = colors .active_fg ,
119- bg = colors .active_bg ,
120- bold = true ,
121- })
122-
123- vim .api .nvim_set_hl (0 , " CodeMeTabInactive" , {
124- fg = colors .inactive_fg ,
125- bg = colors .inactive_bg ,
126- })
127-
128- -- Progress bar highlights
129- vim .api .nvim_set_hl (0 , " CodeMeProgressFilled" , {
130- fg = colors .progress_filled ,
131- bold = true ,
132- })
133-
134- vim .api .nvim_set_hl (0 , " CodeMeProgressEmpty" , {
135- fg = colors .progress_empty ,
136- })
137-
138- -- Language bar highlights
139- vim .api .nvim_set_hl (0 , " CodeMeLangBar" , {
140- fg = colors .lang_bar ,
141- bold = true ,
142- })
143-
144- -- Footer highlights
145- vim .api .nvim_set_hl (0 , " CodeMeFooter" , {
146- fg = colors .footer ,
147- italic = true ,
148- })
149-
150- -- Activity heatmap colors (4 levels)
151- vim .api .nvim_set_hl (0 , " CodeMeActivityNone" , { fg = colors .activity_none })
152- vim .api .nvim_set_hl (0 , " CodeMeActivityLow" , { fg = colors .activity_low })
153- vim .api .nvim_set_hl (0 , " CodeMeActivityMed" , { fg = colors .activity_med })
154- vim .api .nvim_set_hl (0 , " CodeMeActivityHigh" , { fg = colors .activity_high })
155178end
156179
157- -- Auto-reload highlights when colorscheme changes
158180function M .setup_autocmd ()
159181 vim .api .nvim_create_autocmd (" ColorScheme" , {
160182 group = vim .api .nvim_create_augroup (" CodeMeColors" , { clear = true }),
161183 callback = function ()
162- -- Small delay to let colorscheme fully load
163- vim .defer_fn (function ()
164- M .setup ()
165- end , 50 )
184+ vim .defer_fn (M .setup , 50 )
166185 end ,
167186 })
168187end
0 commit comments