aboutsummaryrefslogtreecommitdiff
path: root/neovim/.config/nvim/lua/dyamon/terminal.lua
blob: f7702174565fa4664dcb6e8171c92e34ba91a092 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
--- Personal lua config files for NeoVim.
--  Last Changed: 2019-01-27
--  Author: Federico Igne <git@federicoigne.com>
--  License: This file is placed in the public domain.

--- Poor man's popup terminal
--
-- At the moment only one popup terminal is allowed at any time (do I
-- really need more?), and the same buffer is reused if it exists. This
-- should not interfere with normal terminal buffers.
local terminal = {}

local api = vim.api

--- Compute size of popup window
--
-- The window will be 3/4 and 2/3 of the total width and height
-- respectively, with a minimum size of 80x24. Alternatively the
-- terminal will take up the whole window.
local function get_size(opts, cols, rows)
    local w = math.min(cols, math.max(80, math.floor(3*cols/4)))
    local h = math.min(rows, math.max(24, math.floor(2*rows/3)))
    opts['col'] = math.floor((cols - w) / 2)
    opts['row'] = math.floor((rows - h) / 2)
    opts['width'] = w
    opts['height'] = h
end

--- Open a popup window with a terminal buffer in it.
--
-- If the terminal buffer exists already, it is used instead of creating
-- a new one. If the buffer exists but there is no terminal attached, a
-- new terminal instance is created.
--
-- @param opts a dictionary containing the following fields:
--          cmd: command executed in the terminal (`:h jobstart()`)
--          job: options passed to the job creation function (`:h jobstart()`)
--          win: options passed to the window creation function (`:h nvim_open_win()`)
local function open(opts)
  -- Get buffer or create a new one
  local buf = vim.g.termbuf
  if not buf or not api.nvim_buf_is_loaded(buf) then
    buf = api.nvim_create_buf(false, true)
  end
  -- Setup new window
  opts.win.relative = 'editor'   -- global window
  get_size(opts.win, vim.o.columns, vim.o.lines)
  local win = api.nvim_open_win(buf, true, opts.win)
  api.nvim_win_set_option(win, 'winhighlight', 'Normal:Normal')
  --api.nvim_win_set_option(win, 'winblend', 20)
  api.nvim_win_set_var(win, 'is_popup_term', 1)
  -- Start a new terminal instance, if necessary
  -- N.B. `termopen()` won't succede if a proper buffer is shown.
  local ok,_ = pcall(vim.fn.termopen, opts.cmd, opts.job)
  if ok then vim.g.termbuf = buf end
end

--- Close the current window.
--
-- Here we are assuming that we are focusing a terminal popup window.
--
-- @see terminal.toggle()
local function close()
  api.nvim_win_close(0, false)
end

--- Toggle popup terminal window.
--
-- @param opts a dictionary containing the following fields:
--          cmd: command executed in the terminal (`:h jobstart()`)
--          job: options passed to the job creation function (`:h jobstart()`)
--          win: options passed to the window creation function (`:h nvim_open_win()`)
function terminal.toggle(opts)
  local opts = vim.tbl_extend("keep", opts, { cmd = vim.env.SHELL, job = vim.empty_dict(), win = {} })
  if pcall(api.nvim_win_get_var, 0, "is_popup_term") then close() else open(opts) end
end

return terminal