-- 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