nvim windows support + multicursors

This commit is contained in:
alejo committed 2026-11-06 19:56:13 -03:00
1 parent b6968a10b3
commit 93c97e65e2
10 files changed
+778 -24

No files matched your search

+20 -13
View File
@@ -113,19 +113,26 @@ vim.api.nvim_create_autocmd("FileType", {
})
-- SSH Clipboard Support (OSC 52)
vim.g.clipboard = {
name = 'OSC 52',
copy = {
['+'] = require('vim.ui.clipboard.osc52').copy('+'),
['*'] = require('vim.ui.clipboard.osc52').copy('*'),
},
paste = {
-- We now return BOTH the text and the register type ('v', 'V', or '^V')
-- This restores native p and P line-wise behavior
['+'] = function() return { vim.fn.getreg('"', 1, true), vim.fn.getregtype('"') } end,
['*'] = function() return { vim.fn.getreg('"', 1, true), vim.fn.getregtype('"') } end,
},
}
-- Skipped on native Windows: Neovim's own clipboard provider (win32yank,
-- bundled with the Windows builds) works there for both the terminal and
-- Neovide, whereas OSC 52 can't work at all in Neovide (it isn't a
-- terminal). Over SSH you'd be running the Linux config on the remote
-- machine anyway.
if vim.fn.has('win32') == 0 then
vim.g.clipboard = {
name = 'OSC 52',
copy = {
['+'] = require('vim.ui.clipboard.osc52').copy('+'),
['*'] = require('vim.ui.clipboard.osc52').copy('*'),
},
paste = {
-- We now return BOTH the text and the register type ('v', 'V', or '^V')
-- This restores native p and P line-wise behavior
['+'] = function() return { vim.fn.getreg('"', 1, true), vim.fn.getregtype('"') } end,
['*'] = function() return { vim.fn.getreg('"', 1, true), vim.fn.getregtype('"') } end,
},
}
end
-- GENERAL KEYMAPS --
@@ -82,6 +82,9 @@ local function shared_lib_ext()
end
return '.so'
end
local function exe_ext()
return vim.loop.os_uname().sysname == 'Windows_NT' and '.exe' or ''
end
local function fixture_lib_path()
return build_dir() .. '/tests/' .. shared_lib_prefix() .. 'dynlib_test_fixture' .. shared_lib_ext()
end
@@ -97,7 +100,7 @@ local configurations = {
type = 'codelldb',
request = 'launch',
program = function()
return build_dir() .. '/tests/test_dynamic_library'
return build_dir() .. '/tests/test_dynamic_library' .. exe_ext()
end,
args = function()
return { fixture_lib_path() }
@@ -112,7 +115,7 @@ local configurations = {
type = 'codelldb',
request = 'launch',
program = function()
return build_dir() .. '/demo/example_host'
return build_dir() .. '/demo/example_host' .. exe_ext()
end,
args = function()
return { demo_plugin_path() }
@@ -127,7 +130,7 @@ local configurations = {
type = 'codelldb',
request = 'launch',
program = function()
return build_dir() .. '/demo/example_host'
return build_dir() .. '/demo/example_host' .. exe_ext()
end,
args = function()
local path = vim.fn.input('Plugin path: ', demo_plugin_path(), 'file')
+1 -1
View File
@@ -23,7 +23,7 @@ return {
dashboard.button("r", " Recent Files", "<cmd>Telescope oldfiles<CR>"),
dashboard.button("w", " Live Grep", "<cmd>Telescope live_grep<CR>"),
dashboard.button("e", " New File", "<cmd>ene<CR>"),
dashboard.button("c", " Edit Config", "<cmd>edit ~/.config/nvim/init.lua<CR>"),
dashboard.button("c", " Edit Config", "<cmd>edit " .. vim.fn.fnameescape(vim.fs.normalize(vim.fn.stdpath("config")) .. "/init.lua") .. "<CR>"),
dashboard.button("q", " Quit", "<cmd>qa<CR>"),
}
+8 -1
View File
@@ -62,9 +62,16 @@ return {
-- plain text in connections.json here, password included -- leave the
-- password out of the URL and put it in ~/.my.cnf's [client] section
-- if that bothers you (the mariadb client reads it from there).
-- (On Windows that means %LOCALAPPDATA%\db_ui -- Neovim itself uses
-- %LOCALAPPDATA%\nvim and %LOCALAPPDATA%\nvim-data there, so it's
-- outside both of those too.)
local data_home = vim.env.XDG_DATA_HOME
if not data_home or data_home == "" then
data_home = vim.env.HOME .. "/.local/share"
if vim.fn.has("win32") == 1 then
data_home = vim.env.LOCALAPPDATA or (vim.env.USERPROFILE .. "\\AppData\\Local")
else
data_home = vim.env.HOME .. "/.local/share"
end
end
vim.g.db_ui_save_location = data_home .. "/db_ui"
@@ -0,0 +1,112 @@
return {
-- Multiple cursors (multicursor.nvim). Add cursors, then use Vim
-- normally -- motions, operators, insert mode, macros and undo all act
-- on every cursor at once. Esc collapses back to one cursor.
--
-- The key layout below deliberately differs from the plugin's README
-- example, which would collide with this config: <leader>n/s/S/x clash
-- with the <leader>s* "Splits" group, and bare <Up>/<Down> are normal
-- cursor movement. Instead, the everyday actions sit on Ctrl keys
-- (VS Code-style), and the rest live under a <leader>m "Multicursor"
-- group (registered in which-key.lua) so they show up in the popup.
--
-- <leader>m is NOT also bound to the plugin's own `operator` action
-- (which its README suggests) -- that would make every <leader>m...
-- key ambiguous. `ga{motion}` (below) covers the same ground.
{
"jake-stewart/multicursor.nvim",
branch = "1.0",
event = "VeryLazy",
config = function()
local mc = require("multicursor-nvim")
mc.setup()
local set = vim.keymap.set
-- Add cursors: above / below the main cursor.
set({ "n", "x" }, "<C-Up>", function() mc.lineAddCursor(-1) end, { desc = "Add cursor above" })
set({ "n", "x" }, "<C-Down>", function() mc.lineAddCursor(1) end, { desc = "Add cursor below" })
-- Add cursors: at the next / previous match of the word under the
-- cursor, or of the visual selection (like Ctrl+D in VS Code).
set({ "n", "x" }, "<C-n>", function() mc.matchAddCursor(1) end, { desc = "Add cursor at next match" })
set({ "n", "x" }, "<C-p>", function() mc.matchAddCursor(-1) end, { desc = "Add cursor at previous match" })
-- Add cursors with the mouse: Ctrl+click adds or removes one, and
-- Ctrl+drag adds a column of them. (If your terminal swallows
-- Ctrl+click, use <C-q> below instead.)
set("n", "<C-LeftMouse>", mc.handleMouse, { desc = "Add/remove cursor" })
set("n", "<C-LeftDrag>", mc.handleMouseDrag)
set("n", "<C-LeftRelease>", mc.handleMouseRelease)
-- Disable the cursors so only the main one moves; while disabled,
-- pressing this again drops a cursor at the main cursor's position.
-- Move, press, move, press... places cursors anywhere. <Esc>
-- re-enables them. (Shadows Neovim's <C-q> alias for <C-v>;
-- <C-v> itself is untouched.)
set({ "n", "x" }, "<C-q>", mc.toggleCursor, { desc = "Toggle cursor (place / disable)" })
-- `gaip` adds a cursor on every line of a paragraph (any motion or
-- text object works); in Visual mode, on every selected line.
set({ "n", "x" }, "ga", mc.addCursorOperator, { desc = "Add cursors over motion" })
-- Visual mode: insert at the start / append at the end of every
-- selected line, like a block-selection I/A but for any selection.
set("x", "I", mc.insertVisual, { desc = "Insert on each selected line" })
set("x", "A", mc.appendVisual, { desc = "Append on each selected line" })
-- <leader>m group (see which-key.lua).
set({ "n", "x" }, "<leader>ms", function() mc.matchSkipCursor(1) end, { desc = "Skip next match" })
set({ "n", "x" }, "<leader>mS", function() mc.matchSkipCursor(-1) end, { desc = "Skip previous match" })
set({ "n", "x" }, "<leader>mj", function() mc.lineSkipCursor(1) end, { desc = "Skip line below" })
set({ "n", "x" }, "<leader>mk", function() mc.lineSkipCursor(-1) end, { desc = "Skip line above" })
set({ "n", "x" }, "<leader>ma", mc.matchAllAddCursors, { desc = "Add cursors at ALL matches" })
set("n", "<leader>mr", mc.restoreCursors, { desc = "Restore cleared cursors" })
-- Mappings in a keymap layer only exist while there is more than
-- one cursor, so they can overlap with ordinary mappings.
mc.addKeymapLayer(function(layerSet)
-- Make a different cursor the main one.
layerSet({ "n", "x" }, "<leader>mh", mc.prevCursor, { desc = "Previous cursor" })
layerSet({ "n", "x" }, "<leader>ml", mc.nextCursor, { desc = "Next cursor" })
-- Drop the main cursor, keeping the rest.
layerSet({ "n", "x" }, "<leader>mx", mc.deleteCursor, { desc = "Delete main cursor" })
-- Treat all the cursors as one sequence: 1, 2, 3, ... down the
-- column. Kept in the layer so Vim's own Visual-mode g<C-a> /
-- g<C-x> are untouched when there is only one cursor.
layerSet({ "n", "x" }, "g<C-a>", mc.sequenceIncrement, { desc = "Increment as sequence" })
layerSet({ "n", "x" }, "g<C-x>", mc.sequenceDecrement, { desc = "Decrement as sequence" })
-- Esc: re-enable disabled cursors, otherwise collapse to one. This
-- shadows the global <Esc> (clear search highlight) while the
-- layer is active, so it does that too.
layerSet("n", "<Esc>", function()
vim.cmd.nohlsearch()
if not mc.cursorsEnabled() then
mc.enableCursors()
else
mc.clearCursors()
end
end, { desc = "Collapse cursors" })
end)
-- Cursor look. `reverse` stays visible on any background (this
-- theme is transparent in the terminal), and a theme change would
-- otherwise wipe these, so they're re-applied on ColorScheme.
local function set_highlights()
local hl = vim.api.nvim_set_hl
hl(0, "MultiCursorCursor", { reverse = true })
hl(0, "MultiCursorVisual", { link = "Visual" })
hl(0, "MultiCursorSign", { link = "SignColumn" })
hl(0, "MultiCursorMatchPreview", { link = "Search" })
hl(0, "MultiCursorDisabledCursor", { reverse = true })
hl(0, "MultiCursorDisabledVisual", { link = "Visual" })
hl(0, "MultiCursorDisabledSign", { link = "SignColumn" })
end
set_highlights()
vim.api.nvim_create_autocmd("ColorScheme", { callback = set_highlights })
end,
},
}
+48 -3
View File
@@ -1,3 +1,48 @@
-- Recursive copy used by the gM mapping below. Unix keeps using `cp -r`
-- (unchanged behavior); Windows has no `cp`, so it gets an equivalent
-- written against libuv. One difference there: if the destination
-- directory already exists, contents are merged into it rather than the
-- source being nested inside it, which is what `cp -r` would do.
-- Returns true on success, or false plus an error message.
local function copy_path(src, dest)
if vim.fn.has("win32") == 0 then
local result = vim.fn.system({ "cp", "-r", src, dest })
return vim.v.shell_error == 0, result
end
local uv = vim.uv or vim.loop
local function copy(s, d)
local stat = uv.fs_stat(s)
if not stat then
return false, "no such file or directory: " .. s
end
if stat.type == "directory" then
local made, mkerr = uv.fs_mkdir(d, 493) -- 0755
if not made then
local existing = uv.fs_stat(d)
if not (existing and existing.type == "directory") then
return false, mkerr
end
end
local handle = uv.fs_scandir(s)
while handle do
local name = uv.fs_scandir_next(handle)
if not name then
break
end
local ok, err = copy(s .. "/" .. name, d .. "/" .. name)
if not ok then
return false, err
end
end
return true
end
local ok, err = uv.fs_copyfile(s, d)
return ok and true or false, err
end
return copy(src, dest)
end
return {
-- NvimTree (On the right)
{
@@ -198,9 +243,9 @@ return {
-- instead of surfacing cp's raw "same file" error.
vim.notify("Skipped " .. base .. ": pattern didn't match, and destination is the same as source", vim.log.levels.WARN)
else
local result = vim.fn.system({ "cp", "-r", node.absolute_path, dest_path })
if vim.v.shell_error ~= 0 then
vim.notify("Copy failed for " .. base .. ": " .. result, vim.log.levels.ERROR)
local copied, result = copy_path(node.absolute_path, dest_path)
if not copied then
vim.notify("Copy failed for " .. base .. ": " .. tostring(result), vim.log.levels.ERROR)
end
end
end
+11 -1
View File
@@ -9,8 +9,18 @@ return {
-- built in (paths, directory contents, and history) with zero
-- config -- accept with -> or <End>. This only affects terminals
-- opened from Neovim; your system login shell is untouched.
--
-- Windows: fish has no native Windows build, so the terminal
-- launches PowerShell 7 (pwsh) instead -- it has the same kind of
-- grey inline prediction (PSReadLine, from command history) on by
-- default -- falling back to Windows PowerShell 5.1 if pwsh isn't
-- installed. setup_neovim.ps1 installs pwsh.
local shell = "fish"
if vim.fn.has("win32") == 1 then
shell = vim.fn.executable("pwsh") == 1 and "pwsh" or "powershell"
end
require("toggleterm").setup({
shell = "fish",
shell = shell,
})
vim.keymap.set('n', '<leader>tf', '<cmd>ToggleTerm direction=float<cr>', { desc = "Floating Terminal" })
vim.keymap.set('n', '<leader>th', '<cmd>ToggleTerm direction=horizontal<cr>', { desc = "Bottom Terminal" })
@@ -14,6 +14,7 @@ return {
{ "<leader>c", group = "Comments" },
{ "<leader>f", group = "Find / Grep" },
{ "<leader>l", group = "LSP" },
{ "<leader>m", group = "Multicursor" },
{ "<leader>o", group = "OOP" },
{ "<leader>s", group = "Splits" },
{ "<leader>t", group = "Terminal" },