Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add session support #568

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions lua/toggleterm/terminal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,36 @@ 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)
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 +554,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 +608,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()
-- IMPORTANT: Ideally in the future we can allow multiple x.vim file support
-- Reference: https://github.com/akinsho/toggleterm.nvim/issues/567
vim.fn.delete(path)

if not commands then
-- No new terminals needed to be saved
return
end

_append_lines(commands, path)
end

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