From d0d51bca274b93cc374c6b1bffb33dc5b7aef2e9 Mon Sep 17 00:00:00 2001 From: psychhim Date: Mon, 6 Oct 2025 21:32:47 +0530 Subject: [PATCH] Copy to clipboard, extra line break fixed --- lua/copy_to_clipboard_fix.lua | 12 ++++ lua/keymaps.lua | 103 ++++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 42 deletions(-) create mode 100644 lua/copy_to_clipboard_fix.lua diff --git a/lua/copy_to_clipboard_fix.lua b/lua/copy_to_clipboard_fix.lua new file mode 100644 index 0000000..6e42864 --- /dev/null +++ b/lua/copy_to_clipboard_fix.lua @@ -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 diff --git a/lua/keymaps.lua b/lua/keymaps.lua index 072c89b..4b93fff 100644 --- a/lua/keymaps.lua +++ b/lua/keymaps.lua @@ -1,15 +1,14 @@ --- [[ Few useful keymaps]] +-- [[ Few useful keymaps ]] vim.keymap.set('v', 'J', ":m '<+1gv=gv") vim.keymap.set('v', 'K', ":m '<-2gv=gv") vim.keymap.set('n', 'J', 'mzJ`z') -vim.keymap.set('n', 'J', 'mzJ`z') vim.keymap.set('n', 'j', 'zz', { desc = 'Scroll down and center cursor' }) vim.keymap.set('n', 'k', 'zz', { desc = 'Scroll up and center cursor' }) vim.keymap.set('n', 'n', 'nzzzv') vim.keymap.set('n', 'N', 'Nzzzv') vim.keymap.set('x', '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', 'F', function() -- Save current cursor position local pos = vim.api.nvim_win_get_cursor(0) @@ -27,50 +26,48 @@ vim.keymap.set('n', 'F', function() end, { desc = 'Replace all occurrences of word under cursor' }) -- [[ Basic Keymaps ]] - -- Keymaps for better default experience -- See `:help vim.keymap.set()` vim.keymap.set({ 'n', 'v' }, '', '', { 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', '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_next, { desc = 'Go to next diagnostic message' }) vim.keymap.set('n', 'de', vim.diagnostic.open_float, { desc = 'Diagnostics: floating message' }) vim.keymap.set('n', 'dq', vim.diagnostic.setloclist, { desc = 'Diagnostics: location list' }) -- [[ Custom keymaps ]] - --- Neo-tree sync to current directory & toggle +-- [[ Neo-tree sync to current directory & toggle ]] vim.keymap.set('n', 'n', 'cd %:p:h | Neotree toggle float') --- Terminal open in new tab +-- [[ Terminal open in new tab ]] vim.keymap.set('n', 't', 'tabnew +termi') --- Create an empty buffer in a new tab +-- [[ Create an empty buffer in a new tab ]] vim.keymap.set('n', 'e', function() vim.cmd 'tabnew' -- create a new tab vim.cmd 'enew' -- create a new empty buffer in it end, { noremap = true, silent = true }) --- Horizontal split with new empty buffer below +-- [[ Horizontal split with new empty buffer below ]] vim.keymap.set('n', 'sv', function() vim.cmd 'split' -- create horizontal split (above by default) vim.cmd 'wincmd j' -- move to the new split below vim.cmd 'enew' -- open new empty buffer 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', 'sh', function() vim.cmd 'vsplit' -- create vertical split (left by default) vim.cmd 'wincmd l' -- move to the new split to the right vim.cmd 'enew' -- open new empty buffer 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', 'w', function() if vim.api.nvim_buf_get_name(0) == '' then -- Ask user for a filename @@ -85,7 +82,7 @@ vim.keymap.set('n', 'w', function() end 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', 'q', function() if vim.bo.modified then local choice = vim.fn.input 'Buffer modified! Save (y), Discard (n), Cancel (any other key)? ' @@ -111,7 +108,7 @@ vim.keymap.set('n', 'q', function() end 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', 'qy', function() if vim.api.nvim_buf_get_name(0) == '' then -- Ask user for a filename @@ -127,38 +124,68 @@ vim.keymap.set('n', 'qy', function() end end, { desc = 'Save & quit (prompt if new file)' }) --- Discard changes and Close current window +-- [[ Discard changes and Close current window ]] vim.keymap.set('n', 'qn', 'q!') --- Switch below/right split windows +-- [[ Switch below/right split windows ]] vim.keymap.set('n', '', '') --- Switch above/left split windows +-- [[ Switch above/left split windows ]] vim.keymap.set('n', '', 'W') --- Select all -vim.keymap.set('n', 'll', 'ggVG') +-- [[ Select all ]] +vim.keymap.set('n', 'll', 'ggVG', { desc = 'Select all' }) --- Select all and copy to clipboard -vim.keymap.set('n', 'lY', 'ggVG"+y') +-- [[ Select all and copy to clipboard ]] +vim.keymap.set('n', '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 -vim.keymap.set('n', 'Y', '"+yy') +-- [[ Copy to clipboard ]] +-- 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:lua require("copy_to_clipboard_fix").trim_clipboard()]]) --- Copy to clipboard selected text in Visual mode -vim.keymap.set('v', 'Y', '"+y') +-- [[ Paste from clipboard ]] +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', 'P', paste_from_clipboard, { desc = 'Paste from clipboard at cursor' }) +vim.keymap.set('x', 'P', paste_from_clipboard, { desc = 'Paste from clipboard without yanking selection' }) --- Paste from clipboard -vim.keymap.set('n', 'P', '"+p') - --- Redo +-- [[ Redo ]] vim.keymap.set('n', 'U', '') --- 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 action_state = require 'telescope.actions.state' local builtin = require 'telescope.builtin' - local function smart_open_buffer() builtin.buffers { attach_mappings = function(_, map) @@ -168,12 +195,10 @@ local function smart_open_buffer() return end actions.close(prompt_bufnr) - local bufname = vim.api.nvim_buf_get_name(entry.bufnr) if bufname == '' then return end - -- Check all windows in current tab local current_tab = vim.api.nvim_get_current_tabpage() for _, win in ipairs(vim.api.nvim_tabpage_list_wins(current_tab)) do @@ -183,7 +208,6 @@ local function smart_open_buffer() return end end - -- Check other tabs for _, tab in ipairs(vim.api.nvim_list_tabpages()) do if tab ~= current_tab then @@ -198,11 +222,9 @@ local function smart_open_buffer() end end end - -- Not open anywhere → open in current window vim.cmd('buffer ' .. entry.bufnr) end - map('i', '', open_selected) map('n', '', open_selected) return true @@ -216,13 +238,12 @@ require('which-key').register { [''] = { 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) if not path or path == '' then return end path = vim.fn.fnamemodify(path, ':p') -- make absolute - -- 1. If file is already open → jump to it for _, tab in ipairs(vim.api.nvim_list_tabpages()) 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 - -- 2. If current tab has an empty "No Name" buffer → reuse it for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do local buf = vim.api.nvim_win_get_buf(win) @@ -247,12 +267,11 @@ local function smart_open_file(path) return end end - -- 3. Otherwise → open in a new tab vim.cmd('tabedit ' .. vim.fn.fnameescape(path)) end --- Remap gf to use smart_open_file +-- [[ Remap gf to use smart_open_file ]] vim.keymap.set('n', 'gf', function() local path = vim.fn.expand '' -- get file under cursor smart_open_file(path)