diff --git a/lua/u/range.lua b/lua/u/range.lua index 11a409d..69406dd 100644 --- a/lua/u/range.lua +++ b/lua/u/range.lua @@ -93,6 +93,8 @@ end --- @param bufnr number --- @param id number function Range.from_extmark(bufnr, id) + local mode = 'v' + ---@type integer, integer, vim.api.keyset.extmark_details | nil local start_row0, start_col0, details = unpack(vim.api.nvim_buf_get_extmark_by_id(bufnr, NS, id, { details = true })) @@ -100,15 +102,16 @@ function Range.from_extmark(bufnr, id) local start = Pos.new(bufnr, start_row0 + 1, start_col0 + 1) local stop = details and Pos.new(bufnr, details.end_row + 1, details.end_col) - local max_line_num = vim.api.nvim_buf_line_count(bufnr) - if stop and stop.lnum > max_line_num then - stop.lnum = max_line_num - stop.col = Pos.MAX_COL - stop = stop:as_real() - end - if stop and stop.col == 0 then stop = stop:must_next(-1) end + -- Check for invalid extmark range: + if stop and stop < start then return Range.new(stop) end - return Range.new(start, stop, 'v') + if stop and stop.col == 0 then + mode = 'V' + stop = stop:must_next(-1) + stop.col = Pos.MAX_COL + end + + return Range.new(start, stop, mode) end --- @param bufnr? number @@ -371,9 +374,15 @@ end function Range:save_to_extmark() local r = self:to_charwise() + local end_row = r.stop.lnum - 1 + local end_col = r.stop.col + if self.mode == 'V' then + end_row = end_row + 1 + end_col = 0 + end local id = vim.api.nvim_buf_set_extmark(r.start.bufnr, NS, r.start.lnum - 1, r.start.col - 1, { - end_row = r.stop.lnum - 1, - end_col = r.stop.col, + end_row = end_row, + end_col = end_col, }) return ExtmarkRange.new(r.start.bufnr, id) end diff --git a/spec/range_spec.lua b/spec/range_spec.lua index 063a890..0a7f46a 100644 --- a/spec/range_spec.lua +++ b/spec/range_spec.lua @@ -627,7 +627,7 @@ describe('Range', function() 'the lazy dog', }, function() -- Construct a range over 'fox jumps' - local r = Range.new(Pos.new(nil, 2, 1), Pos.new(nil, 3, Pos.MAX_COL), 'V') + local r = Range.new(Pos.new(nil, 2, 1), Pos.new(nil, 3, 5), 'v') local extrange = r:save_to_extmark() assert.are.same({ 'fox', 'jumps' }, extrange:range():lines()) -- change 'jumps' to 'leaps': @@ -642,4 +642,29 @@ describe('Range', function() assert.are.same({ 'fox', 'leaps' }, extrange:range():lines()) end) end) + + it('can save linewise extmark', function() + withbuf({ + 'The quick brown', + 'fox', + 'jumps', + 'over', + 'the lazy dog', + }, function() + -- Construct a range over 'fox jumps' + local r = Range.new(Pos.new(nil, 2, 1), Pos.new(nil, 3, Pos.MAX_COL), 'V') + local extrange = r:save_to_extmark() + assert.are.same({ 'fox', 'jumps' }, extrange:range():lines()) + + local extmark = vim.api.nvim_buf_get_extmark_by_id( + extrange.bufnr, + vim.api.nvim_create_namespace 'u.range', + extrange.id, + { details = true } + ) + local row0, col0, details = unpack(extmark) + assert.are.same({ 1, 0 }, { row0, col0 }) + assert.are.same({ 3, 0 }, { details.end_row, details.end_col }) + end) + end) end)