diff --git a/.gitmodules b/.gitmodules index 914712e..78473aa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,7 +2,3 @@ path = library/busted url = https://github.com/LuaCATS/busted branch = main -[submodule "library/luv"] - path = library/luv - url = https://github.com/LuaCATS/luv - branch = main diff --git a/library/luv b/library/luv deleted file mode 160000 index 3615eb1..0000000 --- a/library/luv +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3615eb12c94a7cfa7184b8488cf908abb5e94c9c diff --git a/lua/u.lua b/lua/u.lua index 721a51f..fc14682 100644 --- a/lua/u.lua +++ b/lua/u.lua @@ -542,6 +542,7 @@ function Range.from_motion(motion, opts) local is_bracket_txtobj = is_txtobj and BRACKET_MAP[motion_rest] ~= nil -- SECTION: Capture original state for restoration + local vinf, vinf_inverted = Range.from_vtext() local original_state = { winview = vim.fn.winsaveview(), unnamed_register = vim.fn.getreg '"', @@ -551,7 +552,8 @@ function Range.from_motion(motion, opts) opfunc = vim.go.operatorfunc, prev_captured_range = _G.Range__from_motion_opfunc_captured_range, prev_mode = vim.fn.mode(), - vinf = Range.from_vtext(), + vinf = vinf, + vinf_inverted = vinf_inverted, } --- @type u.Range|nil _G.Range__from_motion_opfunc_captured_range = nil @@ -603,7 +605,9 @@ function Range.from_motion(motion, opts) vim.fn.setpos('.', original_state.cursor) vim.fn.setpos("'[", original_state.mark_lbracket) vim.fn.setpos("']", original_state.mark_rbracket) - if original_state.prev_mode ~= 'n' then original_state.vinf:set_visual_selection() end + if original_state.prev_mode ~= 'n' then + original_state.vinf:set_visual_selection(original_state.vinf_inverted) + end vim.go.operatorfunc = original_state.opfunc _G.Range__from_motion_opfunc_captured_range = original_state.prev_captured_range @@ -663,7 +667,8 @@ end function Range.from_vtext() local r = Range.from_marks('v', '.') if vim.fn.mode() == 'V' then r = r:to_linewise() end - return r + local inverted = Pos.from_pos '.' ~= r.stop + return r, inverted end --- Get range information from the current text range being operated on @@ -806,18 +811,23 @@ end function Range:save_to_extmark() return Extmark.from_range(self, NS) end -function Range:set_visual_selection() +--- @param inverted boolean? +function Range:set_visual_selection(inverted) if self:is_empty() then return end if vim.api.nvim_get_current_buf() ~= self.start.bufnr then error 'Range:set_visual_selection() called on a buffer other than the current buffer' end - local curr_mode = vim.fn.mode() - if curr_mode ~= self.mode then vim.cmd.normal { args = { self.mode }, bang = true } end + local curr_mode = vim.fn.mode():sub(1, 1) + if curr_mode ~= self.mode then vim.cmd.normal { args = { ESC .. self.mode }, bang = true } end - self.start:save_to_pos '.' + local start, stop = self.start, self.stop + if inverted then + start, stop = stop, start + end + start:save_to_pos '.' vim.cmd.normal { args = { 'o' }, bang = true } - self.stop:save_to_pos '.' + stop:save_to_pos '.' end -------------------------------------------------------------------------------- diff --git a/spec/u_spec.lua b/spec/u_spec.lua index 89e63a8..ad17a4d 100644 --- a/spec/u_spec.lua +++ b/spec/u_spec.lua @@ -468,6 +468,42 @@ describe('Range', function() end) end) + it('from_motion preserves visual selection orientation (cursor at start)', function() + withbuf({ 'the quick brown fox' }, function() + vim.fn.setpos('.', { 0, 1, 5, 0 }) + vim.cmd.normal 'v' + vim.cmd.normal { args = { 'o' }, bang = true } + vim.fn.setpos('.', { 0, 1, 3, 0 }) + vim.cmd.normal { args = { 'o' }, bang = true } + + vim.cmd.normal { args = { 'o' }, bang = true } + local cursor_before = vim.fn.getpos('.')[3] + + Range.from_motion 'aw' + + vim.cmd.normal { args = { 'o' }, bang = true } + local cursor_after = vim.fn.getpos('.')[3] + + assert.are_not_same(cursor_before, cursor_after) + end) + end) + + it('from_motion preserves visual selection orientation (cursor at stop)', function() + withbuf({ 'the quick brown fox' }, function() + vim.fn.setpos('.', { 0, 1, 3, 0 }) + vim.cmd.normal 'vll' + + local cursor_before = vim.fn.getpos('.')[3] + + Range.from_motion 'aw' + + vim.cmd.normal { args = { 'o' }, bang = true } + local cursor_after = vim.fn.getpos('.')[3] + + assert.are_not_same(cursor_before, cursor_after) + end) + end) + describe('from_motion with max_lines', function() it('returns nil when bracket chars are beyond max_lines', function() -- A large block where { and } are far from cursor