Something went wrong. Try again.
Plugin for managing terminal in neovim
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202local M = {}
---@class TerminalSession---@field id string: Unique session identifier---@field cmd string: Command that was executed---@field terminal any: plenary.terminal.Terminal instance---@field created_at number: Timestamp when session was created
local _sessions = {}local _active_session_id = nillocal _session_counter = 0local _callbacks = { on_session_created = {}, on_session_closed = {}, on_active_changed = {},}
---Generate unique session ID---@return stringlocal function _generate_id() _session_counter = _session_counter + 1 return string.format( "session_%d_%d", _session_counter, math.floor(os.time() * 1000) % 1000000 )end
---Call registered callbacks---@param event string: Event name---@param data any: Event datalocal function _emit(event, data) if _callbacks[event] then for _, cb in ipairs(_callbacks[event]) do cb(data) end endend
---Create a new terminal session---@param cmd string: Command to execute---@return TerminalSession|nil: Created session or nil if failedfunction M.create(cmd) if not cmd or cmd == "" then return nil end
local id = _generate_id()
-- Try to load Terminal, but allow graceful degradation for testing local terminal = nil local ok, Terminal = pcall(function() return require("plenary.terminal").Terminal end)
if ok and Terminal then terminal = Terminal:new({ cmd = cmd, on_exit = function() -- Cleanup when terminal exits M.close(id) end, }) end
local session = { id = id, cmd = cmd, terminal = terminal, created_at = os.time(), }
_sessions[id] = session
-- Set as active if it's the first session if not _active_session_id then _active_session_id = id _emit("on_active_changed", { id = id, session = session }) else _active_session_id = id _emit("on_active_changed", { id = id, session = session }) end
_emit("on_session_created", { id = id, session = session })
return sessionend
---List all active sessions---@return TerminalSession[]function M.list() local sessions = {} for _, session in pairs(_sessions) do table.insert(sessions, session) end table.sort(sessions, function(a, b) return a.created_at < b.created_at end) return sessionsend
---Get session by ID---@param id string: Session ID---@return TerminalSession|nilfunction M.get_by_id(id) return _sessions[id]end
---Get currently active session---@return TerminalSession|nilfunction M.get_active() if _active_session_id then return _sessions[_active_session_id] end return nilend
---Get active session ID---@return string|nilfunction M.get_active_id() return _active_session_idend
---Switch to a different session---@param id string: Session ID to switch to---@return boolean: True if successful, false if session not foundfunction M.switch(id) if not _sessions[id] then return false end
_active_session_id = id _emit("on_active_changed", { id = id, session = _sessions[id] }) return trueend
---Close a session---@param id string: Session ID to close---@return boolean: True if successful, false if session not foundfunction M.close(id) local session = _sessions[id] if not session then return false end
-- Terminate the terminal if it exists if session.terminal then pcall(function() session.terminal:shutdown() end) end
_sessions[id] = nil _emit("on_session_closed", { id = id })
-- If closed session was active, switch to another if _active_session_id == id then local remaining = M.list() if #remaining > 0 then M.switch(remaining[1].id) else _active_session_id = nil end end
return trueend
---Clear all sessionsfunction M.clear_all() for id in pairs(_sessions) do pcall(function() local session = _sessions[id] if session.terminal then session.terminal:shutdown() end end) end _sessions = {} _active_session_id = nil _session_counter = 0end
---Check if session exists---@param id string: Session ID---@return booleanfunction M.exists(id) return _sessions[id] ~= nilend
---Register callback for session events---@param event string: Event name (on_session_created, on_session_closed, on_active_changed)---@param callback function: Callback functionfunction M.on(event, callback) if not _callbacks[event] then _callbacks[event] = {} end table.insert(_callbacks[event], callback)end
return M