diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 2f935f0882..53636d6205 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -4539,6 +4539,14 @@ lsp({buf}, {pos}, {position_encoding}) *vim.pos.lsp()* • {pos} (`lsp.Position`) • {position_encoding} (`lsp.PositionEncodingKind`) +mark({buf}, {row}, {col}) *vim.pos.mark()* + Creates a new |vim.Pos| from mark position (see |api-indexing|). + + Parameters: ~ + • {buf} (`integer`) + • {row} (`integer`) + • {col} (`integer`) + offset({buf}, {offset}) *vim.pos.offset()* Creates a new |vim.Pos| from buffer offset. @@ -4583,6 +4591,16 @@ to_lsp({pos}, {position_encoding}) *vim.pos.to_lsp()* • {pos} (`vim.Pos`) See |vim.Pos|. • {position_encoding} (`lsp.PositionEncodingKind`) +to_mark({pos}) *vim.pos.to_mark()* + Converts |vim.Pos| to mark position (see |api-indexing|). + + Parameters: ~ + • {pos} (`vim.Pos`) See |vim.Pos|. + + Return (multiple): ~ + (`integer`) + (`integer`) + to_offset({pos}) *vim.pos.to_offset()* Converts |vim.Pos| to buffer offset. @@ -4719,6 +4737,26 @@ lsp({buf}, {range}, {position_encoding}) *vim.range.lsp()* • {range} (`lsp.Range`) • {position_encoding} (`lsp.PositionEncodingKind`) + *vim.range.mark()* +mark({buf}, {start_row}, {start_col}, {end_row}, {end_col}) + Creates a new |vim.Range| from "mark-indexed" range (see |api-indexing|). + + Example: >lua + -- A range represented by marks may be end-inclusive (decided by 'selection' option). + local start_row, start_col = unpack(api.nvim_buf_get_mark(bufnr, '<')) + local end_row, end_col = unpack(api.nvim_buf_get_mark(bufnr, '>')) + + -- Create an end-exclusive range. + local range = vim.range.mark(0, start_row, start_col, end_row, end_col) +< + + Parameters: ~ + • {buf} (`integer`) + • {start_row} (`integer`) + • {start_col} (`integer`) + • {end_row} (`integer`) + • {end_col} (`integer`) + to_cursor({range}) *vim.range.to_cursor()* Converts |vim.Range| to mark-like range (see |api-indexing|). @@ -4762,6 +4800,25 @@ to_lsp({range}, {position_encoding}) *vim.range.to_lsp()* Return: ~ (`lsp.Range`) +to_mark({range}) *vim.range.to_mark()* + Converts |vim.Range| to extmark range (see |api-indexing|). + + Example: >lua + local range = vim.range(0, 3, 5, 4, 0) + + -- Convert to mark range, you can call it in a method style. + local start_row, start_col, end_row, end_col = range:to_mark() +< + + Parameters: ~ + • {range} (`vim.Range`) See |vim.Range|. + + Return (multiple): ~ + (`integer`) + (`integer`) + (`integer`) + (`integer`) + ============================================================================== Lua module: vim.re *vim.re* diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 1d7dc96b79..0fc47843cb 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -203,6 +203,7 @@ LUA • |vim.log| for easily creating loggers. • |vim.pack.get()| output includes revision of a pending update. • |vim.pack.get()| can fetch new updates before computing the output. +• |vim.pos| and |vim.range| can now convert between mark positions. OPTIONS diff --git a/runtime/lua/vim/pos.lua b/runtime/lua/vim/pos.lua index e5d0d4c84e..a37353f736 100644 --- a/runtime/lua/vim/pos.lua +++ b/runtime/lua/vim/pos.lua @@ -291,6 +291,25 @@ function M.cursor(buf, pos) return M.new(buf, pos[1] - 1, pos[2]) end +--- Converts |vim.Pos| to mark position (see |api-indexing|). +---@param pos vim.Pos +---@return integer, integer +function M.to_mark(pos) + return pos[1] + 1, pos[2] +end + +--- Creates a new |vim.Pos| from mark position (see |api-indexing|). +---@param buf integer +---@param row integer +---@param col integer +function M.mark(buf, row, col) + if buf == 0 then + buf = api.nvim_get_current_buf() + end + + return M.new(buf, row - 1, col) +end + --- Converts |vim.Pos| to extmark position (see |api-indexing|). ---@param pos vim.Pos ---@return integer, integer diff --git a/runtime/lua/vim/range.lua b/runtime/lua/vim/range.lua index f50aff60b4..dd22d1151e 100644 --- a/runtime/lua/vim/range.lua +++ b/runtime/lua/vim/range.lua @@ -160,6 +160,21 @@ local function to_inclusive_pos(buf, row, col) return row, col end +---@param row integer +---@param col integer +---@param buf integer +---@return integer, integer +local function to_exclusive_pos(buf, row, col) + if col >= #get_line(buf, row) then + row = row + 1 + col = 0 + else + col = col + 1 + end + + return row, col +end + ---@private ---@param r1 vim.Range ---@param r2 vim.Range @@ -314,6 +329,67 @@ function M.lsp(buf, range, position_encoding) return M.new(start, end_) end +--- Converts |vim.Range| to extmark range (see |api-indexing|). +--- +--- Example: +--- ```lua +--- local range = vim.range(0, 3, 5, 4, 0) +--- +--- -- Convert to mark range, you can call it in a method style. +--- local start_row, start_col, end_row, end_col = range:to_mark() +--- ``` +---@param range vim.Range +---@return integer, integer, integer, integer +function M.to_mark(range) + validate('range', range, 'table') + + local buf = range.buf + local start_row, start_col, end_row, end_col = range[1], range[2], range[3], range[4] + if vim.o.selection ~= 'exclusive' then + end_row, end_col = to_inclusive_pos(buf, end_row, end_col) + end + + start_row, start_col = vim.pos(buf, start_row, start_col):to_mark() + end_row, end_col = vim.pos(buf, end_row, end_col):to_mark() + return start_row, start_col, end_row, end_col +end + +--- Creates a new |vim.Range| from "mark-indexed" range (see |api-indexing|). +--- +--- Example: +--- ```lua +--- -- A range represented by marks may be end-inclusive (decided by 'selection' option). +--- local start_row, start_col = unpack(api.nvim_buf_get_mark(bufnr, '<')) +--- local end_row, end_col = unpack(api.nvim_buf_get_mark(bufnr, '>')) +--- +--- -- Create an end-exclusive range. +--- local range = vim.range.mark(0, start_row, start_col, end_row, end_col) +--- ``` +---@param buf integer +---@param start_row integer +---@param start_col integer +---@param end_row integer +---@param end_col integer +function M.mark(buf, start_row, start_col, end_row, end_col) + validate('buf', buf, 'number') + validate('start_row', start_row, 'number') + validate('start_col', start_col, 'number') + validate('end_row', end_row, 'number') + validate('end_col', end_col, 'number') + + if buf == 0 then + buf = api.nvim_get_current_buf() + end + + local start = vim.pos.mark(buf, start_row, start_col) + local end_ = vim.pos.mark(buf, end_row, end_col) + + if vim.o.selection ~= 'exclusive' then + end_[1], end_[2] = to_exclusive_pos(buf, end_[1], end_[2]) + end + return M.new(start, end_) +end + --- Converts |vim.Range| to extmark range (see |api-indexing|). --- --- Example: