Copy to clipboard, extra line break fixed

This commit is contained in:
psychhim
2025-10-06 21:32:47 +05:30
parent 289772ff82
commit d0d51bca27
2 changed files with 73 additions and 42 deletions

View File

@@ -0,0 +1,12 @@
local M = {}
function M.trim_clipboard()
local content = vim.fn.getreg '+'
-- Remove single trailing newline if present
content = content:gsub('\n$', '')
vim.fn.setreg('+', content)
vim.fn.setreg('*', content)
vim.notify('Copied to clipboard', vim.log.levels.INFO)
end
return M

View File

@@ -2,14 +2,13 @@
vim.keymap.set('v', 'J', ":m '<+1<CR>gv=gv") vim.keymap.set('v', 'J', ":m '<+1<CR>gv=gv")
vim.keymap.set('v', 'K', ":m '<-2<CR>gv=gv") vim.keymap.set('v', 'K', ":m '<-2<CR>gv=gv")
vim.keymap.set('n', 'J', 'mzJ`z') vim.keymap.set('n', 'J', 'mzJ`z')
vim.keymap.set('n', 'J', 'mzJ`z')
vim.keymap.set('n', '<leader>j', '<C-d>zz', { desc = 'Scroll down and center cursor' }) vim.keymap.set('n', '<leader>j', '<C-d>zz', { desc = 'Scroll down and center cursor' })
vim.keymap.set('n', '<leader>k', '<C-u>zz', { desc = 'Scroll up and center cursor' }) vim.keymap.set('n', '<leader>k', '<C-u>zz', { desc = 'Scroll up and center cursor' })
vim.keymap.set('n', 'n', 'nzzzv') vim.keymap.set('n', 'n', 'nzzzv')
vim.keymap.set('n', 'N', 'Nzzzv') vim.keymap.set('n', 'N', 'Nzzzv')
vim.keymap.set('x', '<leader>p', '"_dP', { desc = 'Paste over selection without yanking' }) vim.keymap.set('x', '<leader>p', '"_dP', { desc = 'Paste over selection without yanking' })
-- Replace all occurrences of the word under cursor -- [[ Replace all occurrences of the word under cursor ]]
vim.keymap.set('n', '<leader>F', function() vim.keymap.set('n', '<leader>F', function()
-- Save current cursor position -- Save current cursor position
local pos = vim.api.nvim_win_get_cursor(0) local pos = vim.api.nvim_win_get_cursor(0)
@@ -27,50 +26,48 @@ vim.keymap.set('n', '<leader>F', function()
end, { desc = 'Replace all occurrences of word under cursor' }) end, { desc = 'Replace all occurrences of word under cursor' })
-- [[ Basic Keymaps ]] -- [[ Basic Keymaps ]]
-- Keymaps for better default experience -- Keymaps for better default experience
-- See `:help vim.keymap.set()` -- See `:help vim.keymap.set()`
vim.keymap.set({ 'n', 'v' }, '<Space>', '<Nop>', { silent = true }) vim.keymap.set({ 'n', 'v' }, '<Space>', '<Nop>', { silent = true })
-- Remap for dealing with word wrap -- [[ Remap for dealing with word wrap ]]
vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true }) vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true })
vim.keymap.set('n', 'j', "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true }) vim.keymap.set('n', 'j', "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true })
-- Diagnostic keymaps -- [[ Diagnostic keymaps ]]
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = 'Go to previous diagnostic message' }) vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = 'Go to previous diagnostic message' })
vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = 'Go to next diagnostic message' }) vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = 'Go to next diagnostic message' })
vim.keymap.set('n', '<leader>de', vim.diagnostic.open_float, { desc = 'Diagnostics: floating message' }) vim.keymap.set('n', '<leader>de', vim.diagnostic.open_float, { desc = 'Diagnostics: floating message' })
vim.keymap.set('n', '<leader>dq', vim.diagnostic.setloclist, { desc = 'Diagnostics: location list' }) vim.keymap.set('n', '<leader>dq', vim.diagnostic.setloclist, { desc = 'Diagnostics: location list' })
-- [[ Custom keymaps ]] -- [[ Custom keymaps ]]
-- [[ Neo-tree sync to current directory & toggle ]]
-- Neo-tree sync to current directory & toggle
vim.keymap.set('n', '<leader>n', '<Cmd>cd %:p:h | Neotree toggle float<CR>') vim.keymap.set('n', '<leader>n', '<Cmd>cd %:p:h | Neotree toggle float<CR>')
-- Terminal open in new tab -- [[ Terminal open in new tab ]]
vim.keymap.set('n', '<leader>t', '<Cmd>tabnew +term<CR>i') vim.keymap.set('n', '<leader>t', '<Cmd>tabnew +term<CR>i')
-- Create an empty buffer in a new tab -- [[ Create an empty buffer in a new tab ]]
vim.keymap.set('n', '<Leader>e', function() vim.keymap.set('n', '<Leader>e', function()
vim.cmd 'tabnew' -- create a new tab vim.cmd 'tabnew' -- create a new tab
vim.cmd 'enew' -- create a new empty buffer in it vim.cmd 'enew' -- create a new empty buffer in it
end, { noremap = true, silent = true }) end, { noremap = true, silent = true })
-- Horizontal split with new empty buffer below -- [[ Horizontal split with new empty buffer below ]]
vim.keymap.set('n', '<leader>sv', function() vim.keymap.set('n', '<leader>sv', function()
vim.cmd 'split' -- create horizontal split (above by default) vim.cmd 'split' -- create horizontal split (above by default)
vim.cmd 'wincmd j' -- move to the new split below vim.cmd 'wincmd j' -- move to the new split below
vim.cmd 'enew' -- open new empty buffer vim.cmd 'enew' -- open new empty buffer
end, { desc = 'New buffer in horizontal split (below)' }) end, { desc = 'New buffer in horizontal split (below)' })
-- Vertical split with new empty buffer to the right -- [[ Vertical split with new empty buffer to the right ]]
vim.keymap.set('n', '<leader>sh', function() vim.keymap.set('n', '<leader>sh', function()
vim.cmd 'vsplit' -- create vertical split (left by default) vim.cmd 'vsplit' -- create vertical split (left by default)
vim.cmd 'wincmd l' -- move to the new split to the right vim.cmd 'wincmd l' -- move to the new split to the right
vim.cmd 'enew' -- open new empty buffer vim.cmd 'enew' -- open new empty buffer
end, { desc = 'New buffer in vertical split (right)' }) end, { desc = 'New buffer in vertical split (right)' })
-- Save current buffer (asks for filename if new/unsaved) -- [[ Save current buffer (asks for filename if new/unsaved) ]]
vim.keymap.set('n', '<leader>w', function() vim.keymap.set('n', '<leader>w', function()
if vim.api.nvim_buf_get_name(0) == '' then if vim.api.nvim_buf_get_name(0) == '' then
-- Ask user for a filename -- Ask user for a filename
@@ -85,7 +82,7 @@ vim.keymap.set('n', '<leader>w', function()
end end
end, { desc = 'Save buffer (prompt if new file)' }) end, { desc = 'Save buffer (prompt if new file)' })
-- Close current window (asks if buffer is unsaved) -- [[ Close current window (asks if buffer is unsaved) ]]
vim.keymap.set('n', '<leader>q', function() vim.keymap.set('n', '<leader>q', function()
if vim.bo.modified then if vim.bo.modified then
local choice = vim.fn.input 'Buffer modified! Save (y), Discard (n), Cancel (any other key)? ' local choice = vim.fn.input 'Buffer modified! Save (y), Discard (n), Cancel (any other key)? '
@@ -111,7 +108,7 @@ vim.keymap.set('n', '<leader>q', function()
end end
end, { desc = 'Close buffer (prompt if modified)' }) end, { desc = 'Close buffer (prompt if modified)' })
-- Save changes and close current window (asks for filename if new/unsaved) -- [[ Save changes and close current window (asks for filename if new/unsaved) ]]
vim.keymap.set('n', '<leader>qy', function() vim.keymap.set('n', '<leader>qy', function()
if vim.api.nvim_buf_get_name(0) == '' then if vim.api.nvim_buf_get_name(0) == '' then
-- Ask user for a filename -- Ask user for a filename
@@ -127,38 +124,68 @@ vim.keymap.set('n', '<leader>qy', function()
end end
end, { desc = 'Save & quit (prompt if new file)' }) end, { desc = 'Save & quit (prompt if new file)' })
-- Discard changes and Close current window -- [[ Discard changes and Close current window ]]
vim.keymap.set('n', '<leader>qn', '<Cmd>q!<CR>') vim.keymap.set('n', '<leader>qn', '<Cmd>q!<CR>')
-- Switch below/right split windows -- [[ Switch below/right split windows ]]
vim.keymap.set('n', '<leader><Tab>', '<C-W><C-W>') vim.keymap.set('n', '<leader><Tab>', '<C-W><C-W>')
-- Switch above/left split windows -- [[ Switch above/left split windows ]]
vim.keymap.set('n', '<Tab>', '<C-W>W') vim.keymap.set('n', '<Tab>', '<C-W>W')
-- Select all -- [[ Select all ]]
vim.keymap.set('n', '<leader>ll', 'ggVG') vim.keymap.set('n', '<leader>ll', 'ggVG', { desc = 'Select all' })
-- Select all and copy to clipboard -- [[ Select all and copy to clipboard ]]
vim.keymap.set('n', '<leader>lY', 'ggVG"+y') vim.keymap.set('n', '<leader>lY', function()
-- Get all lines from the buffer
local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
-- Join them without adding an extra newline
local content = table.concat(lines, '\n')
-- Set to system clipboard
vim.fn.setreg('+', content)
vim.fn.setreg('*', content)
-- Notify
vim.schedule(function()
vim.notify('Copied all to clipboard', vim.log.levels.INFO)
end)
end, { desc = 'Copy all to clipboard' })
-- Copy to clipboard a single line -- [[ Copy to clipboard ]]
vim.keymap.set('n', 'Y', '"+yy') -- Normal mode: copy current line
vim.keymap.set('n', 'Y', function()
local line = vim.api.nvim_get_current_line()
vim.fn.setreg('+', line)
vim.fn.setreg('*', line)
vim.schedule(function()
vim.notify('Copied to clipboard', vim.log.levels.INFO)
end)
end)
-- Visual mode: copy selection, trim trailing newline if needed
vim.keymap.set('x', 'Y', [["+y<esc>:lua require("copy_to_clipboard_fix").trim_clipboard()<CR>]])
-- Copy to clipboard selected text in Visual mode -- [[ Paste from clipboard ]]
vim.keymap.set('v', 'Y', '"+y') local function paste_from_clipboard()
local mode = vim.fn.mode()
if mode == 'v' or mode == 'V' or mode == '\22' then
-- Visual mode: paste without yanking selection
vim.cmd 'normal! "_d"+P'
else
-- Normal mode: paste at cursor position
vim.cmd 'normal! "+P'
end
end
-- In normal and visual modes
vim.keymap.set('n', '<leader>P', paste_from_clipboard, { desc = 'Paste from clipboard at cursor' })
vim.keymap.set('x', '<leader>P', paste_from_clipboard, { desc = 'Paste from clipboard without yanking selection' })
-- Paste from clipboard -- [[ Redo ]]
vim.keymap.set('n', '<leader>P', '"+p')
-- Redo
vim.keymap.set('n', 'U', '<C-r>') vim.keymap.set('n', 'U', '<C-r>')
-- Smart Open current buffers for Telescope (switch to already open buffer) -- [[ Smart Open current buffers for Telescope (switch to already open buffer) ]]
local actions = require 'telescope.actions' local actions = require 'telescope.actions'
local action_state = require 'telescope.actions.state' local action_state = require 'telescope.actions.state'
local builtin = require 'telescope.builtin' local builtin = require 'telescope.builtin'
local function smart_open_buffer() local function smart_open_buffer()
builtin.buffers { builtin.buffers {
attach_mappings = function(_, map) attach_mappings = function(_, map)
@@ -168,12 +195,10 @@ local function smart_open_buffer()
return return
end end
actions.close(prompt_bufnr) actions.close(prompt_bufnr)
local bufname = vim.api.nvim_buf_get_name(entry.bufnr) local bufname = vim.api.nvim_buf_get_name(entry.bufnr)
if bufname == '' then if bufname == '' then
return return
end end
-- Check all windows in current tab -- Check all windows in current tab
local current_tab = vim.api.nvim_get_current_tabpage() local current_tab = vim.api.nvim_get_current_tabpage()
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(current_tab)) do for _, win in ipairs(vim.api.nvim_tabpage_list_wins(current_tab)) do
@@ -183,7 +208,6 @@ local function smart_open_buffer()
return return
end end
end end
-- Check other tabs -- Check other tabs
for _, tab in ipairs(vim.api.nvim_list_tabpages()) do for _, tab in ipairs(vim.api.nvim_list_tabpages()) do
if tab ~= current_tab then if tab ~= current_tab then
@@ -198,11 +222,9 @@ local function smart_open_buffer()
end end
end end
end end
-- Not open anywhere → open in current window -- Not open anywhere → open in current window
vim.cmd('buffer ' .. entry.bufnr) vim.cmd('buffer ' .. entry.bufnr)
end end
map('i', '<CR>', open_selected) map('i', '<CR>', open_selected)
map('n', '<CR>', open_selected) map('n', '<CR>', open_selected)
return true return true
@@ -216,13 +238,12 @@ require('which-key').register {
['<leader><leader>'] = { smart_open_buffer, 'Switch to Open Buffers' }, ['<leader><leader>'] = { smart_open_buffer, 'Switch to Open Buffers' },
} }
-- Smart open a file path, reusing empty buffers or tabs if possible -- [[ Smart open a file path, reusing empty buffers or tabs if possible ]]
local function smart_open_file(path) local function smart_open_file(path)
if not path or path == '' then if not path or path == '' then
return return
end end
path = vim.fn.fnamemodify(path, ':p') -- make absolute path = vim.fn.fnamemodify(path, ':p') -- make absolute
-- 1. If file is already open → jump to it -- 1. If file is already open → jump to it
for _, tab in ipairs(vim.api.nvim_list_tabpages()) do for _, tab in ipairs(vim.api.nvim_list_tabpages()) do
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tab)) do for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tab)) do
@@ -234,7 +255,6 @@ local function smart_open_file(path)
end end
end end
end end
-- 2. If current tab has an empty "No Name" buffer → reuse it -- 2. If current tab has an empty "No Name" buffer → reuse it
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
local buf = vim.api.nvim_win_get_buf(win) local buf = vim.api.nvim_win_get_buf(win)
@@ -247,12 +267,11 @@ local function smart_open_file(path)
return return
end end
end end
-- 3. Otherwise → open in a new tab -- 3. Otherwise → open in a new tab
vim.cmd('tabedit ' .. vim.fn.fnameescape(path)) vim.cmd('tabedit ' .. vim.fn.fnameescape(path))
end end
-- Remap gf to use smart_open_file -- [[ Remap gf to use smart_open_file ]]
vim.keymap.set('n', 'gf', function() vim.keymap.set('n', 'gf', function()
local path = vim.fn.expand '<cfile>' -- get file under cursor local path = vim.fn.expand '<cfile>' -- get file under cursor
smart_open_file(path) smart_open_file(path)