Merge pull request #103 from pranavrao145/fix-merge-conflict

Add tmux support to Harpoon
This commit is contained in:
ThePrimeagen 2021-11-24 08:40:42 -07:00 committed by GitHub
commit 0c0b37d065
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 267 additions and 7 deletions

View File

@ -126,6 +126,22 @@ Just call the following function to edit commands inside the list
lua require('harpoon.cmd-ui').toggle_quick_menu()
```
#### Tmux Integration
Harpoon also supports all terminal operations (see above) with tmux terminals.
The configuration for using tmux is exactly the same as the config for using nvim
terminals. To use tmux terminals instead of nvim terminals, simply replace
`harpoon.term` with `harpoon.tmux` in your require statement.
For example:
```lua
-- goes to the first tmux window
lua require("harpoon.tmux").gotoTerminal(1)
-- sends a command to the first tmux window
lua require("harpoon.tmux").sendCommand(1, "ls -la")
```
### Setup
Setup should be called once.
@ -146,6 +162,7 @@ require("harpoon").setup({
save_on_toggle = false,
save_on_change = true,
enter_on_sendcmd = false,
tmux_autoclose_windows = false,
excluded_filetypes = { "harpoon" }
},
... your other configs ...
@ -160,6 +177,8 @@ require("harpoon").setup({
what I have found).
* `enter_on_sendcmd` will set harpoon to run the command immediately as it's
passed to the terminal when calling `sendCommand`.
* `tmux_autoclose_windows` will close any tmux windows harpoon that harpoon creates
when you close Neovim.
* `excluded_filetypes` filetypes that you want to prevent from adding to the harpoon list menu.
#### Preconfigured Terminal Commands

View File

@ -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?
}
}
},
@ -157,6 +157,7 @@ M.setup = function(config)
["save_on_toggle"] = false,
["save_on_change"] = true,
["enter_on_sendcmd"] = false,
["tmux_autoclose_windows"] = false,
["excluded_filetypes"] = { "harpoon" },
},
}, expand_dir(c_config), expand_dir(u_config), expand_dir(config))

View File

@ -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
@ -40,6 +40,7 @@ local function find_terminal(args)
if not term_handle or not vim.api.nvim_buf_is_valid(term_handle.buf_id) then
local buf_id, term_id = create_terminal(args.create_with)
if buf_id == nil then
error("Failed to find and create terminal.")
return
end
@ -63,14 +64,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 +89,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

210
lua/harpoon/tmux.lua Normal file
View File

@ -0,0 +1,210 @@
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 = {}
if global_config.tmux_autoclose_windows then
vim.cmd([[
augroup HARPOON_TMUX
autocmd!
autocmd VimLeave * :lua require('harpoon.tmux').clear_all()
]])
end
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())
-- This has to be done this way because tmux has-session does not give
-- updated results
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
error("Failed to find and create tmux window.")
return
end
window_handle = {
window_id = window_id,
}
tmux_windows[args.idx] = window_handle
end
return window_handle
end
local function get_first_empty_slot()
log.trace("_get_first_empty_slot()")
for idx, cmd in pairs(harpoon.get_term_config().cmds) do
if cmd == "" then
return idx
end
end
return M.get_length() + 1
end
M.gotoTerminal = function(idx)
log.trace("tmux: gotoTerminal(): Window:", idx)
local window_handle = find_terminal(idx)
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 pairs(tmux_windows) do
-- Delete the current tmux window
utils.get_os_command_output({
"tmux",
"kill-window",
"-t",
"%" .. window.window_id,
}, vim.loop.cwd())
end
tmux_windows = {}
end
M.get_length = function()
log.trace("_get_length()")
return table.maxn(harpoon.get_term_config().cmds)
end
M.valid_index = function(idx)
if idx == nil or idx > M.get_length() or idx <= 0 then
return false
end
return true
end
M.emit_changed = function()
log.trace("_emit_changed()")
if harpoon.get_global_settings().save_on_change then
harpoon.save()
end
end
M.add_cmd = function(cmd)
log.trace("add_cmd()")
local found_idx = get_first_empty_slot()
harpoon.get_term_config().cmds[found_idx] = cmd
M.emit_changed()
end
M.rm_cmd = function(idx)
log.trace("rm_cmd()")
if not M.valid_index(idx) then
log.debug("rm_cmd(): no cmd exists for index", idx)
return
end
table.remove(harpoon.get_term_config().cmds, idx)
M.emit_changed()
end
M.set_cmd_list = function(new_list)
log.trace("set_cmd_list(): New list:", new_list)
for k in pairs(harpoon.get_term_config().cmds) do
harpoon.get_term_config().cmds[k] = nil
end
for k, v in pairs(new_list) do
harpoon.get_term_config().cmds[k] = v
end
M.emit_changed()
end
return M

View File

@ -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,
is_white_space = function(str)
return str:gsub("%s", "") == ""
end,