Search code examples
luaneovimkeymapping

Replace selected Text with String, via Keymap


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.


Solution

  • 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

    Replace visual selection with date (not 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.

    Insert into visual block keeping trailing text

    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 })
    

    Use v_c

    See :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.