diff --git a/CHANGELOG.md b/CHANGELOG.md index 53af00e2..b48a8335 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,14 +31,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `sidebars`-> `options.darken.sidebars.list` - `colors`-> `palettes` or `specs` - `overrides` -> `groups` +- `dev` -> `vim.g.github_theme_debug` ### New Configuration +- `options.compile_file_suffix` -> Option for setting compiled file suffix. +- `options.compile_path` -> Option for setting compile files path. +- `options.terminal_colors` -> Option for toggling builtin terminal highlights. - `options.module_default` -> Option for toggling plugins highlights - `options.modules` -> Option for individual plugins related configuration ### What's New? +- Compiling colorscheme for blazingly fast load. - `lib.deprecation` - A Deprecation library to print Deprecation Messages. - `lib.log` - A logging library to print log Messages. - The `config.default` module has been changed to a variable and moved inside the `config` module. @@ -47,8 +52,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #160 closed due to inactivity. - #191 closed due to inactivity. -- #201 fixed - #193 closed with conversation. +- #201 fixed +- #209 fixed - #213 fixed - #228 fixed - #231 fixed diff --git a/colors/github_dark.vim b/colors/github_dark.vim index bf072bdf..931c442c 100644 --- a/colors/github_dark.vim +++ b/colors/github_dark.vim @@ -1,5 +1,8 @@ lua << EOF +if vim.g.github_theme_debug then + require("github-theme.util.reload")() +end require("github-theme.config").set_theme('github_dark') require("github-theme").load() diff --git a/colors/github_dark_colorblind.vim b/colors/github_dark_colorblind.vim index 915295b0..7b567bc8 100644 --- a/colors/github_dark_colorblind.vim +++ b/colors/github_dark_colorblind.vim @@ -1,5 +1,8 @@ lua << EOF +if vim.g.github_theme_debug then + require("github-theme.util.reload")() +end require("github-theme.config").set_theme('github_dark_colorblind') require("github-theme").load() diff --git a/colors/github_dark_dimmed.vim b/colors/github_dark_dimmed.vim index b894125f..50b85250 100644 --- a/colors/github_dark_dimmed.vim +++ b/colors/github_dark_dimmed.vim @@ -1,5 +1,8 @@ lua << EOF +if vim.g.github_theme_debug then + require("github-theme.util.reload")() +end require('github-theme.config').set_theme('github_dark_dimmed') require('github-theme').load() diff --git a/colors/github_dark_high_contrast.vim b/colors/github_dark_high_contrast.vim index 5feb781c..e970c42a 100644 --- a/colors/github_dark_high_contrast.vim +++ b/colors/github_dark_high_contrast.vim @@ -1,5 +1,8 @@ lua << EOF +if vim.g.github_theme_debug then + require("github-theme.util.reload")() +end require('github-theme.config').set_theme('github_dark_high_contrast') require('github-theme').load() diff --git a/colors/github_dark_tritanopia.vim b/colors/github_dark_tritanopia.vim index 94697f32..b3787d6b 100644 --- a/colors/github_dark_tritanopia.vim +++ b/colors/github_dark_tritanopia.vim @@ -1,5 +1,8 @@ lua << EOF +if vim.g.github_theme_debug then + require("github-theme.util.reload")() +end require('github-theme.config').set_theme('github_dark_tritanopia') require('github-theme').load() diff --git a/colors/github_light.vim b/colors/github_light.vim index 54359fa2..8ca9bf5a 100644 --- a/colors/github_light.vim +++ b/colors/github_light.vim @@ -1,5 +1,8 @@ lua << EOF +if vim.g.github_theme_debug then + require("github-theme.util.reload")() +end require("github-theme.config").set_theme('github_light') require("github-theme").load() diff --git a/colors/github_light_colorblind.vim b/colors/github_light_colorblind.vim index f03c066e..7e0e3d5d 100644 --- a/colors/github_light_colorblind.vim +++ b/colors/github_light_colorblind.vim @@ -1,5 +1,8 @@ lua << EOF +if vim.g.github_theme_debug then + require("github-theme.util.reload")() +end require("github-theme.config").set_theme('github_light_colorblind') require("github-theme").load() diff --git a/colors/github_light_high_contrast.vim b/colors/github_light_high_contrast.vim index 05fc2221..91b9fe19 100644 --- a/colors/github_light_high_contrast.vim +++ b/colors/github_light_high_contrast.vim @@ -1,5 +1,8 @@ lua << EOF +if vim.g.github_theme_debug then + require("github-theme.util.reload")() +end require('github-theme.config').set_theme('github_light_high_contrast') require('github-theme').load() diff --git a/colors/github_light_tritanopia.vim b/colors/github_light_tritanopia.vim index a514d448..75c6dd0b 100644 --- a/colors/github_light_tritanopia.vim +++ b/colors/github_light_tritanopia.vim @@ -1,5 +1,8 @@ lua << EOF +if vim.g.github_theme_debug then + require("github-theme.util.reload")() +end require('github-theme.config').set_theme('github_light_tritanopia') require('github-theme').load() diff --git a/doc/gt_changelog.txt b/doc/gt_changelog.txt index 1cb2f3d5..74690495 100644 --- a/doc/gt_changelog.txt +++ b/doc/gt_changelog.txt @@ -3,6 +3,22 @@ # Changelog + + *github-theme.changelog-06052023* +Date: May 06, 2023 + +I(ful1e5) removed the `dev` configuration from `setup({...})` and added the +`vim.g.github_theme_debug` Vim global option for theme debugging. This option +creates a Lua file in the Neovim cache directory and write debugging logs to +it. + +Previously, the `dev` option was used for debugging and assigning new +highlights to the theme, or for overriding defined highlights. Now, with the +removal of the `dev` option, you can override any highlight without enabling +any option. + + + *github-theme.changelog-23042023* Date: April 23, 2023 diff --git a/doc/gt_deprecated.txt b/doc/gt_deprecated.txt index f0542d8b..4cb133b8 100644 --- a/doc/gt_deprecated.txt +++ b/doc/gt_deprecated.txt @@ -33,6 +33,7 @@ SETUP OPTIONS - *'sidebars'* Deprecated. Use |'options.darken.sidebars.list'| Instead. - *'colors'* Deprecated. Use |'specs'| and |'palettes'| Instead. - *'overrides'* Deprecated. Use |'groups'| Instead. +- *'dev'* Deprecated. Use |'vim.g.github_theme_dev'| Instead. GLOBAL OPTIONS @@ -50,7 +51,7 @@ GLOBAL OPTIONS - *'vim.g.github_function_style'* Use |setup| Lua function instead. - *'vim.g.github_keyword_style'* Use |setup| Lua function instead. - *'vim.g.github_variable_style'* Use |setup| Lua function instead. -- *'vim.g.github_dev'* Use |setup| Lua function instead. +- *'vim.g.github_dev'* Use |vim.g.github_theme_debug| instead. MODULES diff --git a/lua/github-theme/config.lua b/lua/github-theme/config.lua index 7e23dc3e..38fd9cfd 100644 --- a/lua/github-theme/config.lua +++ b/lua/github-theme/config.lua @@ -1,13 +1,15 @@ local collect = require('github-theme.lib.collect') local util = require('github-theme.util') -local M = { theme = 'github_dark', has_options = true } +local M = { theme = 'github_dark', has_options = false } local defaults = { - dev = false, - transparent = false, + compile_file_suffix = '_compiled', + compile_path = util.join_paths(util.cache_home, 'github-theme'), hide_end_of_buffer = true, hide_nc_statusline = true, + terminal_colors = true, + transparent = false, module_default = true, styles = { comments = 'italic', @@ -85,4 +87,16 @@ function M.reset() M.options = collect.deep_copy(defaults) end +function M.get_compiled_info(opts) + local output_path = opts.output_path or M.options.compile_path + local file_suffix = opts.file_suffix or M.options.compile_file_suffix + local style = opts.name or M.theme + return output_path, util.join_paths(output_path, style .. file_suffix) +end + +function M.hash() + local hash = require('github-theme.lib.hash')(M.options) + return hash and hash or 0 +end + return M diff --git a/lua/github-theme/init.lua b/lua/github-theme/init.lua index 75103910..d1fd1887 100644 --- a/lua/github-theme/init.lua +++ b/lua/github-theme/init.lua @@ -1,19 +1,44 @@ -local M = {} - local config = require('github-theme.config') -local highlight = require('github-theme.lib.highlight').highlight -local dep = require('github-theme.util.deprecation') -local did_setup = false +local function read_file(filepath) + local file = io.open(filepath, 'r') + if file then + local content = file:read() + file:close() + return content + end +end + +local function write_file(filepath, content) + local file = io.open(filepath, 'wb') + if file then + file:write(content) + file:close() + end +end + +local M = {} function M.reset() require('github-theme.config').reset() + require('github-theme.override').reset() +end + +function M.compile() + require('github-theme.lib.log').clear() + + local compiler = require('github-theme.lib.compiler') + local themes = require('github-theme.palette').themes + for _, style in ipairs(themes) do + compiler.compile({ style = style }) + end end -- Avoid g:colors_name reloading local lock = false +local did_setup = false -M.load = function(opts) +function M.load(opts) if lock then return end @@ -22,21 +47,19 @@ M.load = function(opts) M.setup() end - lock = true + opts = opts or {} - local spec = require('github-theme.spec').load(config.theme) - local groups = require('github-theme.group').from(spec) - local background = spec.palette.meta.light and 'light' or 'dark' + local _, compiled_file = config.get_compiled_info(opts) + lock = true - if vim.g.colors_name then - vim.cmd('hi clear') + local f = loadfile(compiled_file) + if not f then + M.compile() + f = loadfile(compiled_file) end - vim.o.termguicolors = true - vim.g.colors_name = config.theme - vim.o.background = background - highlight(groups) - require('github-theme.autocmds').set() + ---@diagnostic disable-next-line: need-check-nil + f() lock = false end @@ -47,12 +70,6 @@ M.setup = function(opts) local override = require('github-theme.override') - -- TODO: Remove these individual conditions when migration - -- from old config to 'opts.options' has been DONE. - if opts.dev then - config.set_options({ dev = opts.dev }) - end - -- New configs if opts.options then config.set_options(opts.options) @@ -70,7 +87,22 @@ M.setup = function(opts) override.groups = opts.groups end - dep.check_deprecation(opts) + local util = require('github-theme.util') + util.ensure_dir(config.options.compile_path) + + local cached_path = util.join_paths(config.options.compile_path, 'cache') + local cached = read_file(cached_path) + + local git_path = util.join_paths(debug.getinfo(1).source:sub(2, -23), '.git') + local git = vim.fn.getftime(git_path) + local hash = require('github-theme.lib.hash')(opts) .. (git == -1 and git_path or git) + + if cached ~= hash then + M.compile() + write_file(cached_path, hash) + end + + require('github-theme.util.deprecation').check_deprecation(opts) end return M diff --git a/lua/github-theme/lib/compiler.lua b/lua/github-theme/lib/compiler.lua new file mode 100644 index 00000000..03d303fc --- /dev/null +++ b/lua/github-theme/lib/compiler.lua @@ -0,0 +1,106 @@ +---@diagnostic disable: need-check-nil + +local config = require('github-theme.config') +local util = require('github-theme.util') +local parse_styles = require('github-theme.lib.highlight').parse_style +local fmt = string.format + +local M = {} + +local function inspect(t) + local list = {} + for k, v in pairs(t) do + local q = type(v) == 'string' and [["]] or '' + table.insert(list, fmt([[%s = %s%s%s]], k, q, v, q)) + end + + table.sort(list) + return fmt([[{ %s }]], table.concat(list, ', ')) +end + +local function should_link(link) + return link and link ~= '' +end + +function M.compile(opts) + opts = opts or {} + local theme = config.theme + local spec = require('github-theme.spec').load(theme) + local groups = require('github-theme.group').from(spec) + local background = spec.palette.meta.light and 'light' or 'dark' + + local lines = { + fmt( + [[ +return string.dump(function() +local h = vim.api.nvim_set_hl +if vim.g.colors_name then vim.cmd("hi clear") end +vim.o.termguicolors = true +vim.g.colors_name = "%s" +vim.o.background = "%s" + ]], + theme, + background + ), + } + + if config.options.terminal_colors then + local terminal = require('github-theme.group.terminal').get(spec) + for k, v in pairs(terminal) do + table.insert(lines, fmt([[vim.g.%s = "%s"]], k, v)) + end + end + + for name, values in pairs(groups) do + if should_link(values.link) then + table.insert(lines, fmt([[h(0, "%s", { link = "%s" })]], name, values.link)) + else + local op = parse_styles(values.style) + op.bg = values.bg + op.fg = values.fg + op.sp = values.sp + table.insert(lines, fmt([[h(0, "%s", %s)]], name, inspect(op))) + end + end + + table.insert(lines, 'end)') + + opts.name = theme + local output_path, output_file = config.get_compiled_info(opts) + util.ensure_dir(output_path) + + local file + if vim.g.github_theme_debug then + file = io.open(output_file .. '.lua', 'wb') + file:write(table.concat(lines, '\n')) + file:close() + end + + file = io.open(output_file, 'wb') + + local f = loadstring(table.concat(lines, '\n'), '=') + if not f then + local tmpfile = util.join_paths(util.get_tmp_dir(), 'github_theme_error.lua') + require('github-theme.lib.log').error( + fmt( + [[There is an error in your github-theme config. +You can open '%s' for debugging. + +If you think this is a bug, kindly open an issue and attach '%s' file. +Bellow is the error message: +]], + tmpfile, + tmpfile + ) + ) + local efile = io.open(tmpfile, 'wb') + efile:write(table.concat(lines, '\n')) + efile:close() + dofile(tmpfile) + end + + file:write(f()) + file:close() +end + +return M diff --git a/lua/github-theme/lib/hash.lua b/lua/github-theme/lib/hash.lua new file mode 100644 index 00000000..2115db1e --- /dev/null +++ b/lua/github-theme/lib/hash.lua @@ -0,0 +1,27 @@ +local bitop = bit or bit32 or require('github-theme.lib.native_bit') + +-- https://theartincode.stanis.me/008-djb2/ +local function djb2(s) + local h = 5381 + for i = 1, #s do + h = bitop.lshift(h, 5) + h + string.byte(s, i) -- h * 33 + c + end + return h +end + +-- Reference: https://github.com/catppuccin/nvim/blob/bad9c23f12944683cd11484d9570560849efc101/lua/catppuccin/lib/hashing.lua +local function hash(x) + local t = type(x) + if t == 'table' then + local h = 0 + for k, v in next, x do + h = bitop.bxor(h, djb2(k .. hash(v))) + end + return h + elseif t == 'function' then + return djb2(string.dump(x)) + end + return tostring(x) +end + +return hash diff --git a/lua/github-theme/lib/log.lua b/lua/github-theme/lib/log.lua index e8aa19da..248ac34a 100644 --- a/lua/github-theme/lib/log.lua +++ b/lua/github-theme/lib/log.lua @@ -27,7 +27,7 @@ function M.notify(msg, level) local buf = vim.api.nvim_win_get_buf(win) vim.bo[buf].filetype = 'markdown' end, - title = 'nightfox.nvim', + title = 'github-theme', }) notified[msg] = true diff --git a/lua/github-theme/lib/native_bit.lua b/lua/github-theme/lib/native_bit.lua new file mode 100644 index 00000000..4f917335 --- /dev/null +++ b/lua/github-theme/lib/native_bit.lua @@ -0,0 +1,130 @@ +-- Reference(stripped down): https://github.com/davidm/lua-bit-numberlua/blob/master/lmod/bit/numberlua.lua + +local floor = math.floor + +local MOD = 2 ^ 32 +local MODM = MOD - 1 + +local function memoize(f) + local mt = {} + local t = setmetatable({}, mt) + function mt:__index(k) + local v = f(k) + t[k] = v + return v + end + return t +end + +local function make_bitop_uncached(t, m) + local function bitop(a, b) + local res, p = 0, 1 + while a ~= 0 and b ~= 0 do + local am, bm = a % m, b % m + res = res + t[am][bm] * p + a = (a - am) / m + b = (b - bm) / m + p = p * m + end + res = res + (a + b) * p + return res + end + return bitop +end + +local function make_bitop(t) + local op1 = make_bitop_uncached(t, 2 ^ 1) + local op2 = memoize(function(a) + return memoize(function(b) + return op1(a, b) + end) + end) + return make_bitop_uncached(op2, 2 ^ (t.n or 1)) +end + +local bxor = make_bitop({ [0] = { [0] = 0, [1] = 1 }, [1] = { [0] = 1, [1] = 0 }, n = 4 }) + +local function bnot(a) + return MODM - a +end + +local function band(a, b) + return ((a + b) - bxor(a, b)) / 2 +end + +local function bor(a, b) + return MODM - band(MODM - a, MODM - b) +end + +local lshift, rshift -- forward declare + +rshift = function(a, disp) -- Lua5.2 insipred + if disp < 0 then + return lshift(a, -disp) + end + return floor(a % 2 ^ 32 / 2 ^ disp) +end + +lshift = function(a, disp) -- Lua5.2 inspired + if disp < 0 then + return rshift(a, -disp) + end + return (a * 2 ^ disp) % 2 ^ 32 +end + +local function bit_tobit(x) + x = x % MOD + if x >= 0x80000000 then + x = x - MOD + end + return x +end + +local function bit_not(x) + return bit_tobit(bnot(x % MOD)) +end + +local function bit_bor(a, b, c, ...) + if c then + return bit_bor(bit_bor(a, b), c, ...) + elseif b then + return bit_tobit(bor(a % MOD, b % MOD)) + else + return bit_tobit(a) + end +end + +local function bit_band(a, b, c, ...) + if c then + return bit_band(bit_band(a, b), c, ...) + elseif b then + return bit_tobit(band(a % MOD, b % MOD)) + else + return bit_tobit(a) + end +end + +local function bit_bxor(a, b, c, ...) + if c then + return bit_bxor(bit_bxor(a, b), c, ...) + elseif b then + return bit_tobit(bxor(a % MOD, b % MOD)) + else + return bit_tobit(a) + end +end + +return { + lshift = function(x, n) + return bit_tobit(lshift(x % MOD, n % 32)) + end, + + rshift = function(x, n) + return bit_tobit(rshift(x % MOD, n % 32)) + end, + + bnot = bit_not, + band = bit_band, + bor = bit_bor, + bxor = bit_bxor, +} diff --git a/lua/github-theme/util/deprecation.lua b/lua/github-theme/util/deprecation.lua index 0edc1cc2..6365c08e 100644 --- a/lua/github-theme/util/deprecation.lua +++ b/lua/github-theme/util/deprecation.lua @@ -67,7 +67,7 @@ M.check_deprecation = function(opts) dep.write( ' ', { name, 'WarningMsg' }, - ' has been replaced by ', + ' config has been replaced by ', { replace, 'WarningMsg' }, '. See ', { ':h ' .. help, 'WarningMsg' }, @@ -123,10 +123,14 @@ M.check_deprecation = function(opts) replace = 'options.darken.sidebars.enable', help = 'github-theme.changelog-13042023', }) - check_opt( - 'sidebars', - { replace = 'options.darken.sidebars.list', help = 'github-theme.changelog-13042023' } - ) + check_opt('sidebars', { + replace = 'options.darken.sidebars.list', + help = 'github-theme.changelog-13042023', + }) + check_opt('dev', { + replace = 'vim.g.github_theme_debug', + help = 'github-theme.changelog-06052023', + }) if opts.colors then dep.write( diff --git a/lua/github-theme/util/reload.lua b/lua/github-theme/util/reload.lua new file mode 100644 index 00000000..df496a59 --- /dev/null +++ b/lua/github-theme/util/reload.lua @@ -0,0 +1,19 @@ +local function reload() + for name, _ in pairs(package.loaded) do + if name:match('^github-theme') then + if + not name:match('config') + and not name:match('deprecation') + and not name:match('override') + then + package.loaded[name] = nil + end + end + end +end + +return setmetatable({}, { + __call = function(_) + reload() + end, +})