mirror of
https://github.com/ThePrimeagen/harpoon.git
synced 2025-07-13 17:40:25 +00:00
Merge pull request #103 from pranavrao145/fix-merge-conflict
Add tmux support to Harpoon
This commit is contained in:
commit
0c0b37d065
19
README.md
19
README.md
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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
210
lua/harpoon/tmux.lua
Normal 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
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user