diff --git a/lua/config/keymaps.lua b/lua/config/keymaps.lua index b59c791..1b0f11c 100644 --- a/lua/config/keymaps.lua +++ b/lua/config/keymaps.lua @@ -14,6 +14,7 @@ local data = require("data") -- Add keymapper function local add_keymap = data.func.add_keymap +-- local add_km = require("which-key").add -- ━━━━━━━━━━━━━━━━━━━━━━━━━━ General Keybinds ━━━━━━━━━━━━━━━━━━━━━━━ -- Add keymaps for miscellaneous keybinds @@ -49,6 +50,18 @@ end -- Add keymaps for overrides add_keymap(data.keys.overrides) +-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━ Custom Mappings ━━━━━━━━━━━━━━━━━━━━━━━━━━━ +-- Visual mode: Move selected block of text up +add_keymap("K", function() + data.func.move_visual(true) +end, "Move block of text up", "v") + +-- Visual mode: Move selected block of text down +add_keymap("J", function() + data.func.move_visual(false) +end, "Move block of text down", "v") + +-- Test Prompt: Enter your name add_keymap("qP", function() data.func.InputPrompt("Enter your name: ", function(input) if input then diff --git a/lua/data/func.lua b/lua/data/func.lua index 889ad47..439bb97 100644 --- a/lua/data/func.lua +++ b/lua/data/func.lua @@ -404,6 +404,57 @@ function M.InputPrompt(prompt, callback) end end +---@function Function to move blocks of text up and down +---@param up? boolean Whether to move the blocks up or down +--- Ex: Move selected block of text up: move_visual(true) +--- Move selected block of text down: move_visual(false) +---@param multiplier? integer The number of times to move the blocks +--- Ex: Move selected block of text up 3 times: move_visual(true, 3) +--- Move selected block of text down 2 times: move_visual(false, 2) +---@return nil +function M.move_visual(up, multiplier) + -- Handle parameter + local offset = 1 + if up then + offset = -2 + end + if multiplier then + offset = offset * multiplier + end + + -- escape visual mode + vim.cmd("norm v") + + -- GET REGION + -- eg region = { [103] = {0,-1}, [104] = {0,-1}, [105] = {0,-1}} + ---@diagnostic disable-next-line: deprecated + local region = vim.region(0, "'<", "'>", vim.fn.visualmode(), true) + + local function array_keys(array) + local keys = {} + for k in pairs(array) do + table.insert(keys, k) + end + return keys + end + + -- GET LINES + -- eg lines = { 103, 104, 105 } + local lines = array_keys(region) + table.sort(lines) + + -- GET TOP/BOTTOM LINE NUMBERS + local top = lines[1] + 1 + local bottom = lines[#lines] + 1 + + -- EXECUTE + local new_pos = offset > 0 and bottom + offset or top + offset + vim.cmd(string.format("silent %d, %d move %d", top, bottom, new_pos)) + -- eg :silent 104, 106 move 107 + + vim.cmd("norm gv") +end + ---@function Function to reload the user's Neovim configuration ---@return nil function M.reload_config() @@ -505,13 +556,14 @@ end --- Options: --- - string: The name of the plugin module to check. --- - table: A list of plugin modules to check. +---@param simple boolean|nil Whether to use a simple check (pcall(require, plugin)). ---@return boolean|table condition The installed state of the plugin(s). --- - boolean: The installed state of the plugin. --- - table: A list of installed states of the plugins. --- - boolean: The installed state of the plugin. --- The return type is determined based on the input type. --- If the input is a table of plugin modules, the return type is a table. -function M.is_installed(plugins) +function M.is_installed(plugins, simple) local is_single = type(plugins) == "string" if type(plugins) == "string" then plugins = { plugins } @@ -520,22 +572,26 @@ function M.is_installed(plugins) local installed_plugins = {} for _, plugin in ipairs(plugins) do local installed = false - local lazy_installed = pcall(require, "lazy") - if lazy_installed then - installed = require("lazy.core.config").plugins[plugin] ~= nil - end - local packer_installed = pcall(require, "packer_plugins") - if packer_installed then - ---@diagnostic disable-next-line: undefined-field - installed = _G.packer_plugins and _G.packer_plugins[plugin] ~= nil - end - if vim.fn.exists("g:plugs") == 1 then - installed = vim.g.plugs[plugin] ~= nil - end - if not installed then - local has_plug = pcall(require, plugin) - if has_plug then - installed = true + if simple then + installed = pcall(require, plugin) + else + local lazy_installed = pcall(require, "lazy") + if lazy_installed then + installed = require("lazy.core.config").plugins[plugin] ~= nil + end + local packer_installed = pcall(require, "packer_plugins") + if packer_installed then + ---@diagnostic disable-next-line: undefined-field + installed = _G.packer_plugins and _G.packer_plugins[plugin] ~= nil + end + if vim.fn.exists("g:plugs") == 1 then + installed = vim.g.plugs[plugin] ~= nil + end + if not installed then + local has_plug = pcall(require, plugin) + if has_plug then + installed = true + end end end installed_plugins[plugin] = installed @@ -548,14 +604,65 @@ function M.is_installed(plugins) end end ----@function Condition function to check filetype is not in list ----@param disabled_filetypes string[] The list of filetypes to check ----@return boolean|function true if filetype is not in list, false otherwise -function M.disable_on_filetypes(disabled_filetypes) - return function() - local filetype = vim.bo.filetype - return not vim.tbl_contains(disabled_filetypes, filetype) +-- Function to create a floating terminal window +function M.open_floating_terminal() + -- Create a scratch buffer specifically for the terminal + local buf = vim.api.nvim_create_buf(false, true) -- Create an unnamed, non-file, scratch buffer + + if not buf or buf == 0 then + vim.notify("Failed to create buffer", vim.log.levels.ERROR) + return end + + -- Get the dimensions of the current editor window + -- This helps us center the floating window + local ui = vim.api.nvim_list_uis()[1] + local width = ui.width + local height = ui.height + local win_width = math.floor(width * 0.8) + local win_height = math.floor(height * 0.8) + + -- Define settings of the floating window, sizing it to 80% of the full editor size + local win_opts = { + style = "minimal", -- Minimal UI, no status line or tab line + relative = "editor", -- Float relative to the whole editor UI + width = win_width, -- Set width to 80% of editor width + height = win_height, -- Set height to 80% of editor height + row = math.floor((height - win_height) / 2), -- Centered vertically + col = math.floor((width - win_width) / 2), -- Centered horizontally + border = "rounded", -- Add a border for aesthetics (can be 'single', 'double', etc.) + } + + -- Open the floating window with our newly created buffer + local win = vim.api.nvim_open_win(buf, true, win_opts) + + -- Check if the window was created successfully + if not win or win == 0 then + vim.notify("Failed to create floating window", vim.log.levels.ERROR) + return + end + + -- Set very specific buffer and window configurations + vim.api.nvim_set_option_value("bufhidden", "wipe", { buf = buf }) -- Auto-remove when the buffer is closed + vim.api.nvim_set_option_value("winblend", 10, { win = win }) -- Add slight transparency to the floating window + + -- Now that the floating window is ready, we run the terminal shell in the created buffer + -- Open the terminal in the buffer when we're sure the buffer is set up in the float + vim.fn.termopen(vim.o.shell, { + on_exit = function() + -- Safety measure: Ensure the window still exists before trying to close it + if vim.api.nvim_win_is_valid(win) then + -- Notify the user that the terminal has closed + vim.notify("Terminal closed", vim.log.levels.INFO) + -- Close and wipe the associated floating window and its buffer + vim.api.nvim_win_close(win, true) -- Force close the terminal window + end + end, + }) + + -- Switch focus to the terminal window in the floating buffer and enter insert mode + vim.api.nvim_set_current_win(win) + vim.cmd("startinsert!") -- Automatically enter insert mode within the terminal end ---@function Helper function to add keymaps with common properties