130 lines
3.2 KiB
Lua
130 lines
3.2 KiB
Lua
-- opencode.nvim - Toggle opencode in a Neovim terminal.
|
|
-- SPDX-License-Identifier: GPL-3.0-only
|
|
-- Copyright (C) 2026 Asger Gitz-Johansen
|
|
--
|
|
-- This program is free software: you can redistribute it and/or modify
|
|
-- it under the terms of the GNU General Public License as published by
|
|
-- the Free Software Foundation, version 3 only.
|
|
--
|
|
-- This program is distributed in the hope that it will be useful,
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-- GNU General Public License for more details.
|
|
|
|
local M = {}
|
|
|
|
local state = {
|
|
buf = nil,
|
|
win = nil,
|
|
job = nil,
|
|
}
|
|
|
|
local config = {
|
|
width = 0.3,
|
|
location = "right",
|
|
}
|
|
|
|
local valid_locations = {
|
|
left = true,
|
|
right = true,
|
|
top = true,
|
|
bottom = true,
|
|
}
|
|
|
|
local function is_valid_window(win)
|
|
return win and vim.api.nvim_win_is_valid(win)
|
|
end
|
|
|
|
local function is_valid_buffer(buf)
|
|
return buf and vim.api.nvim_buf_is_valid(buf)
|
|
end
|
|
|
|
local function terminal_width()
|
|
return math.max(1, math.floor(vim.o.columns * config.width))
|
|
end
|
|
|
|
local function terminal_height()
|
|
return math.max(1, math.floor(vim.o.lines * config.width))
|
|
end
|
|
|
|
local function open_terminal_window()
|
|
if config.location == "left" then
|
|
vim.cmd("topleft vertical " .. terminal_width() .. "new")
|
|
elseif config.location == "right" then
|
|
vim.cmd("botright vertical " .. terminal_width() .. "new")
|
|
elseif config.location == "top" then
|
|
vim.cmd("topleft " .. terminal_height() .. "new")
|
|
else
|
|
vim.cmd("botright " .. terminal_height() .. "new")
|
|
end
|
|
|
|
state.win = vim.api.nvim_get_current_win()
|
|
|
|
if config.location == "left" or config.location == "right" then
|
|
vim.api.nvim_set_option_value("winfixwidth", true, { win = state.win })
|
|
else
|
|
vim.api.nvim_set_option_value("winfixheight", true, { win = state.win })
|
|
end
|
|
end
|
|
|
|
local function start_terminal()
|
|
state.buf = vim.api.nvim_create_buf(false, true)
|
|
vim.api.nvim_set_option_value("bufhidden", "hide", { buf = state.buf })
|
|
vim.api.nvim_set_option_value("filetype", "opencode", { buf = state.buf })
|
|
vim.api.nvim_buf_set_name(state.buf, "opencode")
|
|
|
|
vim.api.nvim_win_set_buf(state.win, state.buf)
|
|
state.job = vim.fn.termopen("opencode", {
|
|
on_exit = function()
|
|
state.job = nil
|
|
end,
|
|
})
|
|
end
|
|
|
|
function M.toggle()
|
|
if is_valid_window(state.win) then
|
|
vim.api.nvim_win_close(state.win, false)
|
|
state.win = nil
|
|
return
|
|
end
|
|
|
|
open_terminal_window()
|
|
|
|
if is_valid_buffer(state.buf) then
|
|
vim.api.nvim_win_set_buf(state.win, state.buf)
|
|
else
|
|
start_terminal()
|
|
end
|
|
|
|
vim.cmd("startinsert")
|
|
end
|
|
|
|
function M.setup(opts)
|
|
opts = opts or {}
|
|
|
|
if opts.width ~= nil then
|
|
assert(
|
|
type(opts.width) == "number" and opts.width > 0 and opts.width <= 1,
|
|
"opencode.nvim: width must be a number between 0 and 1"
|
|
)
|
|
|
|
config.width = opts.width
|
|
end
|
|
|
|
if opts.location ~= nil then
|
|
assert(
|
|
type(opts.location) == "string" and valid_locations[opts.location],
|
|
"opencode.nvim: location must be one of: left, right, top, bottom"
|
|
)
|
|
|
|
config.location = opts.location
|
|
end
|
|
|
|
vim.api.nvim_create_user_command("OpenCodeToggle", function()
|
|
M.toggle()
|
|
end, { force = true })
|
|
|
|
end
|
|
|
|
return M
|