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

fix: task output problems #11

Merged
merged 1 commit into from
Jul 26, 2024
Merged
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
2 changes: 1 addition & 1 deletion lua/projector/outputs/dap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function DapOutput:init(configuration, callback)
end

self.session.on_close["projector"] = function()
self.state = "inactive"
callback(true)
end
end
Expand Down Expand Up @@ -66,7 +67,6 @@ function DapOutput:kill()
if has_dapui then
dapui.close()
end
self.state = "inactive"
end

---@return task_action[]
Expand Down
1 change: 1 addition & 0 deletions lua/projector/outputs/doc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
---@field hide fun(self: Output) function to hide the output off the screen
---@field actions? fun(self: Output):task_action[] function to list any available actions of the output
---@field preview? fun(self: Output, max_lines: integer):string[]? function to return a preview of output (to show in the dashboard) - max_lines indicates how many lines to show
---@field close? fun(self: Output) optional cleanup function that gets called when the task changes the current output for a different one (for example on restart)

---Output Builder interface.
---@class OutputBuilder
Expand Down
91 changes: 59 additions & 32 deletions lua/projector/outputs/task.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
---@class TaskOutput: Output
---@field private name string
---@field private bufnr integer
---@field private winid integer
---@field private state output_status
---@field private job_id integer
---@field private name? string
---@field private bufnr? integer
---@field private winid? integer
---@field private job_id? integer
---@field private died? boolean did task already die?
---@field private killed_manually? boolean was task killed by using the :kill method?
local TaskOutput = {}

---@return TaskOutput
Expand All @@ -16,7 +17,22 @@ end

---@return output_status
function TaskOutput:status()
return self.state or "inactive"
if self.died then
return "inactive"
end

local alive = (self.job_id ~= nil and vim.fn.jobwait({ self.job_id }, 0)[1] == -1)

if not alive then
self.died = true
return "inactive"
elseif self.winid and vim.api.nvim_win_is_valid(self.winid) then
return "visible"
elseif self.bufnr and vim.api.nvim_buf_is_valid(self.bufnr) then
return "hidden"
end

return "inactive"
end

---@param configuration TaskConfiguration
Expand All @@ -40,6 +56,11 @@ function TaskOutput:init(configuration, callback)
env = configuration.env,
cwd = configuration.cwd,
on_exit = function(_, code)
if self.killed_manually then
-- close the window and delete the buffer (only if killed usink key combination)
self:close()
end

callback(code == 0)
end,
}
Expand Down Expand Up @@ -69,30 +90,19 @@ function TaskOutput:init(configuration, callback)
-- close the dummy window
vim.api.nvim_win_close(winid, true)

self.state = "hidden"

-- Autocommands
-- Deactivate the output if we delete the buffer
vim.api.nvim_create_autocmd({ "BufDelete", "BufUnload" }, {
buffer = self.bufnr,
callback = function()
self.bufnr = nil
self.state = "inactive"
end,
})
-- If we close the window, the output is hidden
vim.api.nvim_create_autocmd({ "WinClosed" }, {
buffer = self.bufnr,
callback = function()
self.winid = nil
self.state = "hidden"
end,
})
-- switch back to our buffer when trying to open a different buffer in this window
vim.api.nvim_create_autocmd({ "BufWinEnter", "BufWinLeave", "BufReadPost", "BufNewFile" }, {
callback = function(arg)
-- delete autocmd if output is dead
if not self.bufnr or self.state == "inactive" then
if (not self.bufnr or not vim.api.nvim_buf_is_valid(self.bufnr)) or self:status() == "inactive" then
return true
end

Expand All @@ -106,8 +116,7 @@ end

function TaskOutput:show()
-- Open a new window and open the buffer in it
if not self.bufnr then
self.state = "inactive"
if not self.bufnr or not vim.api.nvim_buf_is_valid(self.bufnr) then
return
end

Expand All @@ -117,37 +126,55 @@ function TaskOutput:show()

-- set winbar
vim.api.nvim_win_set_option(self.winid, "winbar", self.name)

self.state = "visible"
end

function TaskOutput:hide()
pcall(vim.api.nvim_win_close, self.winid, true)
self.winid = nil
end

---@param winid integer
local function kill_terminal(winid)
if not winid or not vim.api.nvim_win_is_valid(winid) then
return
end

-- switch to provided window and kill it
vim.api.nvim_set_current_win(winid)

self.state = "hidden"
-- enter insert mode and send ctrl+c and escape (insert-mode, kill-process, normal-mode)
local escaped = vim.api.nvim_replace_termcodes("i<C-c>", true, false, true)
vim.api.nvim_feedkeys(escaped, "m", false)
end

function TaskOutput:kill()
-- kill the task
if self.job_id then
vim.fn.jobstop(self.job_id)
local status = self:status()
if status == "inactive" then
return
end

-- show window on screen if it's not there
if status == "hidden" then
self:show()
end

-- close the window and delete the buffer
self.killed_manually = true
-- kill the process
kill_terminal(self.winid)
end

function TaskOutput:close()
pcall(vim.api.nvim_win_close, self.winid, true)
pcall(vim.api.nvim_buf_delete, self.bufnr, { force = true })

self.state = "inactive"
end

---@param max_lines integer
---@return string[]?
function TaskOutput:preview(max_lines)
if self.state ~= "visible" and self.state ~= "hidden" then
local status = self:status()
if status ~= "visible" and status ~= "hidden" then
return
end
if not self.bufnr then
if not self.bufnr or not vim.api.nvim_buf_is_valid(self.bufnr) then
return
end

Expand Down
7 changes: 4 additions & 3 deletions lua/projector/task.lua
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,11 @@ function Task:run(opts)
callback(ok)
end

-- build the output and run the task
if mode ~= self.last_mode or not self.output then
self.output = self.output_builders[mode]:build()
-- close the old output, build a new one and run the task
if self.output and type(self.output.close) == "function" then
self.output:close()
end
self.output = self.output_builders[mode]:build()
self.output:init(self.expand_config_variables(self.configuration), cb)

-- show the output
Expand Down
Loading