Skip to content

Commit

Permalink
feat: Add functions for better working with windows
Browse files Browse the repository at this point in the history
  • Loading branch information
idanarye committed Nov 7, 2023
1 parent c2b656f commit 758bd22
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 6 deletions.
73 changes: 70 additions & 3 deletions doc/channelot.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,25 @@ a running job:
end
<

ChannelotCreateWindowForTerminalOpts *ChannelotCreateWindowForTerminalOpts*

Fields: ~
{bufnr?} (number) Use an existing buffer instead of creating a new one


M.create_window_for_terminal({opts?}) *channelot.create_window_for_terminal*
Create a new window suitable for running terminal jobs.

* When the terminal window is closed, the focus will return (if possible) to
the original window from which this function was invoked.
* Automatically goes into insert mode inside the new window.
* Does not actually start the terminal.


Parameters: ~
{opts?} (ChannelotCreateWindowForTerminalOpts)


ChannelotTerminalOpts *ChannelotTerminalOpts*

Fields: ~
Expand All @@ -92,6 +111,26 @@ M.terminal({opts?}) *channelot.terminal*
Parameters: ~
{opts?} (ChannelotTerminalOpts)

Returns: ~
(ChannelotTerminal)


M.windowed_terminal({opts?}) *channelot.windowed_terminal*
Similar to |channelot.terminal|, but automatically creates a window with
|channelot.create_window_for_terminal| to put the new terminal in.

Parameters: ~
{opts?} (ChannelotTerminalOpts)

Returns: ~
(ChannelotTerminal)


M.shadow_terminal() *channelot.shadow_terminal*
Similar to |channelot.terminal|, but without creating a window.

A window can be created later using |ChannelotTerminal:expose|.

Returns: ~
(ChannelotTerminal)

Expand All @@ -107,7 +146,22 @@ M.terminal_job({env}, {command}, {opts?})

Returns: ~
(ChannelotJob) @overload fun(command: string|string[]): ChannelotJob
@overload fun(command: string|string[], opts: table): ChannelotJob
@overload fun(command: string|string[], opts: ChannelotJobOptions): ChannelotJob


*channelot.windowed_terminal_job*
M.windowed_terminal_job({env}, {command}, {opts?})
Similar to |channelot.terminal_job|, but automatically creates a window with
|channelot.create_window_for_terminal| to run the terminal job in.

Parameters: ~
{env} (table<string,any>) Environment variables for the command
{command} (string|string[]) The command as a string or as a list of arguments
{opts?} (ChannelotJobOptions)

Returns: ~
(ChannelotJob) @overload fun(command: string|string[]): ChannelotJob
@overload fun(command: string|string[], opts: ChannelotJobOptions): ChannelotJob


M.job({env}, {command}, {opts?}) *channelot.job*
Expand All @@ -122,7 +176,7 @@ M.job({env}, {command}, {opts?}) *channelot.job*

Returns: ~
(ChannelotJob) @overload fun(command: string|string[]): ChannelotJob
@overload fun(command: string|string[], opts: table): ChannelotJob
@overload fun(command: string|string[], opts: ChannelotJobOptions): ChannelotJob


ChannelotTerminal *ChannelotTerminal*
Expand All @@ -142,7 +196,7 @@ ChannelotTerminal:job({env}, {command}, {opts?})

Returns: ~
(ChannelotJob) @overload fun(command: string|string[]): ChannelotJob
@overload fun(command: string|string[], opts: table): ChannelotJob
@overload fun(command: string|string[], opts: ChannelotJobOptions): ChannelotJob


ChannelotTerminal:raw_write({text}) *ChannelotTerminal:raw_write*
Expand Down Expand Up @@ -187,6 +241,19 @@ ChannelotTerminal:get_bufnr() *ChannelotTerminal:get_bufnr*
(number) The buffer number used by the terminal.


ChannelotTerminal:list_windows() *ChannelotTerminal:list_windows*

Returns: ~
(number[]) A list of window handles that contain the terminal


ChannelotTerminal:expose() *ChannelotTerminal:expose*
Create a window for the terminal using |channelot.create_window_for_terminal|.

This is useful for a |channelot.shadow_terminal| that later needs to be
displayed - for example, if an error was encountered.


ChannelotTerminal:close_buffer() *ChannelotTerminal:close_buffer*
Close (delete) the buffer used by the terminal.

Expand Down
20 changes: 19 additions & 1 deletion lua/channelot/Terminal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ local ChannelotTerminal = {}
---@param opts? ChannelotJobOptions
---@return ChannelotJob
---@overload fun(command: string|string[]): ChannelotJob
---@overload fun(command: string|string[], opts: table): ChannelotJob
---@overload fun(command: string|string[], opts: ChannelotJobOptions): ChannelotJob
function ChannelotTerminal:job(env, command, opts)
env, command, opts = require'channelot.util'.normalize_job_arguments(env, command, opts)
local pty = require'channelot.util'.first_non_nil(opts.pty, true)
Expand Down Expand Up @@ -112,6 +112,24 @@ function ChannelotTerminal:get_bufnr()
return chan_info.buffer
end

