local toggleterm = require("toggleterm") local Terminal = require("toggleterm.terminal").Terminal toggleterm.setup({ start_in_insert = true, insert_mappings = true, terminal_mappings = true, persist_size = true, persist_mode = true, close_on_exit = false, direction = "horizontal", size = 14, }) local M = {} local runners = { build = { cmd = "cmake --build --preset debug-with-tidy", title = "Build", }, test = { cmd = "ctest --test-dir build --output-on-failure", title = "Tests", }, } local terminals = { shell = Terminal:new({ hidden = true, close_on_exit = false, direction = "horizontal", }), } local last_runner = nil local function run_in_terminal(term, cmd) term:open() vim.defer_fn(function() term:send(cmd .. "\r", false) end, 20) end local function project_root() local current_file = vim.api.nvim_buf_get_name(0) local start_path = current_file ~= "" and vim.fs.dirname(current_file) or vim.loop.cwd() local markers = { "CMakePresets.json", "CMakeLists.txt", ".git" } local found = vim.fs.find(markers, { upward = true, path = start_path })[1] if found then return vim.fs.dirname(found) end return vim.loop.cwd() end local function get_runner_term(name) if terminals[name] then return terminals[name] end terminals[name] = Terminal:new({ hidden = true, close_on_exit = false, direction = "horizontal", display_name = runners[name].title, }) return terminals[name] end function M.toggle_shell() terminals.shell.dir = project_root() terminals.shell:toggle() end function M.run_build() local term = get_runner_term("build") term.dir = project_root() run_in_terminal(term, runners.build.cmd) last_runner = "build" end function M.run_tests() local term = get_runner_term("test") term.dir = project_root() run_in_terminal(term, runners.test.cmd) last_runner = "test" end function M.rerun_last() if not last_runner then vim.notify("No build/test command has been run yet", vim.log.levels.WARN) return end if last_runner == "build" then M.run_build() else M.run_tests() end end function M.toggle_build_terminal() local term = get_runner_term("build") term.dir = project_root() term:toggle() end function M.toggle_test_terminal() local term = get_runner_term("test") term.dir = project_root() term:toggle() end return M