diff --git a/.gitignore b/.gitignore index c3a388a..056a5d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /lazy /plugins +quick-command/commands.lua diff --git a/init.lua b/init.lua index 9677764..4ef3519 100644 --- a/init.lua +++ b/init.lua @@ -148,7 +148,7 @@ vim.diagnostic.config({ local highlight = require("highlight") highlight.setup() -local quickCommand = require("quick-command") +local quickCommand = require("quick-command/quick-command") quickCommand.setup() vim.api.nvim_create_autocmd({ 'VimLeavePre' }, { diff --git a/quick-command/quick-command.lua b/quick-command/quick-command.lua new file mode 100644 index 0000000..cd74f19 --- /dev/null +++ b/quick-command/quick-command.lua @@ -0,0 +1,203 @@ +---@alias EngineName "Lua" | "Jq" | "Node" | "Nvim" + +---@class Argument +---@field value string + +---@class Command +---@field name string +---@field engine EngineName +---@field executable_path string +---@field arguments? Argument[] +---@field working_dir? string +---@field output? "terminal" | "register" + +local M = {} + +---@type table +local Engine_prefixes = { + ["Lua"] = "lua", + ["Jq"] = "jq", + ["Node"] = "tsx", + ["Nvim"] = "source", +} + +M.setup = function () + vim.api.nvim_create_user_command( + "QC", + function(opts) M.execute(opts) end, + { desc = "[Q]uick [C]ommand" } + ) +end + +M.execute = function (opts) + local options = {} + package.loaded["quick-command.commands"] = nil + local commands = require("quick-command.commands") + for _, v in ipairs(commands) do + table.insert(options, v.name) + end + + vim.ui.select( + options, + { prompt = "Select command", }, + function (_, idx) + if not idx then + return + end + local command = commands[idx] + ExecuteCommand(command) + end + ) +end + +---@param command Command +function ExecuteCommand(command) + local executable_path = ReplaceVariables(command.executable_path) + + -- if Engine_prefixes[command.engine] then + -- executable_path = Engine_prefixes[command.engine] .. " " .. executable_path + -- end + + -- if command.working_dir then + -- command_text = "cd /d \"" .. command.working_dir .. "\" && " .. command_text + -- end + + if command.engine == "Nvim" then + vim.api.nvim_command(":" .. executable_path) + return + -- else + -- command_text = "[[" .. command_text .. "]]" + -- command_text = ":split | terminal " .. command_text + end + + local arguments = {} + table.insert(arguments, Engine_prefixes[command.engine]) + table.insert(arguments, executable_path) + for _, argument in ipairs(command.arguments or {}) do + local argument_parsed = ReplaceVariables(argument.value) + table.insert(arguments, argument_parsed) + end + + -- if command.engine ~= "Nvim" then + + ---@type vim.SystemOpts + local options = { + text = true + } + if command.working_dir then + options.cwd = ReplaceVariables(command.working_dir) + end + -- for index, value in ipairs(arguments) do + -- print(value) + -- end + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_command("split") + vim.api.nvim_set_current_buf(buf) + vim.bo[buf].buftype = "nofile" + + SetBufferContents(buf, { "Executing command..." }) + local time_elapsed = 0 + local timer = vim.uv.new_timer() + local timer_interval = 100 + if timer then + timer:start(0, timer_interval, vim.schedule_wrap(function () + time_elapsed = time_elapsed + timer_interval + SetBufferContents(buf, { "Executing command... (" .. (time_elapsed / 1000) .. "s)"}) + end)) + end + + vim.system( + arguments, + options, + function (result) + local lines = {} + if result.code == 0 then + lines = SplitIntoLines(result.stdout) + else + lines = SplitIntoLines(result.stdout) + lines = SplitIntoLines(result.stderr) + end + vim.schedule(function () + if timer then + timer:stop() + end + SetBufferContents(buf, lines) + end) + end + ) + + -- local result = vim.system( + -- arguments, + -- options + -- ):wait() + -- local lines = {} + -- if result.code == 0 then + -- lines = SplitIntoLines(result.stdout) + -- else + -- lines = SplitIntoLines(result.stdout) + -- lines = SplitIntoLines(result.stderr) + -- end + -- vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) + + + -- else + -- -- print(command_text) + -- local cmd = vim.api.nvim_parse_cmd(executable_path, {}) + -- -- print(command_text) + -- vim.api.nvim_command(executable_path) + -- end + +end + +---@param buf integer +---@param lines string[] +function SetBufferContents(buf, lines) + vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) +end + +---@param contents string | nil +---@return string +function CreateTempFile(contents) + contents = contents or "" + local temp_name = os.tmpname() + local file = io.open(temp_name, "w") + if not file then + error("Error creating temporary file") + end + file:write(contents) + file:close() + return temp_name +end + +function ReplaceVariables(input) + local result = input + result = ReplaceBufferName(result) + result = ReplaceHomeDirectory(result) + return result +end + +function ReplaceBufferName(input) + local buf_name = vim.api.nvim_buf_get_name(0) + if buf_name == "" then + local buffer_lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) + local buffer_content = table.concat(buffer_lines, "\n") + buf_name = CreateTempFile(buffer_content) + end + return string.gsub(input, "", buf_name) +end + +function ReplaceHomeDirectory(input) + local home_directory = os.getenv("HOME") or os.getenv("USERPROFILE") or os.getenv("HOMEPATH") or "~" + return string.gsub(input, "", home_directory) +end + +function SplitIntoLines(text) + local lines = {} + for line in (text--[[ .. "\n" ]]):gmatch("(.-)\n") do + line = line:gsub("\r$", "") + table.insert(lines, line) + end + return lines +end + +return M