local toBase64Url = function(text) local binaryToBase64 = function(binary) local alphabet = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-", "_" }; return alphabet[binary + 1] end local output = "" local size = (string.len(text) - (string.len(text) % 3)) / 3 for i = 1, size do local first_byte = string.byte(text, 3 * (i - 1) + 1) local second_byte = string.byte(text, 3 * (i - 1) + 2); local third_byte = string.byte(text, 3 * (i - 1) + 3); local first_base64 = first_byte >> 2 local second_base64 = ((first_byte & 3) << 4) | (second_byte >> 4) local third_base64 = ((second_byte & 15) << 2) | ((third_byte & 192) >> 6) local fourth_base64 = third_byte & 63 output = output .. binaryToBase64(first_base64) .. binaryToBase64(second_base64) .. binaryToBase64(third_base64) .. binaryToBase64(fourth_base64) end return output end local data_path = vim.fn.stdpath("data") local PERSONAL_COMMAND_JSON_PATH = data_path .. "/personal_commands/" .. toBase64Url(vim.fn.getcwd()) .. ".json" return { "MunifTanjim/nui.nvim", config = function() local COMMANDS = {} local CURRENT_COMMAND = nil --- ---@param command string|nil ---@return nil local executeCommandInTerminal = function(command) if (command ~= nil) then vim.cmd.term() vim.cmd.startinsert() local channel = vim.bo.channel -- 'clear' is used to hide the command local exitMessage = "\nPress enter to exit..." local commandString = command() vim.api.nvim_chan_send(channel, "clear && " .. commandString .. "; echo '" .. exitMessage .. "' && read -s && exit" .. "\n") end end local readJsonFromFile = function(filePath) local file, _ = io.open(filePath, 'r') if file ~= nil then local content = file:read("*a") local decoded_json = vim.json.decode(content) return decoded_json end return nil end local addCommandToJsonFile = function(commandBlock, commandsFilePath, directory) local current_json = readJsonFromFile(commandsFilePath) local is_new_file = false if current_json ~= nil then if current_json[directory] == nil then current_json[directory] = {} end -- FIXME: duplicates table.insert(current_json[directory], { command = tostring(commandBlock.command()), description = tostring(commandBlock.description()) }) else is_new_file = true end local file, error = io.open(commandsFilePath, 'w') if is_new_file and file ~= nil then file:write("{}") end if file then local indent = vim.bo.expandtab and (' '):rep(vim.o.shiftwidth) or '\t' if current_json ~= nil then json_content = vim.json.encode(current_json, {indent = indent}) file:write(json_content) end file:close() else print("Error in writeTableToJsonFile: " .. error) end end local updateJsonFile = function(listOfCommands, commandsFilePath, directory) local current_json = readJsonFromFile(commandsFilePath) current_json[directory] = {} for _, value in pairs(listOfCommands) do table.insert(current_json[directory], { command = tostring(value.command()), description = tostring(value.description()) }) end local file, error = io.open(commandsFilePath, 'w') if file then local indent = vim.bo.expandtab and (' '):rep(vim.o.shiftwidth) or '\t' file:write(vim.json.encode(current_json, {indent = indent})) file:close() else print("Error in updateJsonFile: " .. error) end end local appendCommandsFromFile = function(commands, commandsFilePath, directory) local current_list_of_commands_json = readJsonFromFile( commandsFilePath) if current_list_of_commands_json ~= nil and current_list_of_commands_json[directory] ~= nil then for _, block in pairs(current_list_of_commands_json[directory]) do local new_command_name = block["description"] commands[new_command_name] = { command = function() return block["command"] end, description = function() return new_command_name end } end end end local selectCommand = function(listOfCommands, callback) vim.ui.select(vim.tbl_keys(listOfCommands), { prompt = "Select your command.", format_item = function(item) return listOfCommands[item].description() end }, function(choice) if (choice ~= nil) then CURRENT_COMMAND = listOfCommands[choice].command callback(choice) end end) end local addCommand = function(current_command, commands, personal_command_json_path) local selectedCommand = nil local event = require("nui.utils.autocmd").event local Input = require("nui.input") local input = Input({ position = "50%", size = {width = 120}, border = { style = "single", text = {top = "[Howdy?]", top_align = "center"} }, win_options = { winhighlight = "Normal:Normal,FloatBorder:Normal" } }, { prompt = "> ", default_value = "", on_submit = function(value) selectedCommand = value local selectedDescription = vim.fn.input( 'Name the command: ') commands[selectedDescription] = { command = function() return selectedCommand end, description = function() return selectedDescription end } local created_command = commands[selectedDescription] addCommandToJsonFile(created_command, personal_command_json_path, vim.fn.getcwd()) current_command = created_command.command executeCommandInTerminal(current_command) end }) -- mount/open the component input:mount() input:map("n", "", function() input:unmount() end, {noremap = true}) end local deleteCommand = function() local previous_command = CURRENT_COMMAND selectCommand(COMMANDS, function(choice) local index = 0 for key, _ in pairs(COMMANDS) do index = index + 1 if key == choice then COMMANDS[key] = nil updateJsonFile(COMMANDS, PERSONAL_COMMAND_JSON_PATH, vim.fn.getcwd()) break end end CURRENT_COMMAND = previous_command end) end vim.api.nvim_create_user_command("AddCommand", function() addCommand(CURRENT_COMMAND, COMMANDS, PERSONAL_COMMAND_JSON_PATH) end, {}) vim.api.nvim_create_user_command("DeleteCommand", deleteCommand, {}) vim.api.nvim_create_user_command("EditCommands", function() vim.cmd("e " .. PERSONAL_COMMAND_JSON_PATH) end, {}) vim.api.nvim_create_autocmd({'BufEnter', 'BufWinEnter', 'DirChanged'}, { callback = function() COMMANDS = {} local current_json = readJsonFromFile(PERSONAL_COMMAND_JSON_PATH) local current_path = vim.fn.getcwd() if current_json ~= nil then for existing_directory, _ in pairs(current_json) do if (string.find(current_path, existing_directory) == 1) then appendCommandsFromFile(COMMANDS, PERSONAL_COMMAND_JSON_PATH, existing_directory) end end end end }) vim.keymap.set("n", "mc", function() if (CURRENT_COMMAND == nil) then selectCommand(COMMANDS, function() executeCommandInTerminal(CURRENT_COMMAND) end) else executeCommandInTerminal(CURRENT_COMMAND) end end) vim.keymap.set("n", "mC", function() selectCommand(COMMANDS, function() executeCommandInTerminal(CURRENT_COMMAND) end) end) end }