From f0783201faa567879c0deef0c1081c3097b40835 Mon Sep 17 00:00:00 2001 From: Tristan Knight Date: Thu, 21 Dec 2023 21:09:58 +0000 Subject: [PATCH] refactor(init): move config into object and add tests (#33) Co-authored-by: tris203 Co-authored-by: Will Hopkins --- lua/hawtkeys/init.lua | 122 ++++++++++++++++++++--------------- lua/hawtkeys/score.lua | 26 ++++---- lua/hawtkeys/ts.lua | 18 +++--- tests/hawtkeys/init_spec.lua | 84 ++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 72 deletions(-) create mode 100644 tests/hawtkeys/init_spec.lua diff --git a/lua/hawtkeys/init.lua b/lua/hawtkeys/init.lua index 47ea44b..8e48fad 100644 --- a/lua/hawtkeys/init.lua +++ b/lua/hawtkeys/init.lua @@ -1,13 +1,18 @@ +---@class Hawtkeys +---@field config HawtKeyConfig +---@field package defaultConfig HawtKeyConfig local M = {} ----@alias SupportedKeyboardLayouts "qwerty" | "dvorak" +---@alias HawtKeySupportedKeyboardLayouts "qwerty" | "dvorak" ---@class HawtKeyConfig ---@field leader string ---@field homerow number ---@field powerFingers number[] ----@field keyboardLayout SupportedKeyboardLayouts +---@field keyboardLayout HawtKeySupportedKeyboardLayouts +---@field keyMapSet { [string] : TSKeyMapArgs | WhichKeyMapargs } | nil ---@field customMaps { [string] : TSKeyMapArgs | WhichKeyMapargs } | nil +---@field highlights HawtKeyHighlights | nil ---@class HawtKeyHighlights ---@field HawtkeysMatchGreat vim.api.keyset.highlight | nil @@ -19,13 +24,11 @@ local M = {} ---@field leader string | nil ---@field homerow number | nil ---@field powerFingers number[] | nil ----@field keyboardLayout SupportedKeyboardLayouts | nil +---@field keyboardLayout HawtKeySupportedKeyboardLayouts | nil ---@field customMaps { [string] : TSKeyMapArgs | WhichKeyMapargs } | nil ---@field highlights HawtKeyHighlights | nil ---- ---@type { [string] : TSKeyMapArgs | WhichKeyMapargs }--- - local _defaultSet = { ["vim.keymap.set"] = { modeIndex = 1, @@ -46,58 +49,67 @@ local _defaultSet = { }, -- method 6 } ----@param config HawtKeyPartialConfig -function M.setup(config) - config = config or {} - M.leader = config.leader or " " - M.homerow = config.homerow or 2 - M.powerFingers = config.powerFingers or { 2, 3, 6, 7 } - M.keyboardLayout = config.keyboardLayout or "qwerty" - M.keyMapSet = vim.tbl_extend("force", _defaultSet, config.customMaps or {}) +local defaultConfig = { + leader = " ", + homerow = 2, + powerFingers = { 2, 3, 6, 7 }, + keyboardLayout = "qwerty", + keyMapSet = _defaultSet, + highlights = { + HawtkeysMatchGreat = { link = "DiagnosticOk", underline = true }, + HawtkeysMatchGood = { link = "DiagnosticOk" }, + HawtkeysMatchOk = { link = "DiagnosticWarn" }, + HawtkeysMatchBad = { link = "DiagnosticError" }, + }, +} + +local function apply_highlights() + for name, props in pairs(M.config.highlights) do + local styleConfig + if props.link then + styleConfig = vim.api.nvim_get_hl(0, { + name = props.link, + link = false, + }) + else + styleConfig = {} + end - local default_match_great - if not config.highlights or not config.highlights.HawtkeysMatchGreat then - default_match_great = - vim.api.nvim_get_hl(0, { name = "DiagnosticOk", link = false }) - default_match_great.underline = true + for k, v in pairs(props) do + if k ~= "link" then + styleConfig[k] = v + end + end + vim.api.nvim_set_hl(0, name, styleConfig) end - M.highlights = vim.tbl_extend("keep", config.highlights or {}, { - HawtkeysMatchGreat = default_match_great, - HawtkeysMatchGood = { - link = "DiagnosticOk", - }, - HawtkeysMatchOk = { - link = "DiagnosticWarn", - }, - HawtkeysMatchBad = { - link = "DiagnosticError", - }, - }) +end - for name, hl in pairs(M.highlights) do - vim.api.nvim_set_hl(0, name, hl) +---@param config HawtKeyPartialConfig +function M.setup(config) + M.config = M.config or {} + for k, default in pairs(defaultConfig) do + local v = config[k] + if k == "highlights" then + -- shallow merge to preserve highlight values + M.config[k] = + vim.tbl_extend("force", defaultConfig.highlights, v or {}) + elseif k == "keyMapSet" then + M.config[k] = vim.tbl_deep_extend( + "force", + defaultConfig.keyMapSet, + config.customMaps or {} + ) + elseif type(default) == "table" then + M.config[k] = vim.tbl_deep_extend("force", default, v or {}) + else + M.config[k] = v or default + end end - vim.api.nvim_create_autocmd("ColorScheme", { - callback = function() - if default_match_great then - for k, v in - pairs( - vim.api.nvim_get_hl( - 0, - { name = "DiagnosticOk", link = false } - ) - ) - do - default_match_great[k] = v - end - default_match_great.underline = true - end + apply_highlights() - for name, hl in pairs(M.highlights) do - vim.api.nvim_set_hl(0, name, hl) - end - end, + vim.api.nvim_create_autocmd("ColorScheme", { + callback = apply_highlights, }) vim.api.nvim_create_user_command( @@ -117,4 +129,12 @@ function M.setup(config) ) end +setmetatable(M, { + __index = function(_, k) + if k == "defaultConfig" then + return vim.deepcopy(defaultConfig) + end + end, +}) + return M diff --git a/lua/hawtkeys/score.lua b/lua/hawtkeys/score.lua index 838904e..87ee13e 100644 --- a/lua/hawtkeys/score.lua +++ b/lua/hawtkeys/score.lua @@ -1,4 +1,4 @@ -local config = require("hawtkeys") +local hawtkeys = require("hawtkeys") local keyboardLayouts = require("hawtkeys.keyboards") local tsSearch = require("hawtkeys.ts") local utils = require("hawtkeys.utils") @@ -51,24 +51,24 @@ local function key_score(key1, key2, str, layout) local sameFingerPenalty = (key1Data.finger == key2Data.finger) and 1 or 0 local homerowBonus = ( - key1Data.row == config.homerow - and key2Data.row == config.homerow + key1Data.row == hawtkeys.config.homerow + and key2Data.row == hawtkeys.config.homerow ) and 1 or 0 local powerFinger1Bonus = ( - key1Data.finger == config.powerFingers[1] - or key1Data.finger == config.powerFingers[2] - or key1Data.finger == config.powerFingers[3] - or key1Data.finger == config.powerFingers[4] + key1Data.finger == hawtkeys.config.powerFingers[1] + or key1Data.finger == hawtkeys.config.powerFingers[2] + or key1Data.finger == hawtkeys.config.powerFingers[3] + or key1Data.finger == hawtkeys.config.powerFingers[4] ) and 1 or 0 local powerFinger2Bonus = ( - key2Data.finger == config.powerFingers[1] - or key2Data.finger == config.powerFingers[2] - or key2Data.finger == config.powerFingers[3] - or key2Data.finger == config.powerFingers[4] + key2Data.finger == hawtkeys.config.powerFingers[1] + or key2Data.finger == hawtkeys.config.powerFingers[2] + or key2Data.finger == hawtkeys.config.powerFingers[3] + or key2Data.finger == hawtkeys.config.powerFingers[4] ) and 1 or 0 @@ -91,7 +91,7 @@ end ---@param str string ---@return table local function generate_combos(str) - str = str:gsub(config.leader, "") + str = str:gsub(hawtkeys.config.leader, "") local pairs = {} local len = #str for i = 1, len - 1 do @@ -112,7 +112,7 @@ local function find_matches(str) for _, combo in ipairs(combinations) do local a, b = combo:sub(1, 1), combo:sub(2, 2) - local score = key_score(a, b, str, config.keyboardLayout) + local score = key_score(a, b, str, hawtkeys.config.keyboardLayout) scores[combo] = score end diff --git a/lua/hawtkeys/ts.lua b/lua/hawtkeys/ts.lua index b11b35e..1d8d0ae 100644 --- a/lua/hawtkeys/ts.lua +++ b/lua/hawtkeys/ts.lua @@ -2,7 +2,7 @@ local M = {} local Path = require("plenary.path") local scan = require("plenary.scandir") local utils = require("hawtkeys.utils") -local config = require("hawtkeys") +local hawtkeys = require("hawtkeys") local ts = require("nvim-treesitter.compat") local tsQuery = require("nvim-treesitter.query") @@ -135,7 +135,7 @@ local function find_maps_in_file(filePath) -- need to use TS to resolve it back to a native keymap local dotIndexExpressionQuery = ts.parse_query( "lua", - build_dot_index_expression_query(config.keyMapSet) + build_dot_index_expression_query(hawtkeys.config.keyMapSet) ) for match in tsQuery.iter_prepared_matches( @@ -152,7 +152,7 @@ local function find_maps_in_file(filePath) node.node:parent():child(0), fileContent ) - local mapDef = config.keyMapSet[parent] + local mapDef = hawtkeys.config.keyMapSet[parent] ---@type string local mode = return_field_data( node.node, @@ -219,8 +219,10 @@ local function find_maps_in_file(filePath) end end - local functionCallQuery = - ts.parse_query("lua", build_function_call_query(config.keyMapSet)) + local functionCallQuery = ts.parse_query( + "lua", + build_function_call_query(hawtkeys.config.keyMapSet) + ) for match in tsQuery.iter_prepared_matches( @@ -237,7 +239,7 @@ local function find_maps_in_file(filePath) node.node:parent():child(0), fileContent ) - local mapDef = config.keyMapSet[parent] + local mapDef = hawtkeys.config.keyMapSet[parent] ---@type string local mode = return_field_data( node.node, @@ -306,7 +308,7 @@ local function find_maps_in_file(filePath) end local whichKeyQuery = - ts.parse_query("lua", build_which_key_query(config.keyMapSet)) + ts.parse_query("lua", build_which_key_query(hawtkeys.config.keyMapSet)) for match in tsQuery.iter_prepared_matches(whichKeyQuery, tree, fileContent, 0, -1) @@ -359,7 +361,7 @@ local function get_keymaps_from_vim() table.insert(vimKeymaps, { mode = vimKeymap.mode, -- TODO: leader subsitiution as vim keymaps contain raw leader - lhs = vimKeymap.lhs:gsub(config.leader, ""), + lhs = vimKeymap.lhs:gsub(hawtkeys.config.leader, ""), rhs = vimKeymap.rhs, from_file = "Vim Defaults", }) diff --git a/tests/hawtkeys/init_spec.lua b/tests/hawtkeys/init_spec.lua new file mode 100644 index 0000000..c6cd05b --- /dev/null +++ b/tests/hawtkeys/init_spec.lua @@ -0,0 +1,84 @@ +local hawtkeys = require("hawtkeys") +---@diagnostic disable-next-line: undefined-field +local eq = assert.are.same +---@diagnostic disable-next-line: undefined-field +local falsy = assert.falsy +local userCommands = { + ["Hawtkeys"] = "lua require('hawtkeys.ui').show()", + ["HawtkeysAll"] = "lua require('hawtkeys.ui').show_all()", + ["HawtkeysDupes"] = "lua require('hawtkeys.ui').show_dupes()", +} + +describe("set up function", function() + before_each(function() + require("plenary.reload").reload_module("hawtkeys") + for _, command in ipairs(userCommands) do + vim.api.nvim_command("silent! delcommand " .. command) + end + end) + it("should set up the default config", function() + hawtkeys.setup({}) + ---@diagnostic disable-next-line: invisible + eq(hawtkeys.defaultConfig, hawtkeys.config) + end) + + it("should be able to override the default config", function() + hawtkeys.setup({ leader = "," }) + eq(",", hawtkeys.config.leader) + end) + + it("can set custom highlights", function() + hawtkeys.setup({ + highlights = { + HawtkeysMatchGreat = { + link = "DiagnosticSomethingElse", + }, + }, + }) + eq( + "DiagnosticSomethingElse", + hawtkeys.config.highlights.HawtkeysMatchGreat.link + ) + eq( + ---@diagnostic disable-next-line: invisible + hawtkeys.defaultConfig.highlights.HawtkeysMatchGood, + hawtkeys.config.highlights.HawtkeysMatchGood + ) + end) + + it("can pass in custom mapping definitions", function() + hawtkeys.setup({ + customMaps = { + ["custom.map"] = { + method = "dot_index_expression", + lhsIndex = 1, + rhsIndex = 2, + modeIndex = "n", + optsIndex = 3, + }, + }, + }) + eq( + "dot_index_expression", + hawtkeys.config.keyMapSet["custom.map"].method + ) + eq(1, hawtkeys.config.keyMapSet["custom.map"].lhsIndex) + eq(2, hawtkeys.config.keyMapSet["custom.map"].rhsIndex) + eq("n", hawtkeys.config.keyMapSet["custom.map"].modeIndex) + eq(3, hawtkeys.config.keyMapSet["custom.map"].optsIndex) + end) + + it("User commands should be available after setup", function() + local commandspresetup = vim.api.nvim_get_commands({}) + hawtkeys.setup({}) + local commandsPostSetup = vim.api.nvim_get_commands({}) + -- Check that the commands are not present before setup + for command, _ in ipairs(userCommands) do + falsy(commandspresetup[command]) + end + -- Check that the commands are present after setup + for command, action in ipairs(userCommands) do + eq(action, commandsPostSetup[command].definition) + end + end) +end)