From b3833d77afcd787cf8a2363f80d6174155a5bf7d Mon Sep 17 00:00:00 2001 From: Sasha Gurevich Date: Fri, 6 Mar 2026 19:15:11 +0200 Subject: [PATCH 1/3] feat(replacer): adding TODO for future framework --- lua/toggle/replacer.lua | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 lua/toggle/replacer.lua diff --git a/lua/toggle/replacer.lua b/lua/toggle/replacer.lua new file mode 100644 index 0000000..0258c70 --- /dev/null +++ b/lua/toggle/replacer.lua @@ -0,0 +1,4 @@ + +-- TODO provide here +-- modular framework for invoking various replacers for _toggle_ + From 19e91f45b8f869f84cb04a060d97c6060237abe7 Mon Sep 17 00:00:00 2001 From: Sasha Gurevich Date: Fri, 6 Mar 2026 19:54:23 +0200 Subject: [PATCH 2/3] feat(replacers): added replacing framework --- lua/toggle/init.lua | 39 +++++++++++------------------ lua/toggle/replacer.lua | 54 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/lua/toggle/init.lua b/lua/toggle/init.lua index 2f75eba..5cdb954 100644 --- a/lua/toggle/init.lua +++ b/lua/toggle/init.lua @@ -1,5 +1,6 @@ local mapping = require('toggle.mapping') local defaults = require('toggle.defaults') +local replacer = require('toggle.replacer') local M = {} @@ -35,34 +36,22 @@ function M.setup(opts) end function M.toggle() - local cWORD_under_cursor = vim.fn.expand('') - local cword_under_cursor = vim.fn.expand('') - local current_cursor_position = vim.fn.getcurpos() + local replacers = { + replacer.__cWORD_replacer(), + replacer.__cword_replacer(), + replacer.__character_replacer(), + } - if mapping.__has_mapping(cWORD_under_cursor) then - vim.api.nvim_command('normal! ciW' .. mapping.__get_mapping(cWORD_under_cursor)) - if config.keep_cursor_position then - vim.fn.setpos('.', current_cursor_position) - end - return - end + local current_cursor_position = vim.fn.getcurpos() - if mapping.__has_mapping(cword_under_cursor) then - vim.api.nvim_command('normal! ciw' .. mapping.__get_mapping(cword_under_cursor)) - if config.keep_cursor_position then - vim.fn.setpos('.', current_cursor_position) + for _, r in ipairs(replacers) do + if r.can_handle() then + r.replace() + if config.keep_cursor_position then + vim.fn.setpos('.', current_cursor_position) + end + return end - return - end - - -- fall back to single character under cursor - local coords = vim.api.nvim_win_get_cursor(0) - local line = vim.api.nvim_get_current_line() - local character_under_cursor = line:sub(coords[2] + 1, coords[2] + 1) - - if mapping.__has_mapping(character_under_cursor) then - vim.api.nvim_command('normal! r' .. mapping.__get_mapping(character_under_cursor)) - return end end diff --git a/lua/toggle/replacer.lua b/lua/toggle/replacer.lua index 0258c70..e9e8a7d 100644 --- a/lua/toggle/replacer.lua +++ b/lua/toggle/replacer.lua @@ -1,4 +1,54 @@ +local mapping = require('toggle.mapping') --- TODO provide here --- modular framework for invoking various replacers for _toggle_ +local M = {} +M.__cword_replacer = function() + return { + can_handle = function() + local word = vim.fn.expand('') + return mapping.__has_mapping(word) + end, + + replace = function() + local word = vim.fn.expand('') + vim.api.nvim_command('normal! ciw' .. mapping.__get_mapping(word)) + end, + } +end + +M.__cWORD_replacer = function() + return { + can_handle = function() + local word = vim.fn.expand('') + return mapping.__has_mapping(word) + end, + + replace = function() + local word = vim.fn.expand('') + vim.api.nvim_command('normal! ciW' .. mapping.__get_mapping(word)) + end, + } +end + +M.__character_replacer = function() + return { + can_handle = function() + local character = M.__get_character_under_cursor() + return mapping.__has_mapping(character) + end, + + replace = function() + local character = M.__get_character_under_cursor() + vim.api.nvim_command('normal! r' .. mapping.__get_mapping(character)) + end, + } +end + +-- TODO write tests +M.__get_character_under_cursor = function() + local coords = vim.api.nvim_win_get_cursor(0) + local line = vim.api.nvim_get_current_line() + return line:sub(coords[2] + 1, coords[2] + 1) +end + +return M From b60439878cb6c50bc24b13563d8c730dee928d61 Mon Sep 17 00:00:00 2001 From: Sasha Gurevich Date: Sat, 7 Mar 2026 18:28:38 +0200 Subject: [PATCH 3/3] feat(replacer): end of word replacer implementation --- lua/toggle/init.lua | 10 ++++++---- lua/toggle/replacer.lua | 41 ++++++++++++++++++++++++++------------ test/test_files/test_1.txt | 1 + test/toggle_spec.lua | 21 ++++++++++++++++--- 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/lua/toggle/init.lua b/lua/toggle/init.lua index 5cdb954..d801d9a 100644 --- a/lua/toggle/init.lua +++ b/lua/toggle/init.lua @@ -37,14 +37,16 @@ end function M.toggle() local replacers = { - replacer.__cWORD_replacer(), - replacer.__cword_replacer(), - replacer.__character_replacer(), + replacer.__get_cWORD_replacer, + replacer.__get_cword_replacer, + replacer.__get_end_of_word_replacer, + replacer.__character_replacer, } local current_cursor_position = vim.fn.getcurpos() - for _, r in ipairs(replacers) do + for _, get_replacer in ipairs(replacers) do + local r = get_replacer() if r.can_handle() then r.replace() if config.keep_cursor_position then diff --git a/lua/toggle/replacer.lua b/lua/toggle/replacer.lua index e9e8a7d..7b03b79 100644 --- a/lua/toggle/replacer.lua +++ b/lua/toggle/replacer.lua @@ -1,54 +1,69 @@ local mapping = require('toggle.mapping') +-- TODO provide luadocs for replacers local M = {} -M.__cword_replacer = function() +M.__get_cword_replacer = function() + local word = vim.fn.expand('') return { can_handle = function() - local word = vim.fn.expand('') return mapping.__has_mapping(word) end, replace = function() - local word = vim.fn.expand('') vim.api.nvim_command('normal! ciw' .. mapping.__get_mapping(word)) end, } end -M.__cWORD_replacer = function() +M.__get_cWORD_replacer = function() + local word = vim.fn.expand('') return { can_handle = function() - local word = vim.fn.expand('') return mapping.__has_mapping(word) end, replace = function() - local word = vim.fn.expand('') vim.api.nvim_command('normal! ciW' .. mapping.__get_mapping(word)) end, } end -M.__character_replacer = function() +M.__get_character_replacer = function() + local coords = vim.api.nvim_win_get_cursor(0) + local line = vim.api.nvim_get_current_line() + local character = line:sub(coords[2] + 1, coords[2] + 1) + return { can_handle = function() - local character = M.__get_character_under_cursor() return mapping.__has_mapping(character) end, replace = function() - local character = M.__get_character_under_cursor() vim.api.nvim_command('normal! r' .. mapping.__get_mapping(character)) end, } end --- TODO write tests -M.__get_character_under_cursor = function() - local coords = vim.api.nvim_win_get_cursor(0) +M.__get_end_of_word_replacer = function() + local current_cursor_position = vim.fn.getcurpos() + vim.api.nvim_command('normal! e') -- jump to the end of word + + local end_of_word_column = vim.api.nvim_win_get_cursor(0)[2] + vim.fn.setpos('.', current_cursor_position) -- restore cursor position + local line = vim.api.nvim_get_current_line() - return line:sub(coords[2] + 1, coords[2] + 1) + local end_of_word_under_cursor = line:sub(current_cursor_position[3], end_of_word_column + 1) + + return { + can_handle = function() + return mapping.__has_mapping(end_of_word_under_cursor) + end, + + replace = function() + vim.api.nvim_command('normal! ce' .. mapping.__get_mapping(end_of_word_under_cursor)) + end, + } end return M diff --git a/test/test_files/test_1.txt b/test/test_files/test_1.txt index ba0004c..50b2a23 100644 --- a/test/test_files/test_1.txt +++ b/test/test_files/test_1.txt @@ -1,3 +1,4 @@ false false, < +goto_prev diff --git a/test/toggle_spec.lua b/test/toggle_spec.lua index 94c4041..ba1a413 100644 --- a/test/toggle_spec.lua +++ b/test/toggle_spec.lua @@ -15,24 +15,39 @@ local function get_character_under_cursor() end describe('toggle', function() - it('toggle cword', function() + it('toggle - cword', function() open_file_at('test/test_files/test_1.txt', 1, 1, function() toggle.toggle() assert(vim.fn.expand('') == 'true') + toggle.toggle() + assert(vim.fn.expand('') == 'false') end) end) - it('toggle cWORD', function() + it('toggle - cWORD', function() open_file_at('test/test_files/test_1.txt', 2, 1, function() toggle.toggle() assert(vim.fn.expand('') == 'true') + toggle.toggle() + assert(vim.fn.expand('') == 'false') end) end) - it('toggle char', function() + it('toggle - char', function() open_file_at('test/test_files/test_1.txt', 3, 1, function() toggle.toggle() assert(get_character_under_cursor() == '>') + toggle.toggle() + assert(get_character_under_cursor() == '<') + end) + end) + + it('toggle - end of word', function() + open_file_at('test/test_files/test_1.txt', 4, 5, function() + toggle.toggle() + assert(vim.fn.expand('') == 'goto_next') + toggle.toggle() + assert(vim.fn.expand('') == 'goto_prev') end) end) end)