From 1ee4044077059b34eacd18d93613495a602c131f Mon Sep 17 00:00:00 2001 From: Alexander van Zyl Date: Tue, 24 Sep 2024 10:54:33 +0200 Subject: [PATCH] Release 0.1.0 (#144) Co-authored-by: Owen Friedman <5-pebble@protonmail.com> Co-authored-by: github-actions[bot] Co-authored-by: Avi Herman <45245854+avih7531@users.noreply.github.com> --- .github/workflows/tests.yml | 4 +- .stylua.toml | 2 +- README.md | 105 ++++++++-- doc/nordic.nvim.txt | 102 +++++++-- lua/lualine/themes/nordic.lua | 2 +- lua/nordic/colors/init.lua | 50 +++-- lua/nordic/colors/nordic.lua | 1 + lua/nordic/compatibility.lua | 48 +++++ lua/nordic/config.lua | 29 ++- lua/nordic/groups/init.lua | 19 +- lua/nordic/groups/integrations.lua | 18 +- lua/nordic/groups/native.lua | 2 +- lua/nordic/groups/terminal.lua | 2 +- lua/nordic/init.lua | 12 +- lua/nordic/tests/init.lua | 11 + lua/nordic/tests/options.lua | 326 +++++++++++++++++++++++++---- lua/nordic/tests/utils.lua | 59 ++++++ lua/nordic/utils.lua | 137 +++++------- 18 files changed, 712 insertions(+), 217 deletions(-) create mode 100644 lua/nordic/compatibility.lua create mode 100644 lua/nordic/tests/init.lua create mode 100644 lua/nordic/tests/utils.lua diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2cdd6bfe..94d8af5f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -45,8 +45,8 @@ jobs: shell: bash run: | nvim --version - OUTPUT=$(nvim --headless -c "lua require 'nordic.tests.options'" -c 'q' 2>&1); + OUTPUT=$(nvim --headless -c "lua require('nordic.tests').run_tests()" -c 'q' 2>&1); if [[ -n "$OUTPUT" ]] then - exit 1 + echo "::error title='Checks failed'::$OUTPUT" && exit 1 fi diff --git a/.stylua.toml b/.stylua.toml index 59b695a7..52592843 100644 --- a/.stylua.toml +++ b/.stylua.toml @@ -3,5 +3,5 @@ line_endings = "Unix" indent_type = "Spaces" indent_width = 4 quote_style = "AutoPreferSingle" -call_parentheses = "None" +call_parentheses = "Always" collapse_simple_statement = "ConditionalOnly" \ No newline at end of file diff --git a/README.md b/README.md index d4664118..17f95b84 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ With [lazy.nvim](https://github.com/folke/lazy.nvim): lazy = false, priority = 1000, config = function() - require 'nordic' .load() + require('nordic').load() end } ``` @@ -57,49 +57,58 @@ colorscheme nordic Using lua: ```lua -vim.cmd.colorscheme 'nordic' +vim.cmd.colorscheme('nordic') -- or -require 'nordic' .load() +require('nordic').load() ``` Using with lualine: ```lua -require 'lualine' .setup { +require('lualine').setup({ options = { theme = 'nordic' } -} +}) ``` -To get the palette in lua: +If you want to use the color palette somewhere else, you can access it with: ```lua -local palette = require 'nordic.colors' +local palette = require('nordic.colors') ``` +> [!WARNING] +> Please make sure that `require('nordic.colors')` is called *after* setup, otherwise the colors might be wrong for your config. # ⚙️ Configuration Nordic will use the default values, unless `setup` is called. Below is the default configuration. ```lua -require 'nordic' .setup { - -- This callback can be used to override the colors used in the palette. - on_palette = function(palette) return palette end, +require('nordic').setup({ + -- This callback can be used to override the colors used in the base palette. + on_palette = function(palette) end, + -- This callback can be used to override the colors used in the extended palette. + after_palette = function(palette) end, + -- This callback can be used to override highlights before they are applied. + on_highlight = function(highlights, palette) end, -- Enable bold keywords. bold_keywords = false, -- Enable italic comments. italic_comments = true, - -- Enable general editor background transparency. - transparent_bg = false, + -- Enable editor background transparency. + transparent = { + -- Enable transparent background. + bg = false, + -- Enable transparent background for floating windows. + float = false, + }, -- Enable brighter float border. bright_border = false, -- Reduce the overall amount of blue in the theme (diverges from base Nord). reduced_blue = true, -- Swap the dark background with the normal one. swap_backgrounds = false, - -- Override the styling of any highlight group. - override = {}, -- Cursorline options. Also includes visual/selection. cursorline = { -- Bold font in cursorline. @@ -127,16 +136,54 @@ require 'nordic' .setup { -- Enables dark background for treesitter-context window dark_background = true, } -} +}) ``` -An example of overriding the `TelescopePromptTitle` colors: +**Examples:** + +
+ on_palette +  + +An example of overriding colors in the base palette: +```lua +require('nordic').setup({ + on_palette = function(palette) + palette.black0 = "#BF616A" + palette.green.base = palette.cyan.base + end, +}) +``` + +
+ + +
+ after_palette +  + +An example of setting the visual selection color (for more values see [this file](https://github.com/AlexvZyl/nordic.nvim/blob/main/lua/nordic/colors/init.lua)): +```lua +require('nordic').setup({ + after_palette = function(palette) + local U = require("nordic.utils") + palette.bg_visual = U.blend(palette.orange.base, palette.bg, 0.15) + end, +}) +``` + +
+ + +
+ on_highlight +  +An example of overriding the `TelescopePromptTitle` colors: ```lua -local palette = require 'nordic.colors' -require 'nordic' .setup { - override = { - TelescopePromptTitle = { +require('nordic').setup({ + on_highlight = function(highlights, palette) + highlights.TelescopePromptTitle = { fg = palette.red.bright, bg = palette.green.base, italic = true, @@ -144,10 +191,24 @@ require 'nordic' .setup { sp = palette.yellow.dim, undercurl = false } - } -} + end, +}) ``` +And an example of disabling all italics: +```lua +require('nordic').setup({ + on_highlight = function(highlights, _palette) + for _, highlight in pairs(highlights) do + highlight.italic = false + end + end +}) +``` + +
+ + # 🗒️ Supported Plugins and Platforms For the list of supported plugins, please take a look at [this file](https://github.com/AlexvZyl/nordic.nvim/blob/main/lua/nordic/groups/integrations.lua). For the list of supported platforms, please take a look at [this directory](https://github.com/AlexvZyl/nordic.nvim/tree/main/platforms). diff --git a/doc/nordic.nvim.txt b/doc/nordic.nvim.txt index 366d698f..0933b324 100644 --- a/doc/nordic.nvim.txt +++ b/doc/nordic.nvim.txt @@ -1,4 +1,4 @@ -*nordic.nvim.txt* For NVIM v0.8.0 Last change: 2024 April 14 +*nordic.nvim.txt* For NVIM v0.8.0 Last change: 2024 September 24 ============================================================================== Table of Contents *nordic.nvim-table-of-contents* @@ -59,7 +59,7 @@ With lazy.nvim : lazy = false, priority = 1000, config = function() - require 'nordic' .load() + require('nordic').load() end } < @@ -83,28 +83,31 @@ Using vim: Using lua: >lua - vim.cmd.colorscheme 'nordic' + vim.cmd.colorscheme('nordic') -- or - require 'nordic' .load() + require('nordic').load() < Using with lualine: >lua - require 'lualine' .setup { + require('lualine').setup({ options = { theme = 'nordic' } - } + }) < -To get the palette in lua: +If you want to use the color palette somewhere else, you can access it with: >lua - local palette = require 'nordic.colors' + local palette = require('nordic.colors') < + [!WARNING] Please make sure that `require('nordic.colors')` is called _after_ + setup, otherwise the colors might be wrong for your config. + ============================================================================== 6. ⚙️ Configuration *nordic.nvim-⚙️-configuration* @@ -112,23 +115,30 @@ Nordic will use the default values, unless `setup` is called. Below is the default configuration. >lua - require 'nordic' .setup { - -- This callback can be used to override the colors used in the palette. - on_palette = function(palette) return palette end, + require('nordic').setup({ + -- This callback can be used to override the colors used in the base palette. + on_palette = function(palette) end, + -- This callback can be used to override the colors used in the extended palette. + after_palette = function(palette) end, + -- This callback can be used to override highlights before they are applied. + on_highlight = function(highlights, palette) end, -- Enable bold keywords. bold_keywords = false, -- Enable italic comments. italic_comments = true, - -- Enable general editor background transparency. - transparent_bg = false, + -- Enable editor background transparency. + transparent = { + -- Enable transparent background. + bg = false, + -- Enable transparent background for floating windows. + float = false, + }, -- Enable brighter float border. bright_border = false, -- Reduce the overall amount of blue in the theme (diverges from base Nord). reduced_blue = true, -- Swap the dark background with the normal one. swap_backgrounds = false, - -- Override the styling of any highlight group. - override = {}, -- Cursorline options. Also includes visual/selection. cursorline = { -- Bold font in cursorline. @@ -156,16 +166,52 @@ default configuration. -- Enables dark background for treesitter-context window dark_background = true, } - } + }) +< + +**Examples:** + +on_palette ~ + +  + +An example of overriding colors in the base palette: + +>lua + require('nordic').setup({ + on_palette = function(palette) + palette.black0 = "#BF616A" + palette.green.base = palette.cyan.base + end, + }) +< + +after_palette ~ + +  + +An example of setting the visual selection color (for more values see this file +): + +>lua + require('nordic').setup({ + after_palette = function(palette) + local U = require("nordic.utils") + palette.bg_visual = U.blend(palette.orange.base, palette.bg, 0.15) + end, + }) < +on_highlight ~ + +  + An example of overriding the `TelescopePromptTitle` colors: >lua - local palette = require 'nordic.colors' - require 'nordic' .setup { - override = { - TelescopePromptTitle = { + require('nordic').setup({ + on_highlight = function(highlights, palette) + highlights.TelescopePromptTitle = { fg = palette.red.bright, bg = palette.green.base, italic = true, @@ -173,8 +219,20 @@ An example of overriding the `TelescopePromptTitle` colors: sp = palette.yellow.dim, undercurl = false } - } - } + end, + }) +< + +And an example of disabling all italics: + +>lua + require('nordic').setup({ + on_highlight = function(highlights, _palette) + for _, highlight in pairs(highlights) do + highlight.italic = false + end + end + }) < diff --git a/lua/lualine/themes/nordic.lua b/lua/lualine/themes/nordic.lua index 4b73d08b..a915799f 100644 --- a/lua/lualine/themes/nordic.lua +++ b/lua/lualine/themes/nordic.lua @@ -1,4 +1,4 @@ -local C = require 'nordic.colors' +local C = require('nordic.colors') local nordic = {} diff --git a/lua/nordic/colors/init.lua b/lua/nordic/colors/init.lua index 8d0e43ac..a182b726 100644 --- a/lua/nordic/colors/init.lua +++ b/lua/nordic/colors/init.lua @@ -1,7 +1,12 @@ -local U = require 'nordic.utils' -local C = require 'nordic.colors.nordic' +local U = require('nordic.utils') +local P = require('nordic.colors.nordic') + +local C = {} + +function C.build_palette() + -- Override all values from the base palette. + U.merge_inplace(C, P) -function C.extend_palette() local options = require('nordic.config').options -- `white0` is used as the default fg, and has a blue tint. @@ -9,7 +14,7 @@ function C.extend_palette() C.white0 = (options.reduced_blue and C.white0_reduce_blue) or C.white0_normal -- Modify the palette before generating colors. - C = options.on_palette(C) + options.on_palette(C) -- Add these for international convenience :) C.grey0 = C.gray0 @@ -23,27 +28,25 @@ function C.extend_palette() -- Some of the format is from @folke/tokyonight.nvim. -- Backgrounds - C.bg = (options.transparent_bg and C.none) or ((options.swap_backgrounds and C.black1) or C.gray0) - C.bg_dark = (options.transparent_bg and C.none) or C.black0 - C.bg_sidebar = (options.transparent_bg and C.none) or C.bg - C.bg_popup = (options.transparent_bg and C.none) or C.bg + C.bg = (options.transparent.bg and C.none) or ((options.swap_backgrounds and C.black1) or C.gray0) + C.bg_dark = (options.transparent.bg and C.none) or C.black0 + C.bg_sidebar = (options.transparent.bg and C.none) or C.bg C.bg_statusline = C.black0 - C.bg_selected = U.blend(C.gray2, C.black0, 0.4) C.bg_fold = C.gray2 -- Cursorline Background if options.cursorline.theme == 'light' then - options.cursorline.bg = C.gray1 + options.cursorline.bg = C.gray2 else options.cursorline.bg = C.black0 end - C.bg_visual = (options.transparent_bg and options.cursorline.bg) + C.bg_visual = (options.transparent.bg and options.cursorline.bg) or U.blend(options.cursorline.bg, C.bg, options.cursorline.blend) -- Borders C.border_fg = (options.bright_border and C.white0) or C.black0 - C.border_bg = (options.transparent_bg and C.none) or C.bg + C.border_bg = (options.transparent.bg and C.none) or C.bg -- Foregrounds C.fg = C.white0 @@ -53,18 +56,19 @@ function C.extend_palette() C.fg_fold = C.fg C.fg_selected = C.fg_bright - -- Popups - C.bg_popup = C.bg - C.fg_popup = C.fg - C.bg_popup_border = C.bg - C.fg_popup_border = C.border_fg - -- Floating windows - C.bg_float = (options.transparent_bg and C.none) or ((options.swap_backgrounds and C.gray0) or C.black1) + C.bg_float = (options.transparent.float and C.none) or ((options.swap_backgrounds and C.gray0) or C.black1) C.fg_float = C.fg C.bg_float_border = C.bg_float C.fg_float_border = C.border_fg + -- Popups + C.bg_popup = C.bg_float + C.bg_selected = C.gray2 + C.fg_popup = C.fg + C.bg_popup_border = C.bg + C.fg_popup_border = C.border_fg + -- Diffs local diff_blend = 0.2 C.diff = { @@ -90,10 +94,12 @@ function C.extend_palette() -- Misc C.comment = C.gray4 + + -- Modify the palette after generating colors. + options.after_palette(C) end --- Sometimes the palette is required before the theme has been loaded, --- so we need to extend the palette in those cases. -C.extend_palette() +-- Build the first palette. +C.build_palette() return C diff --git a/lua/nordic/colors/nordic.lua b/lua/nordic/colors/nordic.lua index a95136b2..8013ef5d 100644 --- a/lua/nordic/colors/nordic.lua +++ b/lua/nordic/colors/nordic.lua @@ -1,6 +1,7 @@ -- The Nord palette: https://www.nordtheme.com/. -- This file has a bunch of added colors. +-- NOTE: All hex codes must be uppercase (for testing) local palette = { none = 'NONE', diff --git a/lua/nordic/compatibility.lua b/lua/nordic/compatibility.lua new file mode 100644 index 00000000..e293881b --- /dev/null +++ b/lua/nordic/compatibility.lua @@ -0,0 +1,48 @@ +local U = require('nordic.utils') + +local function compatability(options) + -- All backwards compatibility + -- While an option is deprecated it should still work but be overridden by its replacement + + -- Log level + local level = vim.log.levels.WARN + -- Message Options + local message_options = { + title = 'Warning from nordic.nvim', + } + + -- transparent_bg + if options.transparent_bg ~= nil then + vim.notify_once( + 'Nordic.nvim: config.transparent_bg is deprecated, use config.transparent instead', + level, + message_options + ) + + options.transparent = { + bg = options.transparent_bg, + float = options.transparent_bg, + } + end + + -- override + if options.override ~= nil then + vim.notify_once( + 'Nordic.nvim: config.override is deprecated, use config.on_highlight instead', + level, + message_options + ) + + local users_on_highlight = options.on_highlight + -- Create a new on_highlight that will apply `override` and then the users `on_highlight` + options.on_highlight = function(highlights, palette) + U.merge_inplace(highlights, options.override) + -- This nil check is required because we have not been given default values yet + if users_on_highlight ~= nil then users_on_highlight(highlights, palette) end + end + end + + return options +end + +return compatability diff --git a/lua/nordic/config.lua b/lua/nordic/config.lua index b85b7a60..aba079e0 100644 --- a/lua/nordic/config.lua +++ b/lua/nordic/config.lua @@ -1,24 +1,29 @@ local M = {} local defaults = { - -- This callback can be used to override the colors used in the palette. - on_palette = function(palette) - return palette - end, + -- This callback can be used to override the colors used in the base palette. + on_palette = function(palette) end, + -- This callback can be used to override the colors used in the extended palette. + after_palette = function(palette) end, + -- This callback can be used to override highlights before they are applied. + on_highlight = function(highlights, palette) end, -- Enable bold keywords. bold_keywords = false, -- Enable italic comments. italic_comments = true, - -- Enable general editor background transparency. - transparent_bg = false, + -- Enable editor background transparency. + transparent = { + -- Enable transparent background. + bg = false, + -- Enable transparent background for floating windows. + float = false, + }, -- Enable brighter float border. bright_border = false, - -- Adjusts some colors to make the theme a bit nicer (imo). + -- Reduce the overall amount of blue in the theme (diverges from base Nord). reduced_blue = true, - -- Swop the dark background with the normal one. + -- Swap the dark background with the normal one. swap_backgrounds = false, - -- Override the styling of any highlight group. - override = {}, -- Cursorline options. Also includes visual/selection. cursorline = { -- Bold font in cursorline. @@ -52,6 +57,10 @@ M.options = defaults -- called automatically by load function M.setup(options) + -- backwards compatibility + options = require('nordic.compatibility')(options) + + -- set defaults M.options = vim.tbl_deep_extend('force', M.options or defaults, options or {}) end diff --git a/lua/nordic/groups/init.lua b/lua/nordic/groups/init.lua index 6f898922..5bdc7745 100644 --- a/lua/nordic/groups/init.lua +++ b/lua/nordic/groups/init.lua @@ -1,16 +1,25 @@ -local merge = require('nordic.utils').merge +local merge_inplace = require('nordic.utils').merge_inplace local M = {} function M.get_groups() - local groups = - merge(require('nordic.groups.native').get_groups(), require('nordic.groups.integrations').get_groups()) + local native = require('nordic.groups.native').get_groups() + local integrations = require('nordic.groups.integrations').get_groups() - return merge(groups, require('nordic.config').options.override) + local groups = {} + merge_inplace(groups, native) + merge_inplace(groups, integrations) + + -- Apply on_highlight + local palette = require('nordic.colors') + local options = require('nordic.config').options + options.on_highlight(groups, palette) + + return groups end function M.set_term_colors() - local colors = require 'nordic.groups.terminal' + local colors = require('nordic.groups.terminal') for term, col in pairs(colors) do vim.g[term] = col end diff --git a/lua/nordic/groups/integrations.lua b/lua/nordic/groups/integrations.lua index 2c4b7edd..b6c9c265 100644 --- a/lua/nordic/groups/integrations.lua +++ b/lua/nordic/groups/integrations.lua @@ -1,7 +1,7 @@ local M = {} function M.get_groups() - local C = require 'nordic.colors' + local C = require('nordic.colors') local O = require('nordic.config').options local G = {} @@ -85,7 +85,7 @@ function M.get_groups() G.DiagnosticBorder = { link = 'FloatBorder' } -- Mini Statusline. - local LC = require 'lualine.themes.nordic' + local LC = require('lualine.themes.nordic') G.MiniStatuslineModeNormal = { bg = LC.normal.a.bg, fg = LC.normal.a.fg, bold = LC.normal.a.gui == 'bold' } G.MiniStatuslineModeInsert = { bg = LC.insert.a.bg, fg = LC.insert.a.fg, bold = LC.insert.a.gui == 'bold' } G.MiniStatuslineModeVisual = { bg = LC.visual.a.bg, fg = LC.visual.a.fg, bold = LC.visual.a.gui == 'bold' } @@ -120,7 +120,6 @@ function M.get_groups() G.NeoTreeCursorLine = { link = 'NvimTreeCursorLine' } G.NeoTreeDirectoryIcon = { link = 'NvimTreeFolderIcon' } G.NeoTreeRootName = { link = 'NvimTreeRootFolder' } - G.NeoTreeFileName = { link = 'NvimTreeNormal' } G.NeoTreeFileIcon = { fg = C.blue2 } G.NeoTreeFileNameOpened = { fg = C.fg } G.NeoTreeIndentMarker = { link = 'NvimTreeIndentMarker' } @@ -290,7 +289,7 @@ function M.get_groups() --- Punctuation G['@punctuation.delimiter'] = { link = 'Delimiter' } -- For delimiters ie: `.` G['@punctuation.bracket'] = { link = '@operator' } -- For brackets and parens. - G['@punctuation.special'] = { link = 'Macro' } -- For special punctutation that does not fall in the catagories before. + G['@punctuation.special'] = { link = 'Macro' } -- For special punctuation that does not fall in the categories before. G['@punctuation.special.markdown'] = { fg = C.orange.base, bold = true } --- Literals G['@string'] = { link = 'String' } @@ -310,7 +309,7 @@ function M.get_groups() G['@keyword.directive.define'] = { link = 'Define' } G['@keyword.exception'] = { link = 'Exception' } G['@keyword.export'] = { link = 'Keyword' } - G['@keyword.function'] = { link = 'Keyword' } -- For keywords used to define a fuction. + G['@keyword.function'] = { link = 'Keyword' } -- For keywords used to define a function. G['@keyword.import'] = { link = 'Include' } G['@keyword.operator'] = { link = 'Keyword' } G['@keyword.repeat'] = { link = 'Repeat' } @@ -456,7 +455,7 @@ function M.get_groups() local bg local fg if O.ts_context.dark_background then - bg = C.black + bg = C.black1 fg = C.gray1 else bg = C.gray1 @@ -523,6 +522,13 @@ function M.get_groups() G.WhichKeySeperator = {} G.WhichKeyValue = {} + -- Rainbow delimiters + G.RainbowDelimiterOrange = { fg = C.orange.base } + G.RainbowDelimiterYellow = { fg = C.yellow.bright } + G.RainbowDelimiterBlue = { fg = C.blue2 } + G.RainbowDelimiterRed = { fg = C.red.bright } + G.RainbowDelimiterGreen = { fg = C.green.bright } + return G end diff --git a/lua/nordic/groups/native.lua b/lua/nordic/groups/native.lua index 04b9669a..6e9f2065 100644 --- a/lua/nordic/groups/native.lua +++ b/lua/nordic/groups/native.lua @@ -6,7 +6,7 @@ local M = {} -- Uncomment and edit if you want more specific syntax highlighting. function M.get_groups() - local C = require 'nordic.colors' + local C = require('nordic.colors') local O = require('nordic.config').options local G = {} diff --git a/lua/nordic/groups/terminal.lua b/lua/nordic/groups/terminal.lua index 9df67340..82f9923c 100644 --- a/lua/nordic/groups/terminal.lua +++ b/lua/nordic/groups/terminal.lua @@ -1,7 +1,7 @@ local M = {} function M.get_groups() - local C = require 'nordic.colors' + local C = require('nordic.colors') local G = {} G.terminal_color_0 = C.black0 diff --git a/lua/nordic/init.lua b/lua/nordic/init.lua index 0f8c26d4..ca3db28d 100644 --- a/lua/nordic/init.lua +++ b/lua/nordic/init.lua @@ -1,10 +1,10 @@ -local U = require 'nordic.utils' +local U = require('nordic.utils') local M = {} function M.load(opts) if not U.loaded() then - vim.api.nvim_command 'hi clear' + vim.api.nvim_command('hi clear') vim.o.termguicolors = true vim.g.colors_name = U.NAME end @@ -12,17 +12,17 @@ function M.load(opts) if opts then require('nordic.config').setup(opts) end -- Setup colors - require('nordic.colors').extend_palette() + require('nordic.colors').build_palette() -- Apply theme - local G = require 'nordic.groups' - U.highlight(G.get_groups()) + local G = require('nordic.groups') + U.apply_highlights(G.get_groups()) G.set_term_colors() end -- Add command to nvim vim.api.nvim_create_user_command('Nordic', function(_) - vim.api.nvim_command 'colorscheme nordic' + vim.api.nvim_command('colorscheme nordic') end, { nargs = 1, }) diff --git a/lua/nordic/tests/init.lua b/lua/nordic/tests/init.lua new file mode 100644 index 00000000..4053d9dd --- /dev/null +++ b/lua/nordic/tests/init.lua @@ -0,0 +1,11 @@ +M = {} + +function M.run_tests() + -- Ensures config resets + require('nordic').setup({}) + + require('nordic.tests.utils') + require('nordic.tests.options') +end + +return M diff --git a/lua/nordic/tests/options.lua b/lua/nordic/tests/options.lua index 010cb229..d6f4af42 100644 --- a/lua/nordic/tests/options.lua +++ b/lua/nordic/tests/options.lua @@ -1,39 +1,293 @@ --- First test the default config, and then test different variations of the config. +local base_palette = require('nordic.colors.nordic') -local config = require('nordic.config').options +local assert_eq = require('nordic.utils').assert_eq local load = require('nordic').load +local get_highlight = require('nordic.utils').get_highlight -local function flip_string(string) - local switch = { - ['light'] = 'dark', - ['dark'] = 'light', - ['flat'] = 'classic', - ['classic'] = 'flat', - } - return switch[string] -end - -load(config) - -config.on_palette = function(palette) - palette.black0 = '#000000' - return palette -end - --- Flip all fields -config.bold_keywords = not config.bold_keywords -config.italic_comments = not config.italic_comments -config.transparent_bg = not config.transparent_bg -config.bright_border = not config.bright_border -config.reduced_blue = not config.reduced_blue -config.swap_backgrounds = not config.swap_backgrounds -config.cursorline.bold = not config.cursorline.bold -config.cursorline.bold_number = not config.cursorline.bold_number -config.cursorline.theme = flip_string(config.cursorline.theme) -config.cursorline.blend = 0 -config.noice.style = flip_string(config.noice.style) -config.telescope.style = flip_string(config.telescope.style) -config.leap.dim_backdrop = not config.leap.dim_backdrop -config.ts_context.dark_background = not config.ts_context.dark_background - -load(config) +load({}) + +-- Tests for changes in palette should check highlights (to make sure everything is applied) + +-- on_palette +assert_eq( + get_highlight('Normal').bg, + base_palette.gray0, + 'on_palette: all highlights that use `gray0` should be `gray0` by default' +) +load({ + on_palette = function(palette) + palette.gray0 = '#FFFFFF' + end, +}) +assert_eq( + get_highlight('Normal').bg, + '#FFFFFF', + 'on_platte: changing a color should cascade to all highlights that use it' +) +load({ on_palette = function(_) end }) +assert_eq( + get_highlight('Normal').bg, + base_palette.gray0, + 'on_palette: reloading should revert the palette to its original state' +) + +-- after_palette +assert_eq( + get_highlight('Normal').bg, + base_palette.gray0, + 'after_palette: all highlights that use `bg` should be `gray0` by default' +) +load({ + after_palette = function(palette) + palette.bg = '#FFFFFF' + end, +}) +assert_eq( + get_highlight('Normal').bg, + '#FFFFFF', + 'after_platte: changing a color should cascade to all highlights that use it' +) +load({ after_palette = function(_) end }) +assert_eq( + get_highlight('Normal').bg, + base_palette.gray0, + 'after_palette: reloading should revert the palette to its original state' +) + +-- on_highlight +assert_eq(get_highlight('Normal').bg, base_palette.gray0, 'on_highlight: `Normal` should be `gray0` by default') +load({ + on_highlight = function(highlights, _) + highlights['Normal'].bg = '#FFFFFF' + end, +}) +assert_eq( + get_highlight('Normal').bg, + '#FFFFFF', + 'on_highlight: changing a highlight should actually change the highlight' +) +load({ on_highlight = function(_, _) end }) +assert_eq( + get_highlight('Normal').bg, + base_palette.gray0, + 'on_highlight: reloading should revert all highlights to their original state' +) + +-- bold_keywords +assert_eq(get_highlight('Keyword').bold, nil, 'bold_keywords: highlight `Keyword` should not be bold by default') +load({ bold_keywords = true }) +assert_eq( + get_highlight('Keyword').bold, + true, + 'bold_keywords: highlight `Keyword` should be bold if `bold_keywords` is true' +) +load({ bold_keywords = false }) + +-- italic_comments +assert_eq(get_highlight('Comment').italic, true, 'italic_comments: highlight `Comments` should be italic by default') +load({ italic_comments = false }) +assert_eq( + get_highlight('Comment').italic, + nil, + 'italic_comments: highlight `Comments` should not be italic if `italic_comments` is false' +) +load({ italic_comments = true }) + +-- transparent +-- bg +assert_eq(get_highlight('Normal').bg ~= nil, true, 'transparent: highlight `Normal.bg` should not be `nil` by default') +load({ transparent = { bg = true } }) +assert_eq( + get_highlight('Normal').bg, + nil, + 'transparent: highlight `Normal.bg` should be `nil` if `transparent.bg` is true' +) +load({ transparent = { bg = false } }) +-- float +assert_eq( + get_highlight('NormalFloat').bg ~= nil, + true, + 'transparent: highlight `NormalFloat.bg` should not be `nil` by default' +) +load({ transparent = { float = true } }) +assert_eq( + get_highlight('NormalFloat').bg, + nil, + 'transparent: highlight `NormalFloat.bg` should be `nil` if `transparent.float` is true' +) +load({ transparent = { float = false } }) + +-- bright_border +assert_eq( + get_highlight('WinSeparator').fg, + base_palette.black0, + 'bright_border: all highlights that use `border_fg` should be `black0` by default' +) +load({ bright_border = true }) +-- NOTE: This will fail if the wrong white0 variant is used +assert_eq( + get_highlight('WinSeparator').fg, + base_palette.white0_reduce_blue, + 'bright_border: all highlights that use `border_fg` should be `white0_reduce_blue` if `bright_border` is true' +) +load({ bright_border = false }) + +-- reduced_blue +assert_eq( + get_highlight('Normal').fg, + base_palette.white0_reduce_blue, + 'reduced_blue: all highlights that use `white0` should be `white0_reduce_blue` by default' +) +load({ reduced_blue = false }) +assert_eq( + get_highlight('Normal').fg, + base_palette.white0_normal, + 'reduced_blue: all highlights that use `white0` should be `white0_normal` if `reduced_blue` is false' +) +load({ reduced_blue = true }) + +-- swap_backgrounds +-- NOTE: This will fail if any transparent settings are set +assert_eq( + get_highlight('Normal').bg, + base_palette.gray0, + 'swap_backgrounds: all highlights that use `bg` should be `gray0` by default' +) +assert_eq( + get_highlight('NormalFloat').bg, + base_palette.black1, + 'swap_backgrounds: all highlights that use `bg_float` should be `black1` by default' +) +load({ swap_backgrounds = true }) +assert_eq( + get_highlight('Normal').bg, + base_palette.black1, + 'swap_backgrounds: all highlights that use `bg` should be `black1` if `swap_backgrounds` is true' +) +assert_eq( + get_highlight('NormalFloat').bg, + base_palette.gray0, + 'swap_backgrounds: all highlights that use `bg_float` should be `gray0` if `swap_backgrounds` is true' +) +load({ swap_backgrounds = false }) + +-- cursorline +-- bold +assert_eq(get_highlight('CursorLine').bold, nil, 'cursorline: highlight `CursorLine` should not be bold by default') +load({ cursorline = { bold = true } }) +assert_eq( + get_highlight('CursorLine').bold, + true, + 'cursorline: highlight `CursorLine` should be bold if `cursorline.bold` is true' +) +load({ cursorline = { bold = false } }) +-- bold_number +assert_eq(get_highlight('CursorLineNr').bold, true, 'cursorline: highlight `CursorLineNr` should be bold by default') +load({ cursorline = { bold_number = false } }) +assert_eq( + get_highlight('CursorLineNr').bold, + nil, + 'cursorline: highlight `CursorLineNr` should not be bold if `cursorline.bold_number` is false' +) +load({ cursorline = { bold_number = true } }) +-- theme +load({ cursorline = { blend = 1 } }) +assert_eq( + get_highlight('CursorLine').bg, + base_palette.black0, + 'cursorline: highlight `CursorLine` should be `black0` with the default theme' +) +load({ cursorline = { theme = 'light' } }) +assert_eq( + get_highlight('CursorLine').bg, + base_palette.gray2, + 'cursorline: highlight `CursorLine` should be `gray2` if `cursorline.theme` is `light`' +) +load({ cursorline = { theme = 'dark' } }) +assert_eq( + get_highlight('CursorLine').bg, + base_palette.black0, + 'cursorline: highlight `CursorLine` should be `black0` if `cursorline.theme` is `dark`' +) +-- blend +load({ cursorline = { blend = 1 } }) +assert_eq( + get_highlight('CursorLine').bg, + base_palette.black0, + 'cursorline: highlight `CursorLine` should be `black0` if `cursorline.blend` is 1' +) +load({ cursorline = { blend = 0.5 } }) +local blend = require('nordic.utils').blend +assert_eq( + get_highlight('CursorLine').bg, + blend(base_palette.black0, base_palette.gray0, 0.5), + 'cursorline: highlight `CursorLine` should be `#1F232C` if `cursorline.blend` is 0.5' +) +load({ cursorline = { blend = 0 } }) +assert_eq( + get_highlight('CursorLine').bg, + base_palette.gray0, + 'cursorline: highlight `CursorLine` should be `gray0` if `cursorline.blend` is 0' +) + +-- noice.style +assert_eq( + get_highlight('NoiceCmdline').bg, + base_palette.gray0, + 'noice: highlight `NoiceCmdline` should be `gray0` by default' +) +load({ noice = { style = 'flat' } }) +assert_eq( + get_highlight('NoiceCmdline').bg, + base_palette.black0, + 'noice: highlight `NoiceCmdline` should be `black0` if `noice.style` is `flat`' +) +load({ noice = { style = 'classic' } }) +assert_eq( + get_highlight('NoiceCmdline').bg, + base_palette.gray0, + 'noice: highlight `NoiceCmdline` should be `gray0` if `noice.style` is `classic`' +) + +-- telescope.style +assert_eq( + get_highlight('TelescopeNormal').bg, + base_palette.black1, + 'telescope: highlight `TelescopeNormal` should be `black1` by default' +) +load({ telescope = { style = 'classic' } }) +assert_eq( + get_highlight('TelescopeNormal').bg, + base_palette.gray0, + 'telescope: highlight `TelescopeNormal` should be `gray0` if `telescope.style` is `classic`' +) +load({ telescope = { style = 'flat' } }) +assert_eq( + get_highlight('TelescopeNormal').bg, + base_palette.black1, + 'telescope: highlight `TelescopeNormal` should be `black1` if `telescope.style` is `flat`' +) + +-- leap.dim_backdrop +assert_eq(get_highlight('LeapBackdrop').fg, nil, 'leap: highlight `LeapBackdrop` should be `nil` by default') +load({ leap = { dim_backdrop = true } }) +assert_eq( + get_highlight('LeapBackdrop').fg, + base_palette.gray4, + 'leap: highlight `LeapBackdrop` should be `gray4` if `leap.dim_backdrop` is true' +) +load({ leap = { dim_backdrop = false } }) + +-- ts_context.dark_background +assert_eq( + get_highlight('TreesitterContext').bg, + base_palette.black1, + 'ts_context: highlight `TreesitterContext` should be `black1` by default' +) +load({ ts_context = { dark_background = false } }) +assert_eq( + get_highlight('TreesitterContext').bg, + base_palette.gray1, + 'ts_context: highlight `TreesitterContext` should be `gray1` if `ts_context.dark_background` is false' +) +load({ ts_context = { dark_background = true } }) diff --git a/lua/nordic/tests/utils.lua b/lua/nordic/tests/utils.lua new file mode 100644 index 00000000..d970d8be --- /dev/null +++ b/lua/nordic/tests/utils.lua @@ -0,0 +1,59 @@ +local assert_eq = require('nordic.utils').assert_eq +local U = require('nordic.utils') + +local t1, t2, nested + +-- Types. + +assert_eq(U.none(), 'NONE', 'utils.none() should return "NONE"') +assert_eq(U.is_none('NONE'), true, 'U.is_none("NONE") should return true') +assert_eq(U.is_none('none'), true, 'U.is_none("none") should return true') +assert_eq(U.is_none('nil'), false, 'U.is_none("nil") should return false') +assert_eq(U.is_table('string'), false, 'U.is_table("string") should return false') +assert_eq(U.is_table(4), false, 'U.is_table(4) should return false') +assert_eq(U.is_table({}), true, 'U.is_table({}) should return true') + +-- Table. + +t1 = { a = 1 } +t2 = { b = 2 } +U.merge_inplace(t1, t2) +assert_eq(t1, { a = 1, b = 2 }, 'U.merge_inplace(t1, t2) basic merge') + +t1 = { a = 1, b = 3 } +t2 = { b = 2, c = 4 } +U.merge_inplace(t1, t2) +assert_eq(t1, { a = 1, b = 2, c = 4 }, 'U.merge_inplace(t1, t2) overwriting values') + +t1 = { a = 1, d = { x = 10 } } +t2 = { d = { y = 20 }, e = 5 } +U.merge_inplace(t1, t2) +assert_eq(t1, { a = 1, d = { x = 10, y = 20 }, e = 5 }, 'U.merge_inplace(t1, t2) nested tables') + +nested = { y = 20 } +t1 = { d = nested, e = 5 } +t2 = { a = 1 } +U.merge_inplace(t1, t2) +assert_eq(t1['d'] ~= nested, true, 'U.merge_inplace(t1, t2) copy t1 nested values') + +nested = { y = 20 } +t1 = { a = 1 } +t2 = { d = nested, e = 5 } +U.merge_inplace(t1, t2) +assert_eq(t1['d'] ~= nested, true, 'U.merge_inplace(t1, t2) copy t2 nested values') + +assert_eq(U.merge({}, {}), {}, 'U.merge({}, {}) should return an empty table') +assert_eq(U.merge(nil, nil), {}, 'U.merge(nil, nil) should return an empty table') +assert_eq(U.merge(nil, { a = 1 }), { a = 1 }, 'U.merge(nil, {a = 1}) should return {a = 1}') +assert_eq(U.merge({ a = 1 }, nil), { a = 1 }, 'U.merge({a = 1}, nil) should return {a = 1}') +assert_eq( + U.merge({ a = 1, b = 3 }, { b = 2, c = 4 }), + { a = 1, b = 2, c = 4 }, + 'U.merge({a = 1, b = 3}, {b = 2, c = 4}) should return {a = 1, b = 2, c = 4}' +) + +-- Colors. + +assert_eq({ U.hex_to_rgb('#191D24') }, { 25, 29, 36 }, 'U.hex_to_rgb("#191D24") should return 25, 29, 36') +assert_eq(U.rgb_to_hex(25, 29, 36), '#191D24', 'U.rgb_to_hex(25, 29, 36) should return "#191D24"') +assert_eq(U.blend('#FFFFFF', '#000000', 0.5), '#808080', 'U.blend("#FFFFFF", ""#000000", 0.5) should return "#808080"') diff --git a/lua/nordic/utils.lua b/lua/nordic/utils.lua index 26de7902..b8ba4cc7 100644 --- a/lua/nordic/utils.lua +++ b/lua/nordic/utils.lua @@ -5,112 +5,73 @@ function M.loaded() return vim.g.colors_name == M.NAME end -function M.highlight(table) - for group, config in pairs(table) do +function M.apply_highlights(groups) + for group, config in pairs(groups) do vim.api.nvim_set_hl(0, group, config) end end -function M.is_none(string) - return string == 'NONE' or string == 'none' +function M.get_highlight(group) + local function hexify(value) + if type(value) == 'number' then + return string.format('#%X', value) + elseif type(value) == 'table' then + return vim.tbl_map(hexify, value) + end + return value + end + + return hexify(vim.api.nvim_get_hl(0, { name = group, create = false })) end function M.none() return 'NONE' end -function M.merge(table1, table2) - if table1 == table2 == nil then return {} end - if table1 == nil then - return table2 - elseif table2 == nil then - return table1 - end - return vim.tbl_deep_extend('force', table1, table2) -end - -function M.hex_to_rgb(str) - str = string.lower(str) - return tonumber(str:sub(2, 3), 16), tonumber(str:sub(4, 5), 16), tonumber(str:sub(6, 7), 16) +function M.is_none(string) + return string == 'NONE' or string == 'none' end -function M.rgb_to_hex(r, g, b) - return '#' .. string.format('%x', r) .. string.format('%x', g) .. string.format('%x', b) +function M.is_table(value) + return type(value) == 'table' end -function M.rgb_to_hsv(r, g, b) - r, g, b = r / 255, g / 255, b / 255 - local max, min = math.max(r, g, b), math.min(r, g, b) - - local h, s, v - v = max - - local d = max - min - if max == 0 then - s = 0 - else - s = d / max +function M.merge(t1, t2) + if not t1 then + return t2 or {} + elseif not t2 then + return t1 end + return vim.tbl_deep_extend('force', t1, t2) +end - if max == min then - h = 0 - else - if max == r then - h = (g - b) / d - if g < b then h = h + 6 end - elseif max == g then - h = (b - r) / d + 2 - elseif max == b then - h = (r - g) / d + 4 +function M.merge_inplace(t1, t2) + -- clone values + for k, v in pairs(t1) do + if M.is_table(v) then + t1[k] = {} + M.merge_inplace(t1[k], v) end - h = h / 6 end - return h, s, v -end - -function M.hsv_to_rbg(h, s, v) - local r, g, b - - local i = math.floor(h * 6) - local f = h * 6 - i - local p = v * (1 - s) - local q = v * (1 - f * s) - local t = v * (1 - (1 - f) * s) - - i = i % 6 - - if i == 0 then - r, g, b = v, t, p - elseif i == 1 then - r, g, b = q, v, p - elseif i == 2 then - r, g, b = p, v, t - elseif i == 3 then - r, g, b = p, q, v - elseif i == 4 then - r, g, b = t, p, v - elseif i == 5 then - r, g, b = v, p, q + -- merge + for k, v in pairs(t2) do + if M.is_table(v) then + if not M.is_table(t1[k]) then t1[k] = {} end + M.merge_inplace(t1[k], v) + else + t1[k] = v + end end - - return r * 255, g * 255, b * 255 end -function M.darken(hex, amount) - local r, g, b = M.hex_to_rgb(hex) - local h, s, v = M.rgb_to_hsv(r, g, b) - v = v * ((1 - amount) / 1) - r, g, b = M.hsv_to_rbg(h, s, v) - return M.rgb_to_hex(r, g, b) +function M.hex_to_rgb(str) + str = string.lower(str) + return tonumber(str:sub(2, 3), 16), tonumber(str:sub(4, 5), 16), tonumber(str:sub(6, 7), 16) end -function M.lighten(hex, amount) - local r, g, b = M.hex_to_rgb(hex) - local h, s, v = M.rgb_to_hsv(r, g, b) - v = v * (1 + amount) - r, g, b = M.hsv_to_rbg(h, s, v) - return M.rgb_to_hex(r, g, b) +function M.rgb_to_hex(r, g, b) + return '#' .. string.format('%X', r) .. string.format('%X', g) .. string.format('%X', b) end -- Adapted from @folke/tokyonight.nvim. @@ -128,4 +89,16 @@ function M.blend(foreground, background, alpha) return M.rgb_to_hex(blend_channel(fg[1], bg[1]), blend_channel(fg[2], bg[2]), blend_channel(fg[3], bg[3])) end +function M.assert_eq(left, right, message) + if not vim.deep_equal(left, right) then + local info = debug.getinfo(2) + local file_name = info.short_src + local line_number = info.currentline + print('Equal assertion failed at "' .. file_name .. ':' .. line_number .. '"') + print('Message: ' .. message) + print('Left:\n' .. vim.inspect(left)) + print('Right:\n' .. vim.inspect(right)) + end +end + return M