From b4e860322d6dd4ab8ac2def72a27e8891415edbe Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 13 Jul 2024 18:52:07 +0800 Subject: [PATCH] feat(hsv): add hsv format --- bundle/cpicker.nvim/lua/cpicker.lua | 227 ++++-------------- .../cpicker.nvim/lua/cpicker/formats/hsl.lua | 109 +++++++++ .../cpicker.nvim/lua/cpicker/formats/hsv.lua | 110 +++++++++ .../cpicker.nvim/lua/cpicker/formats/rgb.lua | 89 +++++++ bundle/cpicker.nvim/lua/cpicker/util.lua | 22 ++ .../cpicker.nvim/syntax/spacevim_cpicker.vim | 2 +- lua/spacevim/api/color.lua | 93 +++++++ 7 files changed, 465 insertions(+), 187 deletions(-) create mode 100644 bundle/cpicker.nvim/lua/cpicker/formats/hsl.lua create mode 100644 bundle/cpicker.nvim/lua/cpicker/formats/hsv.lua create mode 100644 bundle/cpicker.nvim/lua/cpicker/formats/rgb.lua create mode 100644 bundle/cpicker.nvim/lua/cpicker/util.lua diff --git a/bundle/cpicker.nvim/lua/cpicker.lua b/bundle/cpicker.nvim/lua/cpicker.lua index 372b1f6d5..413f54bf3 100644 --- a/bundle/cpicker.nvim/lua/cpicker.lua +++ b/bundle/cpicker.nvim/lua/cpicker.lua @@ -10,197 +10,37 @@ local M = {} local winid local bufnr +local color_hi = '#000000' local hi = require('spacevim.api.vim.highlight') -local color = require('spacevim.api.color') local notify = require('spacevim.api.notify') +local log = require('spacevim.logger').derive('cpicker') +local util = require('cpicker.util') -local red = 0 -- [0, 255] -local green = 0 -- [0, 255] -local blue = 0 -- [0, 255] -local hue = 0 -- [0, 360] -local saturation = 0 -- [0, 100%] -local lightness = 0 -- [0, 100%] local enabled_formats = {} local increase_keys = {} local reduce_keys = {} -local function decimalToHex(decimal) - local hex = '' - local hexChars = '0123456789ABCDEF' - while decimal > 0 do - local mod = decimal % 16 - hex = string.sub(hexChars, mod + 1, mod + 1) .. hex - decimal = math.floor(decimal / 16) - end - if hex == '' then - return '00' - elseif #hex == 1 then - return '0' .. hex - else - return hex - end -end - -local function generate_bar(n, char, m) - return string.rep(char, math.floor(24 * n / (m or 255))) -end -local function increase_rgb_red() - if red < 255 then - red = red + 1 - hue, saturation, lightness = color.rgb2hsl(red, green, blue) - end -end -local function reduce_rgb_red() - if red > 0 then - red = red - 1 - hue, saturation, lightness = color.rgb2hsl(red, green, blue) - end -end -local function increase_rgb_green() - if green < 255 then - green = green + 1 - hue, saturation, lightness = color.rgb2hsl(red, green, blue) - end -end -local function reduce_rgb_green() - if green > 0 then - green = green - 1 - hue, saturation, lightness = color.rgb2hsl(red, green, blue) - end -end - -local function increase_rgb_blue() - if blue < 255 then - blue = blue + 1 - hue, saturation, lightness = color.rgb2hsl(red, green, blue) - end -end - -local function reduce_rgb_blue() - if blue > 0 then - blue = blue - 1 - hue, saturation, lightness = color.rgb2hsl(red, green, blue) - end -end - -local function increase_hsl_h() - if hue < 360 then - hue = hue + 1 - red, green, blue = color.hsl2rgb(hue, saturation, lightness) - end -end -local function reduce_hsl_h() - if hue >= 1 then - hue = hue - 1 - elseif hue > 0 then - hue = 0 - end - red, green, blue = color.hsl2rgb(hue, saturation, lightness) -end -local function increase_hsl_s() - if saturation <= 0.99 then - saturation = saturation + 0.01 - elseif saturation < 1 then - saturation = 1 - end - red, green, blue = color.hsl2rgb(hue, saturation, lightness) -end -local function reduce_hsl_s() - if saturation >= 0.01 then - saturation = saturation - 0.01 - elseif saturation > 0 and saturation < 0.01 then - saturation = 0 - end - red, green, blue = color.hsl2rgb(hue, saturation, lightness) -end -local function increase_hsl_l() - if lightness <= 0.99 then - lightness = lightness + 0.01 - elseif lightness < 1 then - lightness = 1 - end - red, green, blue = color.hsl2rgb(hue, saturation, lightness) -end -local function reduce_hsl_l() - if lightness >= 0.01 then - lightness = lightness - 0.01 - elseif lightness > 0 and lightness < 0.01 then - lightness = 0 - end - red, green, blue = color.hsl2rgb(hue, saturation, lightness) -end - local function update_buf_text() local rst = {} - local r_bar = generate_bar(red, '+') - local g_bar = generate_bar(green, '+') - local b_bar = generate_bar(blue, '+') - local h_bar = generate_bar(hue, '+', 360) - local s_bar = generate_bar(saturation, '+', 1) - local l_bar = generate_bar(lightness, '+', 1) - if enabled_formats.all or enabled_formats.rgb then - table.insert(rst, 'R: ' .. string.format('%4s', red) .. ' ' .. r_bar) - increase_keys[#rst] = increase_rgb_red - reduce_keys[#rst] = reduce_rgb_red - table.insert(rst, 'G: ' .. string.format('%4s', green) .. ' ' .. g_bar) - increase_keys[#rst] = increase_rgb_green - reduce_keys[#rst] = reduce_rgb_green - table.insert(rst, 'B: ' .. string.format('%4s', blue) .. ' ' .. b_bar) - increase_keys[#rst] = increase_rgb_blue - reduce_keys[#rst] = reduce_rgb_blue - end - if enabled_formats.all or enabled_formats.hsl then - table.insert(rst, 'H: ' .. string.format('%4s', math.floor(hue + 0.5)) .. ' ' .. h_bar) - increase_keys[#rst] = increase_hsl_h - reduce_keys[#rst] = reduce_hsl_h - table.insert( - rst, - 'S: ' .. string.format('%3s', math.floor(saturation * 100 + 0.5)) .. '% ' .. s_bar - ) - increase_keys[#rst] = increase_hsl_s - reduce_keys[#rst] = reduce_hsl_s - table.insert( - rst, - 'L: ' .. string.format('%3s', math.floor(lightness * 100 + 0.5)) .. '% ' .. l_bar - ) - increase_keys[#rst] = increase_hsl_l - reduce_keys[#rst] = reduce_hsl_l + for _, format in ipairs(enabled_formats) do + local ok, f = pcall(require, 'cpicker.formats.' .. format) + if ok then + local funcs = f.increase_reduce_functions() + for i, text in ipairs(f.buf_text()) do + table.insert(rst, text) + increase_keys[#rst] = funcs[i][1] + reduce_keys[#rst] = funcs[i][2] + end + end end table.insert(rst, '') - local r = decimalToHex(red) - local g = decimalToHex(green) - local b = decimalToHex(blue) - if not vim.g.cpicker_default_format or vim.g.cpicker_default_format == 'hex' then - table.insert(rst, ' =========' .. ' #' .. r .. g .. b) - elseif vim.g.cpicker_default_format == 'rgb' then - table.insert(rst, ' =========' .. string.format(' rgb(%s, %s, %s)', red, green, blue)) - elseif vim.g.cpicker_default_format == 'hsl' then - table.insert( - rst, - ' =========' - .. string.format( - ' hsl(%s, %s%%, %s%%)', - math.floor(hue + 0.5), - math.floor(saturation * 100 + 0.5), - math.floor(lightness * 100 + 0.5) - ) - ) - elseif vim.g.cpicker_default_format == 'all' then - table.insert(rst, ' =========' .. ' #' .. r .. g .. b) - table.insert(rst, ' =========' .. string.format(' rgb(%s, %s, %s)', red, green, blue)) - table.insert( - rst, - ' =========' - .. string.format( - ' hsl(%s, %s%%, %s%%)', - math.floor(hue + 0.5), - math.floor(saturation * 100 + 0.5), - math.floor(lightness * 100 + 0.5) - ) - ) + for _, format in ipairs(enabled_formats) do + local ok, f = pcall(require, 'cpicker.formats.' .. format) + if ok then + table.insert(rst, f.color_code()) + end end - local color_hi = '#' .. r .. g .. b local normal_bg = hi.group2dict('Normal').guibg hi.hi({ name = 'SpaceVimPickerCode', @@ -225,13 +65,16 @@ local function update_buf_text() vim.api.nvim_set_option_value('modifiable', false, { buf = bufnr, }) + vim.api.nvim_win_set_config(winid, { + height = #rst + 1 + }) end -- https://zenn.dev/kawarimidoll/articles/a8ac50a17477bd local function copy_color() - local from, to = vim - .regex([[#[0123456789ABCDEF]\+\|rgb(\d\+,\s\d\+,\s\d\+)\|hsl(\d\+,\s\d\+%,\s\d\+%)]]) + local from, to = vim + .regex([[#[0123456789ABCDEF]\+\|rgb(\d\+,\s\d\+,\s\d\+)\|hsl(\d\+,\s\d\+%,\s\d\+%)\|hsv(\d\+,\s\d\+%,\s\d\+%)]]) :match_str(vim.fn.getline('.')) if from then vim.fn.setreg('+', string.sub(vim.fn.getline('.'), from, to + 1)) @@ -241,23 +84,35 @@ end local function increase() if increase_keys[vim.fn.line('.')] then - increase_keys[vim.fn.line('.')]() + local t, code = increase_keys[vim.fn.line('.')]() + color_hi = util.get_hex_code(t, code) + for _, format in ipairs(enabled_formats) do + local ok, f = pcall(require, 'cpicker.formats.' .. format) + if ok then + f.on_change(t, code) + end + end end update_buf_text() end local function reduce() if reduce_keys[vim.fn.line('.')] then - reduce_keys[vim.fn.line('.')]() + local t, code = reduce_keys[vim.fn.line('.')]() + color_hi = util.get_hex_code(t, code) + for _, format in ipairs(enabled_formats) do + local ok, f = pcall(require, 'cpicker.formats.' .. format) + if ok then + f.on_change(t, code) + end + end end update_buf_text() end M.picker = function(formats) - enabled_formats = {} - for _, v in ipairs(formats) do - enabled_formats[v] = true - end + enabled_formats = formats + log.info(vim.inspect(enabled_formats)) if not bufnr or not vim.api.nvim_win_is_valid(bufnr) then bufnr = vim.api.nvim_create_buf(false, false) vim.api.nvim_set_option_value('buftype', 'nofile', { diff --git a/bundle/cpicker.nvim/lua/cpicker/formats/hsl.lua b/bundle/cpicker.nvim/lua/cpicker/formats/hsl.lua new file mode 100644 index 000000000..af38f6ce4 --- /dev/null +++ b/bundle/cpicker.nvim/lua/cpicker/formats/hsl.lua @@ -0,0 +1,109 @@ +--============================================================================= +-- hsl.lua +-- Copyright (c) 2019-2024 Wang Shidong & Contributors +-- Author: Wang Shidong < wsdjeg@outlook.com > +-- URL: https://spacevim.org +-- License: GPLv3 +--============================================================================= +local M = {} + +local color = require('spacevim.api.color') +local util = require('cpicker.util') + +local hue = 0 -- [0, 360] +local saturation = 0 -- [0, 100%] +local lightness = 0 -- [0, 100%] + +local function on_change_argv() + return 'hsl', { hue, saturation, lightness } +end + +function M.buf_text() + local rst = {} + local h_bar = util.generate_bar(hue, '+', 360) + local s_bar = util.generate_bar(saturation, '+', 1) + local l_bar = util.generate_bar(lightness, '+', 1) + table.insert(rst, 'HSL: H: ' .. string.format('%4s', math.floor(hue + 0.5)) .. ' ' .. h_bar) + table.insert( + rst, + ' S: ' .. string.format('%3s', math.floor(saturation * 100 + 0.5)) .. '% ' .. s_bar + ) + table.insert( + rst, + ' L: ' .. string.format('%3s', math.floor(lightness * 100 + 0.5)) .. '% ' .. l_bar + ) + return rst +end + +function M.color_code() + return + ' =========' .. string.format( + ' hsl(%s, %s%%, %s%%)', + math.floor(hue + 0.5), + math.floor(saturation * 100 + 0.5), + math.floor(lightness * 100 + 0.5) + ) +end + +local function increase_hsl_h() + if hue < 360 then + hue = hue + 1 + end + return on_change_argv() +end +local function reduce_hsl_h() + if hue >= 1 then + hue = hue - 1 + elseif hue > 0 then + hue = 0 + end + return on_change_argv() +end +local function increase_hsl_s() + if saturation <= 0.99 then + saturation = saturation + 0.01 + elseif saturation < 1 then + saturation = 1 + end + return on_change_argv() +end +local function reduce_hsl_s() + if saturation >= 0.01 then + saturation = saturation - 0.01 + elseif saturation > 0 and saturation < 0.01 then + saturation = 0 + end + return on_change_argv() +end +local function increase_hsl_l() + if lightness <= 0.99 then + lightness = lightness + 0.01 + elseif lightness < 1 then + lightness = 1 + end + return on_change_argv() +end +local function reduce_hsl_l() + if lightness >= 0.01 then + lightness = lightness - 0.01 + elseif lightness > 0 and lightness < 0.01 then + lightness = 0 + end + return on_change_argv() +end +function M.increase_reduce_functions() + return { + { increase_hsl_h, reduce_hsl_h }, + { increase_hsl_s, reduce_hsl_s }, + { increase_hsl_l, reduce_hsl_l }, + } +end + +function M.on_change(f, code) + if f == 'hsl' then + return + end + hue, saturation, lightness = color[f .. '2hsl'](unpack(code)) +end + +return M diff --git a/bundle/cpicker.nvim/lua/cpicker/formats/hsv.lua b/bundle/cpicker.nvim/lua/cpicker/formats/hsv.lua new file mode 100644 index 000000000..ce0786eaa --- /dev/null +++ b/bundle/cpicker.nvim/lua/cpicker/formats/hsv.lua @@ -0,0 +1,110 @@ +--============================================================================= +-- hsv.lua --- +-- Copyright (c) 2019-2024 Wang Shidong & Contributors +-- Author: Wang Shidong < wsdjeg@outlook.com > +-- URL: https://spacevim.org +-- License: GPLv3 +--============================================================================= +local M = {} + +local color = require('spacevim.api.color') +local util = require('cpicker.util') + +local hue = 0 +local saturation = 0 +local value = 0 + +local function on_change_argv() + return 'hsv', {hue, saturation, value} +end + +function M.buf_text() + + local rst = {} + local h_bar = util.generate_bar(hue, '+', 360) + local s_bar = util.generate_bar(saturation, '+', 1) + local l_bar = util.generate_bar(value, '+', 1) + table.insert(rst, 'HSV: H: ' .. string.format('%4s', math.floor(hue + 0.5)) .. ' ' .. h_bar) + table.insert( + rst, + ' S: ' .. string.format('%3s', math.floor(saturation * 100 + 0.5)) .. '% ' .. s_bar + ) + table.insert( + rst, + ' V: ' .. string.format('%3s', math.floor(value * 100 + 0.5)) .. '% ' .. l_bar + ) + return rst +end + +function M.color_code() + return + ' =========' .. string.format( + ' hsv(%s, %s%%, %s%%)', + math.floor(hue + 0.5), + math.floor(saturation * 100 + 0.5), + math.floor(value * 100 + 0.5) + ) + +end +local function increase_hsl_h() + if hue < 360 then + hue = hue + 1 + end + return on_change_argv() +end +local function reduce_hsl_h() + if hue >= 1 then + hue = hue - 1 + elseif hue > 0 then + hue = 0 + end + return on_change_argv() +end +local function increase_hsl_s() + if saturation <= 0.99 then + saturation = saturation + 0.01 + elseif saturation < 1 then + saturation = 1 + end + return on_change_argv() +end +local function reduce_hsl_s() + if saturation >= 0.01 then + saturation = saturation - 0.01 + elseif saturation > 0 and saturation < 0.01 then + saturation = 0 + end + return on_change_argv() +end +local function increase_hsl_v() + if value <= 0.99 then + value = value + 0.01 + elseif value < 1 then + value = 1 + end + return on_change_argv() +end +local function reduce_hsl_v() + if value >= 0.01 then + value = value - 0.01 + elseif value > 0 and value < 0.01 then + value = 0 + end + return on_change_argv() +end +function M.increase_reduce_functions() + return { + { increase_hsl_h, reduce_hsl_h }, + { increase_hsl_s, reduce_hsl_s }, + { increase_hsl_v, reduce_hsl_v }, + } +end + +function M.on_change(f, code) + if f == 'hsv' then + return + end + hue, saturation, value = color[f .. '2hsv'](unpack(code)) +end + +return M diff --git a/bundle/cpicker.nvim/lua/cpicker/formats/rgb.lua b/bundle/cpicker.nvim/lua/cpicker/formats/rgb.lua new file mode 100644 index 000000000..7856951fe --- /dev/null +++ b/bundle/cpicker.nvim/lua/cpicker/formats/rgb.lua @@ -0,0 +1,89 @@ +--============================================================================= +-- rgb.lua --- +-- Copyright (c) 2019-2024 Wang Shidong & Contributors +-- Author: Wang Shidong < wsdjeg@outlook.com > +-- URL: https://spacevim.org +-- License: GPLv3 +--============================================================================= +local M = {} + +local color = require('spacevim.api.color') +local util = require('cpicker.util') + +local red = 0 -- [0, 255] +local green = 0 -- [0, 255] +local blue = 0 -- [0, 255] + +local function on_change_argv() + return 'rgb', { red, green, blue } +end + +function M.buf_text() + local rst = {} + local r_bar = util.generate_bar(red, '+') + local g_bar = util.generate_bar(green, '+') + local b_bar = util.generate_bar(blue, '+') + table.insert(rst, 'RGB: R: ' .. string.format('%4s', red) .. ' ' .. r_bar) + table.insert(rst, ' G: ' .. string.format('%4s', green) .. ' ' .. g_bar) + table.insert(rst, ' B: ' .. string.format('%4s', blue) .. ' ' .. b_bar) + return rst +end + +function M.color_code() + return ' =========' .. ' ' .. color.rgb2hex(red, green, blue) +end + +local function increase_rgb_red() + if red < 255 then + red = red + 1 + end + return on_change_argv() +end +local function reduce_rgb_red() + if red > 0 then + red = red - 1 + end + return on_change_argv() +end +local function increase_rgb_green() + if green < 255 then + green = green + 1 + end + return on_change_argv() +end +local function reduce_rgb_green() + if green > 0 then + green = green - 1 + end + return on_change_argv() +end + +local function increase_rgb_blue() + if blue < 255 then + blue = blue + 1 + end + return on_change_argv() +end + +local function reduce_rgb_blue() + if blue > 0 then + blue = blue - 1 + end + return on_change_argv() +end +function M.increase_reduce_functions() + return { + { increase_rgb_red, reduce_rgb_red }, + { increase_rgb_green, reduce_rgb_green }, + { increase_rgb_blue, reduce_rgb_blue }, + } +end + +function M.on_change(f, code) + if f == 'rgb' then + return + end + red, green, blue = color[f .. '2rgb'](unpack(code)) +end + +return M diff --git a/bundle/cpicker.nvim/lua/cpicker/util.lua b/bundle/cpicker.nvim/lua/cpicker/util.lua new file mode 100644 index 000000000..1a03fb06e --- /dev/null +++ b/bundle/cpicker.nvim/lua/cpicker/util.lua @@ -0,0 +1,22 @@ +--============================================================================= +-- util.lua +-- Copyright (c) 2019-2024 Wang Shidong & Contributors +-- Author: Wang Shidong < wsdjeg@outlook.com > +-- URL: https://spacevim.org +-- License: GPLv3 +--============================================================================= + + +local M = {} + +local color = require('spacevim.api.color') + +function M.generate_bar(n, char, m) + return string.rep(char, math.floor(24 * n / (m or 255))) +end + +function M.get_hex_code(t, code) + return color[t .. '2hex'](unpack(code)) +end + +return M diff --git a/bundle/cpicker.nvim/syntax/spacevim_cpicker.vim b/bundle/cpicker.nvim/syntax/spacevim_cpicker.vim index 19f0e37bb..c172ca18a 100644 --- a/bundle/cpicker.nvim/syntax/spacevim_cpicker.vim +++ b/bundle/cpicker.nvim/syntax/spacevim_cpicker.vim @@ -5,7 +5,7 @@ let b:current_syntax = 'spacevim_cpicker' syntax case ignore syn match ProcessBar /[?=+]\+/ -syn match SpaceVimPickerCode /#[0123456789ABCDEF]\+\|rgb(\d\+,\s\d\+,\s\d\+)\|hsl(\d\+,\s\d\+%,\s\d\+%)/ +syn match SpaceVimPickerCode /#[0123456789ABCDEF]\+\|rgb(\d\+,\s\d\+,\s\d\+)\|hsl(\d\+,\s\d\+%,\s\d\+%)\|hsv(\d\+,\s\d\+%,\s\d\+%)/ syn match SpaceVimPickerBackground /=\+/ highlight ProcessBar ctermfg=Gray ctermbg=Gray guifg=Gray guibg=Gray diff --git a/lua/spacevim/api/color.lua b/lua/spacevim/api/color.lua index 2e9ad7552..dbae1d7b1 100644 --- a/lua/spacevim/api/color.lua +++ b/lua/spacevim/api/color.lua @@ -81,4 +81,97 @@ color.hsl2rgb = function(h, s, l) return math.floor(r * 255), math.floor(g * 255), math.floor(b * 255) end +-- https://www.rapidtables.com/convert/color/rgb-to-hsv.html + +color.rgb2hsv = function(r, g, b) + r = r / 255 + g = g / 255 + b = b / 255 + + local cmax = math.max(r, g, b) + local cmin = math.min(r, g, b) + local d = cmax - cmin + + local h, s, v + + if d == 0 then + h = 0 + elseif cmax == r then + h = 60 * (((g - b) / d) % 6) + elseif cmax == g then + h = 60 * (((b - r) / d) + 2) + elseif cmax == b then + h = 60 * (((r - g) / d) + 4) + end + + if cmax == 0 then + s = 0 + else + s = d / cmax + end + + v = cmax + + return math.floor(h), s, v +end + +-- https://www.rapidtables.com/convert/color/hsv-to-rgb.html +color.hsv2rgb = function(h, s, v) + local c = v * s + local x = c * (1 - math.abs((h / 60) % 2 - 1)) + local m = v - c + local r, g, b + + if h >= 0 and h < 60 then + r, g, b = c, x, 0 + elseif h >= 60 and h < 120 then + r, g, b = x, c, 0 + elseif h >= 120 and h < 180 then + r, g, b = 0, c, x + elseif h >= 180 and h < 240 then + r, g, b = 0, x, c + elseif h >= 240 and h < 300 then + r, g, b = x, 0, c + elseif h >= 300 and h < 360 then + r, g, b = c, 0, x + end + r, g, b = (r + m), (g + m), (b + m) + return math.floor(r * 255), math.floor(g * 255), math.floor(b * 255) +end +color.hsv2hsl = function(h, s, v) + return color.rgb2hsl(color.hsv2rgb(h, s, v)) +end +color.hsl2hsv = function(h, s, l) + return color.rgb2hsv(color.hsl2rgb(h, s, l)) +end + +local function decimalToHex(decimal) + local hex = '' + local hexChars = '0123456789ABCDEF' + while decimal > 0 do + local mod = decimal % 16 + hex = string.sub(hexChars, mod + 1, mod + 1) .. hex + decimal = math.floor(decimal / 16) + end + if hex == '' then + return '00' + elseif #hex == 1 then + return '0' .. hex + else + return hex + end +end +color.rgb2hex = function(r, g, b) + r = decimalToHex(r) + g = decimalToHex(g) + b = decimalToHex(b) + return '#' .. r .. g .. b +end +color.hsv2hex = function(h, s, v) + return color.rgb2hex(color.hsv2rgb(h, s, v)) +end +color.hsl2hex = function(h, s, l) + return color.rgb2hex(color.hsl2rgb(h, s, l)) +end + return color