I want to replace the selected Text (in Visual-Mode) with the current Date.
Currently I am trying to call a cmd and then use the 'change' method.
keymap.set("x", "<leader>nf", function()
vim.cmd(string.format("insert\n%s", os.date("%d.%m.%Y")))
end)
All it does right now is to insert the Date in the line above the selection, not deleting it.
The accepted answer uses '< and '>, but these marks have a drawback. They only update when the user (or script) leaves visual mode. An alternative is to use . and v as position arguments for getpos.
You can read more about these position arguments in the help for line(). Briefly, in visual mode, . and v complement each other: . refers to the position of the cursor (this use of . is common in vim and neovim), and v refers to the other end of the visual selection. You can think of v as where v_o would take you if you enter o while in visual mode.
. and v are especially useful in characterwise visual mode, since they are guaranteed to give you the start and end position of the visual selection. (If the cursor is at the end of the visual selection, . refers to the end and v refers to the start of the selection. If the cursor is at the start of the visual selection, . refers to the start and v refers to the end of the selection.)
In any case, adapting GreatGaga's code to use . and v gives you something like this. (I probably overcommented parts of it, but I didn't repeat the useful comments in GreatGaga's version. Check that for the (six!) arguments to nvim_buf_set_text):
local _should_swap = function(s_pos, e_pos)
-- 1. If s_pos is on a line below e_pos, they are reversed.
if s_pos[2] > e_pos[2] then
return true
end
-- 2. If s_pos and e_pos are on the same line, and s_pos
-- is in a later column, they are reversed.
if s_pos[2] == e_pos[2] and s_pos[3] > e_pos[3] then
return true
end
-- 3. If s_pos is on an earlier line than e_pos or the same line
-- but an earlier column, they are not reversed.
return false
end
local function replace_date()
local s_pos = vim.fn.getpos("v")
local e_pos = vim.fn.getpos(".")
-- Depending on where the cursor is, s_pos may initially refer to
-- the end of the visual selection, and e_pos may initially refer
-- to the start. If so, we swap their values.
if _should_swap(s_pos, e_pos) then
s_pos, e_pos = e_pos, s_pos
end
local date = os.date("%d.%m.%Y")
vim.api.nvim_buf_set_text(
s_pos[1],
s_pos[2] - 1,
s_pos[3] - 1,
e_pos[2] - 1,
e_pos[3],
{ date }
)
vim.api.nvim_feedkeys(
vim.api.nvim_replace_termcodes("<Esc>", true, false, true),
"x",
false
)
end
You can use a custom function you need to work with row and column of a selection of a buffer to make it happen. Other option is using the change block from visual selection. See h v_c
v_c)This solution fully removes all text from a selection and inserts a date
local function replace_date()
-- Use unpack to give tuple values a name otherwise you can only use indexing.
-- We are getting line, column, buffer nr etc based on the visual markers here.
local s_buf, s_row, s_col, _ = unpack(vim.fn.getpos("'<"))
local _, e_row, e_col, _ = unpack(vim.fn.getpos("'>"))
local date = os.date("%d.%m.%Y")
-- Indexing into buffer row needs - 1 because lua indexing starts from 1.
-- Column subtracts are just to account for start and end scenarios.
-- We use the positions to fully clear all selected text of a v-block.
vim.api.nvim_buf_set_text(s_buf, e_row - 1, s_col - 1 , e_row - 1, e_col, {})
-- Place date.
vim.api.nvim_buf_set_text(s_buf, s_row - 1, s_col, s_row - 1, s_col, { date })
-- Exit visual mode
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<esc>', true, false, true), 'x', false)
end
-- Bind to visual mode.
vim.keymap.set('v', '\\', replace_date, { noremap = true, silent = true })
When selection is done you can press \ in visual mode to change to date.
This insert date into visual selection but keeps everything in v-block thats after the inserted date.
local function insert_date_v()
local s_buf, s_row, s_col, _ = unpack(vim.fn.getpos("'<"))
local _, e_row, e_col, _ = unpack(vim.fn.getpos("'>"))
local date = os.date("%d.%m.%Y")
-- Keeps trailing visual selection
vim.api.nvim_buf_set_text(s_buf, e_row - 1, s_col - 1 , e_row - 1, e_col - 1, { date })
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<esc>', true, false, true), 'x', false)
end
vim.keymap.set('v', '\\', insert_date_v, { noremap = true, silent = true })
v_cSee :h v_c you can replace text by entering c after selecting a visual block. If you use c while in visual mode followed by\ the function below replaces it. Notice this is bound to insert mode and not visual.
More keystrokes than the earlier solution but maybe less edgecases.
local function insert_date()
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
local date = os.date("%d.%m.%Y")
vim.api.nvim_buf_set_text(0, row - 1, col, row - 1, col, { date })
end
vim.keymap.set('i', '\\', insert_date, { noremap = true, silent = true })
Consider adding leader key to the bindings of above. use :h to check out the methods for tweaking.
Any of these should cover your needs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With