Lemon = { ws = {}, ws_file = '.nvim.workspace.lua', term_buf = nil, term_win_cmd = 'belowright 12split', } function LoadWorkspace() -- Load persistent configuration from .workspace.lua local loaded, workspace = pcall(dofile, Lemon.ws_file) if not loaded then return nil end return workspace end function WriteWorkspace() -- A very minimal serializer for workspace configuration local s = { l = "", ls = {}, i = "" } local function w(v) s.l = s.l .. v end local function nl() s.ls[#s.ls + 1] = s.l; s.l = s.i; end local function wv(v) local t = type(v) if t == 'table' then w('{'); local pi = s.i; s.i = s.i .. " " for k1, v1 in pairs(v) do nl(); w('['); wv(k1); w('] = '); wv(v1); w(',') end s.i = pi; nl(); w('}'); elseif t == 'number' then w(tostring(v)) elseif t == 'string' then w('"' .. v .. '"') else w(tostring(v)) end end -- Write the workspace file w("return "); wv(Lemon.workspace); nl() vim.fn.writefile(s.ls, Lemon.ws_file) end -- Loads the workspace from the file, or return the default ---@param default table ---@return table function InitWorkspace(default) Lemon.ws = LoadWorkspace() if Lemon.ws == nil then Lemon.ws = default end return Lemon.ws end function TermShow() local info = GetTermInfo() if info == nil then -- Create new terminal buffer vim.cmd(Lemon.term_win_cmd) vim.cmd('terminal') Lemon.term_buf = vim.api.nvim_get_current_buf() -- Mark buffer so we can identify it later vim.api.nvim_buf_set_var(Lemon.term_buf, 'lemon_terminal', true) info = GetTermInfo() elseif info.win == nil then -- Buffer exists but not visible, open it vim.cmd(Lemon.term_win_cmd) vim.api.nvim_win_set_buf(0, Lemon.term_buf) else -- Window is visible, switch to it vim.api.nvim_set_current_win(info.win) end return info end -- Find or create persistent terminal buffer, open window, and run command function TermRun(cmd) local info = TermShow() -- Send command to terminal vim.fn.chansend(info.job_id, '\021' .. cmd .. '\n') vim.fn.feedkeys("G", "n") end -- Get terminal buffer and job_id if valid, returns {buf, job_id, win} -- win is nil if terminal is not currently visible function GetTermInfo() if Lemon.term_buf == nil or not vim.api.nvim_buf_is_valid(Lemon.term_buf) then return nil end local job_id = vim.api.nvim_buf_get_var(Lemon.term_buf, 'terminal_job_id') -- Find window showing the terminal buffer local win = nil for _, w in ipairs(vim.api.nvim_list_wins()) do if vim.api.nvim_win_get_buf(w) == Lemon.term_buf then win = w break end end return { buf = Lemon.term_buf, job_id = job_id, win = win } end -- Compatibility wrapper - returns window ID if terminal is visible function SwitchToExistingTerm() local info = GetTermInfo() return info and info.win or nil end -- Runs the make command and runs the callback when it completes function MakeAnd(run_callback) -- Create a one-time autocmd that fires when make completes local group = vim.api.nvim_create_augroup('MakeAnd', { clear = false }) vim.api.nvim_create_autocmd('QuickFixCmdPost', { group = group, pattern = 'make', once = true, callback = function() local qf_list = vim.fn.getqflist() local has_errors = false for _, item in ipairs(qf_list) do if item.valid == 1 then has_errors = true break end end vim.schedule(function() if not has_errors then run_callback() else vim.api.nvim_echo({ { "Build failed", "ErrorMsg" } }, false, {}) end end) end }) vim.cmd('silent make') end function TabCurrent() return vim.fn.tabpagenr() end function TabSwitch(tab) vim.cmd('tabnext ' .. tab) end