---@return number[] # A list of window handles that contain the terminal
function ChannelotTerminal:list_windows()
local bufnr = self:get_bufnr()
return vim.tbl_filter(function(win)
return vim.api.nvim_win_get_buf(win) == bufnr
end, vim.api.nvim_list_wins())
end

---Create a window for the terminal using |channelot.create_window_for_terminal|.
---
---This is useful for a |channelot.shadow_terminal| that later needs to be
---displayed - for example, if an error was encountered.
function ChannelotTerminal:expose()
require'channelot'.create_window_for_terminal {
bufnr = self:get_bufnr(),
}
end

---Close (delete) the buffer used by the terminal.
function ChannelotTerminal:close_buffer()
vim.api.nvim_buf_delete(self:get_bufnr(), {force = true})
Expand Down
76 changes: 74 additions & 2 deletions lua/channelot/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,43 @@ local M = {}
---<
---@brief ]]

---@class ChannelotCreateWindowForTerminalOpts
---@field bufnr? number Use an existing buffer instead of creating a new one

---Create a new window suitable for running terminal jobs.
---
---* When the terminal window is closed, the focus will return (if possible) to
--- the original window from which this function was invoked.
---* Automatically goes into insert mode inside the new window.
---* Does not actually start the terminal.
---
---@param opts? ChannelotCreateWindowForTerminalOpts
function M.create_window_for_terminal(opts)
opts = opts or {}
local prev_win_id = vim.fn.win_getid(vim.fn.winnr())
vim.cmd'botright 20new'
local bufnr
if opts.bufnr then
bufnr = opts.bufnr
vim.api.nvim_win_set_buf(0, bufnr)
else
bufnr = vim.api.nvim_get_current_buf()
end
vim.api.nvim_create_autocmd('WinEnter', {
buffer = bufnr,
callback = function()
prev_win_id = vim.fn.win_getid(vim.fn.winnr('#'))
end,
})
vim.api.nvim_create_autocmd('WinClosed', {
buffer = bufnr,
callback = function()
vim.fn.win_gotoid(prev_win_id)
end,
})
vim.cmd.startinsert()
end

---@class ChannelotTerminalOpts
---@field bufnr? number Use the specified buffer instead of the current buffer

Expand All @@ -107,13 +144,35 @@ function M.terminal(opts)
return obj
end

---Similar to |channelot.terminal|, but automatically creates a window with
---|channelot.create_window_for_terminal| to put the new terminal in.
---@param opts? ChannelotTerminalOpts
---@return ChannelotTerminal
function M.windowed_terminal(opts)
opts = opts or {}
M.create_window_for_terminal {
bufnr = opts.bufnr,
}
return M.terminal(opts)
end

---Similar to |channelot.terminal|, but without creating a window.
---
---A window can be created later using |ChannelotTerminal:expose|.
---@return ChannelotTerminal
function M.shadow_terminal()
return M.terminal {
bufnr = vim.api.nvim_create_buf(true, false),
}
end

---Start a job on the current buffer, converting it to a terminal
---@param env table<string,any> Environment variables for the command
---@param command string|string[] The command as a string or as a list of arguments
---@param opts? ChannelotJobOptions
---@return ChannelotJob
---@overload fun(command: string|string[]): ChannelotJob
---@overload fun(command: string|string[], opts: table): ChannelotJob
---@overload fun(command: string|string[], opts: ChannelotJobOptions): ChannelotJob
function M.terminal_job(env, command, opts)
env, command, opts = require'channelot.util'.normalize_job_arguments(env, command, opts)
local pty = require'channelot.util'.first_non_nil(opts.pty, true)
Expand Down Expand Up @@ -163,6 +222,19 @@ function M.terminal_job(env, command, opts)
return obj
end

---Similar to |channelot.terminal_job|, but automatically creates a window with
---|channelot.create_window_for_terminal| to run the terminal job in.
---@param env table<string,any> Environment variables for the command
---@param command string|string[] The command as a string or as a list of arguments
---@param opts? ChannelotJobOptions
---@return ChannelotJob
---@overload fun(command: string|string[]): ChannelotJob
---@overload fun(command: string|string[], opts: ChannelotJobOptions): ChannelotJob
function M.windowed_terminal_job(env, command, opts)
M.create_window_for_terminal()
return M.terminal_job(env, command, opts)
end

---Start a job without a terminal attached to it.
---
---Note: this job will not have a PTY, unless `{ pty = true }` is passed in the `opts`.
Expand All @@ -171,7 +243,7 @@ end
---@param opts? ChannelotJobOptions
---@return ChannelotJob
---@overload fun(command: string|string[]): ChannelotJob
---@overload fun(command: string|string[], opts: table): ChannelotJob
---@overload fun(command: string|string[], opts: ChannelotJobOptions): ChannelotJob
function M.job(env, command, opts)
env, command, opts = require'channelot.util'.normalize_job_arguments(env, command, opts)
local pty = require'channelot.util'.first_non_nil(opts.pty, false)
Expand Down

0 comments on commit 758bd22

Please sign in to comment.