From 45a888ee8a8268d4ccd29dc952c40d06d5533b1e Mon Sep 17 00:00:00 2001 From: Pranav Rao <56097527+pranavrao145@users.noreply.github.com> Date: Thu, 21 Oct 2021 14:38:37 -0400 Subject: [PATCH] feat(tmux): added option to use tmux terminals instead of nvim terminals This commit introduces a new module of harpoon, "harpoon.tmux", which provides several functions for using tmux windows for harpoon terminals. So far, all the basic features are supported, such as creating and moving to a new terminal, deleting all terminals, and sending commands to terminals etc. --- lua/harpoon/init.lua | 4 +- lua/harpoon/term.lua | 10 +-- lua/harpoon/tmux.lua | 142 ++++++++++++++++++++++++++++++++++++++++++ lua/harpoon/utils.lua | 29 +++++++++ 4 files changed, 178 insertions(+), 7 deletions(-) create mode 100755 lua/harpoon/tmux.lua diff --git a/lua/harpoon/init.lua b/lua/harpoon/init.lua index ae184ad..48fb8bd 100644 --- a/lua/harpoon/init.lua +++ b/lua/harpoon/init.lua @@ -17,12 +17,12 @@ local M = {} term = { cmds = { } - ... is there antyhnig that could be options? + ... is there anything that could be options? }, mark = { marks = { } - ... is there antyhnig that could be options? + ... is there anything that could be options? } } }, diff --git a/lua/harpoon/term.lua b/lua/harpoon/term.lua index fef47ec..e0a8c5d 100644 --- a/lua/harpoon/term.lua +++ b/lua/harpoon/term.lua @@ -9,7 +9,7 @@ local function create_terminal(create_with) if not create_with then create_with = ":terminal" end - log.trace("_create_terminal(): Init:", create_with) + log.trace("term: _create_terminal(): Init:", create_with) local current_id = vim.api.nvim_get_current_buf() vim.cmd(create_with) @@ -32,7 +32,7 @@ local function create_terminal(create_with) end local function find_terminal(args) - log.trace("_find_terminal(): Terminal:", args) + log.trace("term: _find_terminal(): Terminal:", args) if type(args) == "number" then args = { idx = args } end @@ -63,14 +63,14 @@ local function get_first_empty_slot() end M.gotoTerminal = function(idx) - log.trace("gotoTerminal(): Terminal:", idx) + log.trace("term: gotoTerminal(): Terminal:", idx) local term_handle = find_terminal(idx) vim.api.nvim_set_current_buf(term_handle.buf_id) end M.sendCommand = function(idx, cmd, ...) - log.trace("sendCommand(): Terminal:", idx) + log.trace("term: sendCommand(): Terminal:", idx) local term_handle = find_terminal(idx) if type(cmd) == "number" then @@ -88,7 +88,7 @@ M.sendCommand = function(idx, cmd, ...) end M.clear_all = function() - log.trace("clear_all(): Clearing all terminals.") + log.trace("term: clear_all(): Clearing all terminals.") for _, term in ipairs(terminals) do vim.api.nvim_buf_delete(term.buf_id, { force = true }) end diff --git a/lua/harpoon/tmux.lua b/lua/harpoon/tmux.lua new file mode 100755 index 0000000..661e6d5 --- /dev/null +++ b/lua/harpoon/tmux.lua @@ -0,0 +1,142 @@ +local harpoon = require("harpoon") +local log = require("harpoon.dev").log +local global_config = harpoon.get_global_settings() +local utils = require("harpoon.utils") + +local M = {} +local tmux_windows = {} + +local function create_terminal() + log.trace("tmux: _create_terminal())") + + local window_id + + -- Create a new tmux window and store the window id + local out, ret, _ = utils.get_os_command_output({ + "tmux", + "new-window", + "-P", + "-F", + "#{pane_id}", + }, vim.loop.cwd()) + + if ret == 0 then + window_id = out[1]:sub(2) + end + + if window_id == nil then + log.error("tmux: _create_terminal(): window_id is nil") + return nil + end + + return window_id +end + +-- Checks if the tmux window with the given window id exists +local function terminal_exists(window_id) + log.trace("_terminal_exists(): Window:", window_id) + + local exists = false + + local window_list, _, _ = utils.get_os_command_output({ + "tmux", + "list-windows", + }, vim.loop.cwd()) + + for _, line in pairs(window_list) do + local window_info = utils.split_string(line, "@")[1] + + if string.find(window_info, window_id) then + exists = true + end + end + + return exists +end + +local function find_terminal(args) + log.trace("tmux: _find_terminal(): Window:", args) + + if type(args) == "number" then + args = { idx = args } + end + + local window_handle = tmux_windows[args.idx] + local window_exists + + if window_handle then + window_exists = terminal_exists(window_handle.window_id) + end + + if not window_handle or not window_exists then + local window_id = create_terminal() + + if window_id == nil then + return + end + + window_handle = { + window_id = window_id, + } + + tmux_windows[args.idx] = window_handle + end + + return window_handle +end + +M.gotoTerminal = function(idx) + log.trace("tmux: gotoTerminal(): Window:", idx) + local window_handle = find_terminal(idx) + + local _, _, _ = utils.get_os_command_output({ + "tmux", + "select-window", + "-t", + "%" .. window_handle.window_id, + }, vim.loop.cwd()) +end + +M.sendCommand = function(idx, cmd, ...) + log.trace("tmux: sendCommand(): Window:", idx) + local window_handle = find_terminal(idx) + + if type(cmd) == "number" then + cmd = harpoon.get_term_config().cmds[cmd] + end + + if global_config.enter_on_sendcmd then + cmd = cmd .. "\n" + end + + if cmd then + log.debug("sendCommand:", cmd) + + -- Send the command to the given tmux window (creates it if it doesn't exist) + local _, _, _ = utils.get_os_command_output({ + "tmux", + "send-keys", + "-t", + "%" .. window_handle.window_id, + string.format(cmd, ...), + }, vim.loop.cwd()) + end +end + +M.clear_all = function() + log.trace("tmux: clear_all(): Clearing all tmux windows.") + + for _, window in ipairs(tmux_windows) do + -- Delete the current tmux window + local _, _, _ = utils.get_os_command_output({ + "tmux", + "kill-window", + "-t", + "%" .. window.window_id, + }, vim.loop.cwd()) + end + + tmux_windows = {} +end + +return M diff --git a/lua/harpoon/utils.lua b/lua/harpoon/utils.lua index 11161df..56d813e 100644 --- a/lua/harpoon/utils.lua +++ b/lua/harpoon/utils.lua @@ -1,11 +1,40 @@ local Path = require("plenary.path") local data_path = vim.fn.stdpath("data") +local Job = require("plenary.job") local M = { data_path = data_path, normalize_path = function(item) return Path:new(item):make_relative(vim.loop.cwd()) end, + get_os_command_output = function(cmd, cwd) + if type(cmd) ~= "table" then + print("Harpoon: [get_os_command_output]: cmd has to be a table") + return {} + end + local command = table.remove(cmd, 1) + local stderr = {} + local stdout, ret = Job + :new({ + command = command, + args = cmd, + cwd = cwd, + on_stderr = function(_, data) + table.insert(stderr, data) + end, + }) + :sync() + return stdout, ret, stderr + end, + split_string = function(str, delimiter) + local result = {} + + for match in (str .. delimiter):gmatch("(.-)" .. delimiter) do + table.insert(result, match) + end + + return result + end, } return M