Skip to content

Commit

Permalink
Added Vim Session support
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinKennedy committed Apr 14, 2024
1 parent 193786e commit b876553
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 0 deletions.
71 changes: 71 additions & 0 deletions lua/toggleterm/terminal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,37 @@ local function _get_dir(dir)
end
end

---Convert the togglterm `buffer` to a text representation.
---
---We use this to be able to save and restore terminals later.
---
---@param bufnr number A 0-or-more buffer identifier to change.
---@return string[] # Lines of code which can be saved to a session file, later.
function Terminal:serialize_to_static_lua(bufnr)
-- TODO: Check if bufnr would work here
local fields = {
auto_scroll = self.auto_scroll,
bufnr = bufnr,
clear_env = self.env,
close_on_exit = self.close_on_exit,
cmd = self.cmd,
count = self.count,
dir = self.dir,
direction = self.direction,
display_name = self.display_name,
env = self.env,
hidden = self.hidden,
highlights = self.highlights,
id = self.id,
name = self.name,
newline_chr = self.newline_chr,
}

return {
string.format("terminal.apply_terminal_to_buffer(%s, %s)", bufnr, vim.inspect(fields)),
}
end

---Create a new terminal object
---@param term TermCreateArgs?
---@return Terminal
Expand Down Expand Up @@ -524,6 +555,37 @@ function M.identify(name)
return id, terminals[id]
end

---@return string[]? # The raw Lua commands needed to store/restore toggleterm buffers.
function M.get_all_terminal_commands()
local commands = {}

for _, buffer in ipairs(vim.api.nvim_list_bufs()) do
local number = vim.b[buffer].toggle_number

if number then
local terminal = M.get(number)

if terminal then
for _, line in ipairs(terminal:serialize_to_static_lua(buffer)) do
table.insert(commands, line)
end
end
end
end

if vim.tbl_isempty(commands) then return commands end

local output = { "lua << EOF", 'local terminal = require("toggleterm.terminal")' }

for _, line in ipairs(commands) do
table.insert(output, line)
end

table.insert(output, "EOF")

return output
end

---get existing terminal or create an empty term table
---@param num number?
---@param dir string?
Expand All @@ -547,6 +609,15 @@ function M.get(id, include_hidden)
return (term and (include_hidden == true or not term.hidden)) and term or nil
end

---Change terminal `buffer` into toggleterm buffer.
---
---@param bufnr number A 0-or-more buffer identifier to change.
---@param options TermCreateArgs? Settings to apply to the terminal, on-create.
function M.apply_terminal_to_buffer(bufnr, options)
local terminal = Terminal:new(options)
terminal:spawn()
end

---Get the first terminal that matches a predicate
---@param predicate fun(term: Terminal): boolean
---@return Terminal?
Expand Down
50 changes: 50 additions & 0 deletions plugin/toggleterm.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---Handle Vim session-saving logic when buffers contain a toggleterm terminal.

---Write `lines` of text to-disk at `path`.
---
---@param lines string[] The text to write.
---@param path string An absolute path on-disk to append `lines` onto.
local function _append_lines(commands, path)
local handler = io.open(path, "a")

if not handler then
vim.api.nvim_err_writeln('Unable to write to "%s" Sessionx.vim.', path)

return
end

for _, line in ipairs(commands) do
handler:write(line .. "\n")
end

handler:close()
end

---@return string # Get the full path where a Sessionx.vim file should be written to-disk.
local function _get_sessionx_path()
local path = vim.v.this_session

if not path then
return nil
end

return vim.fn.fnamemodify(path, ":h") .. "/Sessionx.vim"
end

---Serialize all toggleterm terminals to a Sessionx.vim file so they can be restored later.
local function _save_terminals()
local commands = require("toggleterm.terminal").get_all_terminal_commands()
local path = _get_sessionx_path()

if not commands then
-- No new terminals needed to be saved
-- TODO: It's unclear if this should be removed or somehow cleared
vim.fn.delete(path)

return
end

_append_lines(commands, path)
end

vim.api.nvim_create_autocmd("SessionWritePost", {callback=_save_terminals})

0 comments on commit b876553

Please sign in to comment.