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()
|
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
|
||||||
Setup should be called once.
|
Setup should be called once.
|
||||||
|
|
||||||
@ -146,6 +162,7 @@ require("harpoon").setup({
|
|||||||
save_on_toggle = false,
|
save_on_toggle = false,
|
||||||
save_on_change = true,
|
save_on_change = true,
|
||||||
enter_on_sendcmd = false,
|
enter_on_sendcmd = false,
|
||||||
|
tmux_autoclose_windows = false,
|
||||||
excluded_filetypes = { "harpoon" }
|
excluded_filetypes = { "harpoon" }
|
||||||
},
|
},
|
||||||
... your other configs ...
|
... your other configs ...
|
||||||
@ -160,6 +177,8 @@ require("harpoon").setup({
|
|||||||
what I have found).
|
what I have found).
|
||||||
* `enter_on_sendcmd` will set harpoon to run the command immediately as it's
|
* `enter_on_sendcmd` will set harpoon to run the command immediately as it's
|
||||||
passed to the terminal when calling `sendCommand`.
|
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.
|
* `excluded_filetypes` filetypes that you want to prevent from adding to the harpoon list menu.
|
||||||
|
|
||||||
#### Preconfigured Terminal Commands
|
#### Preconfigured Terminal Commands
|
||||||
|
@ -17,12 +17,12 @@ local M = {}
|
|||||||
term = {
|
term = {
|
||||||
cmds = {
|
cmds = {
|
||||||
}
|
}
|
||||||
... is there antyhnig that could be options?
|
... is there anything that could be options?
|
||||||
},
|
},
|
||||||
mark = {
|
mark = {
|
||||||
marks = {
|
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_toggle"] = false,
|
||||||
["save_on_change"] = true,
|
["save_on_change"] = true,
|
||||||
["enter_on_sendcmd"] = false,
|
["enter_on_sendcmd"] = false,
|
||||||
|
["tmux_autoclose_windows"] = false,
|
||||||
["excluded_filetypes"] = { "harpoon" },
|
["excluded_filetypes"] = { "harpoon" },
|
||||||
},
|
},
|
||||||
}, expand_dir(c_config), expand_dir(u_config), expand_dir(config))
|
}, 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
|
if not create_with then
|
||||||
create_with = ":terminal"
|
create_with = ":terminal"
|
||||||
end
|
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()
|
local current_id = vim.api.nvim_get_current_buf()
|
||||||
|
|
||||||
vim.cmd(create_with)
|
vim.cmd(create_with)
|
||||||
@ -32,7 +32,7 @@ local function create_terminal(create_with)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function find_terminal(args)
|
local function find_terminal(args)
|
||||||
log.trace("_find_terminal(): Terminal:", args)
|
log.trace("term: _find_terminal(): Terminal:", args)
|
||||||
if type(args) == "number" then
|
if type(args) == "number" then
|
||||||
args = { idx = args }
|
args = { idx = args }
|
||||||
end
|
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
|
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)
|
local buf_id, term_id = create_terminal(args.create_with)
|
||||||
if buf_id == nil then
|
if buf_id == nil then
|
||||||
|
error("Failed to find and create terminal.")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -63,14 +64,14 @@ local function get_first_empty_slot()
|
|||||||
end
|
end
|
||||||
|
|
||||||
M.gotoTerminal = function(idx)
|
M.gotoTerminal = function(idx)
|
||||||
log.trace("gotoTerminal(): Terminal:", idx)
|
log.trace("term: gotoTerminal(): Terminal:", idx)
|
||||||
local term_handle = find_terminal(idx)
|
local term_handle = find_terminal(idx)
|
||||||
|
|
||||||
vim.api.nvim_set_current_buf(term_handle.buf_id)
|
vim.api.nvim_set_current_buf(term_handle.buf_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
M.sendCommand = function(idx, cmd, ...)
|
M.sendCommand = function(idx, cmd, ...)
|
||||||
log.trace("sendCommand(): Terminal:", idx)
|
log.trace("term: sendCommand(): Terminal:", idx)
|
||||||
local term_handle = find_terminal(idx)
|
local term_handle = find_terminal(idx)
|
||||||
|
|
||||||
if type(cmd) == "number" then
|
if type(cmd) == "number" then
|
||||||
@ -88,7 +89,7 @@ M.sendCommand = function(idx, cmd, ...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
M.clear_all = function()
|
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
|
for _, term in ipairs(terminals) do
|
||||||
vim.api.nvim_buf_delete(term.buf_id, { force = true })
|
vim.api.nvim_buf_delete(term.buf_id, { force = true })
|
||||||
end
|
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 Path = require("plenary.path")
|
||||||
local data_path = vim.fn.stdpath("data")
|
local data_path = vim.fn.stdpath("data")
|
||||||
|
local Job = require("plenary.job")
|
||||||
|
|
||||||
local M = {
|
local M = {
|
||||||
data_path = data_path,
|
data_path = data_path,
|
||||||
normalize_path = function(item)
|
normalize_path = function(item)
|
||||||
return Path:new(item):make_relative(vim.loop.cwd())
|
return Path:new(item):make_relative(vim.loop.cwd())
|
||||||
end,
|
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)
|
is_white_space = function(str)
|
||||||
return str:gsub("%s", "") == ""
|
return str:gsub("%s", "") == ""
|
||||||
end,
|
end,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user