migrating the logs
This commit is contained in:
@@ -2,379 +2,11 @@
|
||||
---
|
||||
local M = {}
|
||||
|
||||
local logs = require("codetyper.adapters.nvim.ui.logs")
|
||||
local queue = require("codetyper.core.events.queue")
|
||||
|
||||
---@class LogsPanelState
|
||||
---@field buf number|nil Logs buffer
|
||||
---@field win number|nil Logs window
|
||||
---@field queue_buf number|nil Queue buffer
|
||||
---@field queue_win number|nil Queue window
|
||||
---@field is_open boolean Whether the panel is open
|
||||
---@field listener_id number|nil Listener ID for logs
|
||||
---@field queue_listener_id number|nil Listener ID for queue
|
||||
|
||||
local state = {
|
||||
buf = nil,
|
||||
win = nil,
|
||||
queue_buf = nil,
|
||||
queue_win = nil,
|
||||
is_open = false,
|
||||
listener_id = nil,
|
||||
queue_listener_id = nil,
|
||||
}
|
||||
|
||||
--- Namespace for highlights
|
||||
local ns_logs = vim.api.nvim_create_namespace("codetyper_logs_panel")
|
||||
local ns_queue = vim.api.nvim_create_namespace("codetyper_queue_panel")
|
||||
|
||||
--- Fixed dimensions
|
||||
local LOGS_WIDTH = 60
|
||||
local QUEUE_HEIGHT = 8
|
||||
|
||||
--- Add a log entry to the buffer
|
||||
---@param entry table Log entry
|
||||
local function add_log_entry(entry)
|
||||
if not state.buf or not vim.api.nvim_buf_is_valid(state.buf) then
|
||||
return
|
||||
end
|
||||
|
||||
vim.schedule(function()
|
||||
if not state.buf or not vim.api.nvim_buf_is_valid(state.buf) then
|
||||
return
|
||||
end
|
||||
|
||||
-- Handle clear event
|
||||
if entry.level == "clear" then
|
||||
vim.bo[state.buf].modifiable = true
|
||||
vim.api.nvim_buf_set_lines(state.buf, 0, -1, false, {
|
||||
"Generation Logs",
|
||||
string.rep("─", LOGS_WIDTH - 2),
|
||||
"",
|
||||
})
|
||||
vim.bo[state.buf].modifiable = false
|
||||
return
|
||||
end
|
||||
|
||||
vim.bo[state.buf].modifiable = true
|
||||
|
||||
local formatted = logs.format_entry(entry)
|
||||
local formatted_lines = vim.split(formatted, "\n", { plain = true })
|
||||
local line_count = vim.api.nvim_buf_line_count(state.buf)
|
||||
|
||||
vim.api.nvim_buf_set_lines(state.buf, -1, -1, false, formatted_lines)
|
||||
|
||||
-- Apply highlighting based on level
|
||||
local hl_map = {
|
||||
info = "DiagnosticInfo",
|
||||
debug = "Comment",
|
||||
request = "DiagnosticWarn",
|
||||
response = "DiagnosticOk",
|
||||
tool = "DiagnosticHint",
|
||||
error = "DiagnosticError",
|
||||
}
|
||||
|
||||
local hl = hl_map[entry.level] or "Normal"
|
||||
for i = 0, #formatted_lines - 1 do
|
||||
vim.api.nvim_buf_add_highlight(state.buf, ns_logs, hl, line_count + i, 0, -1)
|
||||
end
|
||||
|
||||
vim.bo[state.buf].modifiable = false
|
||||
|
||||
-- Auto-scroll logs
|
||||
if state.win and vim.api.nvim_win_is_valid(state.win) then
|
||||
local new_count = vim.api.nvim_buf_line_count(state.buf)
|
||||
pcall(vim.api.nvim_win_set_cursor, state.win, { new_count, 0 })
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--- Update the title with token counts
|
||||
local function update_title()
|
||||
if not state.win or not vim.api.nvim_win_is_valid(state.win) then
|
||||
return
|
||||
end
|
||||
|
||||
local prompt_tokens, response_tokens = logs.get_token_totals()
|
||||
local provider, model = logs.get_provider_info()
|
||||
|
||||
if provider and state.buf and vim.api.nvim_buf_is_valid(state.buf) then
|
||||
vim.bo[state.buf].modifiable = true
|
||||
local title = string.format("%s | %d/%d tokens", (provider or ""):upper(), prompt_tokens, response_tokens)
|
||||
vim.api.nvim_buf_set_lines(state.buf, 0, 1, false, { title })
|
||||
vim.bo[state.buf].modifiable = false
|
||||
end
|
||||
end
|
||||
|
||||
--- Update the queue display
|
||||
local function update_queue_display()
|
||||
if not state.queue_buf or not vim.api.nvim_buf_is_valid(state.queue_buf) then
|
||||
return
|
||||
end
|
||||
|
||||
vim.schedule(function()
|
||||
if not state.queue_buf or not vim.api.nvim_buf_is_valid(state.queue_buf) then
|
||||
return
|
||||
end
|
||||
|
||||
vim.bo[state.queue_buf].modifiable = true
|
||||
|
||||
local lines = {
|
||||
"Queue",
|
||||
string.rep("─", LOGS_WIDTH - 2),
|
||||
}
|
||||
|
||||
-- Get all events (pending and processing)
|
||||
local pending = queue.get_pending()
|
||||
local processing = queue.get_processing()
|
||||
|
||||
-- Add processing events first
|
||||
for _, event in ipairs(processing) do
|
||||
local filename = vim.fn.fnamemodify(event.target_path or "", ":t")
|
||||
local line_num = event.range and event.range.start_line or 0
|
||||
local prompt_preview = (event.prompt_content or ""):sub(1, 25):gsub("\n", " ")
|
||||
if #(event.prompt_content or "") > 25 then
|
||||
prompt_preview = prompt_preview .. "..."
|
||||
end
|
||||
table.insert(lines, string.format("▶ %s:%d %s", filename, line_num, prompt_preview))
|
||||
end
|
||||
|
||||
-- Add pending events
|
||||
for _, event in ipairs(pending) do
|
||||
local filename = vim.fn.fnamemodify(event.target_path or "", ":t")
|
||||
local line_num = event.range and event.range.start_line or 0
|
||||
local prompt_preview = (event.prompt_content or ""):sub(1, 25):gsub("\n", " ")
|
||||
if #(event.prompt_content or "") > 25 then
|
||||
prompt_preview = prompt_preview .. "..."
|
||||
end
|
||||
table.insert(lines, string.format("○ %s:%d %s", filename, line_num, prompt_preview))
|
||||
end
|
||||
|
||||
if #pending == 0 and #processing == 0 then
|
||||
table.insert(lines, " (empty)")
|
||||
end
|
||||
|
||||
vim.api.nvim_buf_set_lines(state.queue_buf, 0, -1, false, lines)
|
||||
|
||||
-- Apply highlights
|
||||
vim.api.nvim_buf_clear_namespace(state.queue_buf, ns_queue, 0, -1)
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, ns_queue, "Title", 0, 0, -1)
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, ns_queue, "Comment", 1, 0, -1)
|
||||
|
||||
local line_idx = 2
|
||||
for _ = 1, #processing do
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, ns_queue, "DiagnosticWarn", line_idx, 0, 1)
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, ns_queue, "String", line_idx, 2, -1)
|
||||
line_idx = line_idx + 1
|
||||
end
|
||||
for _ = 1, #pending do
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, ns_queue, "Comment", line_idx, 0, 1)
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, ns_queue, "Normal", line_idx, 2, -1)
|
||||
line_idx = line_idx + 1
|
||||
end
|
||||
|
||||
vim.bo[state.queue_buf].modifiable = false
|
||||
end)
|
||||
end
|
||||
|
||||
--- Open the logs panel
|
||||
function M.open()
|
||||
if state.is_open then
|
||||
return
|
||||
end
|
||||
|
||||
-- Clear previous logs
|
||||
logs.clear()
|
||||
|
||||
-- Create logs buffer
|
||||
state.buf = vim.api.nvim_create_buf(false, true)
|
||||
vim.bo[state.buf].buftype = "nofile"
|
||||
vim.bo[state.buf].bufhidden = "hide"
|
||||
vim.bo[state.buf].swapfile = false
|
||||
|
||||
-- Create window on the right
|
||||
vim.cmd("botright vsplit")
|
||||
state.win = vim.api.nvim_get_current_win()
|
||||
vim.api.nvim_win_set_buf(state.win, state.buf)
|
||||
vim.api.nvim_win_set_width(state.win, LOGS_WIDTH)
|
||||
|
||||
-- Window options for logs
|
||||
vim.wo[state.win].number = false
|
||||
vim.wo[state.win].relativenumber = false
|
||||
vim.wo[state.win].signcolumn = "no"
|
||||
vim.wo[state.win].wrap = true
|
||||
vim.wo[state.win].linebreak = true
|
||||
vim.wo[state.win].winfixwidth = true
|
||||
vim.wo[state.win].cursorline = false
|
||||
|
||||
-- Set initial content for logs
|
||||
vim.bo[state.buf].modifiable = true
|
||||
vim.api.nvim_buf_set_lines(state.buf, 0, -1, false, {
|
||||
"Generation Logs",
|
||||
string.rep("─", LOGS_WIDTH - 2),
|
||||
"",
|
||||
})
|
||||
vim.bo[state.buf].modifiable = false
|
||||
|
||||
-- Create queue buffer
|
||||
state.queue_buf = vim.api.nvim_create_buf(false, true)
|
||||
vim.bo[state.queue_buf].buftype = "nofile"
|
||||
vim.bo[state.queue_buf].bufhidden = "hide"
|
||||
vim.bo[state.queue_buf].swapfile = false
|
||||
|
||||
-- Create queue window as horizontal split at bottom of logs window
|
||||
vim.cmd("belowright split")
|
||||
state.queue_win = vim.api.nvim_get_current_win()
|
||||
vim.api.nvim_win_set_buf(state.queue_win, state.queue_buf)
|
||||
vim.api.nvim_win_set_height(state.queue_win, QUEUE_HEIGHT)
|
||||
|
||||
-- Window options for queue
|
||||
vim.wo[state.queue_win].number = false
|
||||
vim.wo[state.queue_win].relativenumber = false
|
||||
vim.wo[state.queue_win].signcolumn = "no"
|
||||
vim.wo[state.queue_win].wrap = true
|
||||
vim.wo[state.queue_win].linebreak = true
|
||||
vim.wo[state.queue_win].winfixheight = true
|
||||
vim.wo[state.queue_win].cursorline = false
|
||||
|
||||
-- Setup keymaps for logs buffer
|
||||
local opts = { buffer = state.buf, noremap = true, silent = true }
|
||||
vim.keymap.set("n", "q", M.close, opts)
|
||||
vim.keymap.set("n", "<Esc>", M.close, opts)
|
||||
|
||||
-- Setup keymaps for queue buffer
|
||||
local queue_opts = { buffer = state.queue_buf, noremap = true, silent = true }
|
||||
vim.keymap.set("n", "q", M.close, queue_opts)
|
||||
vim.keymap.set("n", "<Esc>", M.close, queue_opts)
|
||||
|
||||
-- Register log listener
|
||||
state.listener_id = logs.add_listener(function(entry)
|
||||
add_log_entry(entry)
|
||||
if entry.level == "response" then
|
||||
vim.schedule(update_title)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Register queue listener
|
||||
state.queue_listener_id = queue.add_listener(function()
|
||||
update_queue_display()
|
||||
end)
|
||||
|
||||
-- Initial queue display
|
||||
update_queue_display()
|
||||
|
||||
state.is_open = true
|
||||
|
||||
-- Return focus to previous window
|
||||
vim.cmd("wincmd p")
|
||||
|
||||
logs.info("Logs panel opened")
|
||||
end
|
||||
|
||||
--- Close the logs panel
|
||||
---@param force? boolean Force close even if not marked as open
|
||||
function M.close(force)
|
||||
if not state.is_open and not force then
|
||||
return
|
||||
end
|
||||
|
||||
-- Remove log listener
|
||||
if state.listener_id then
|
||||
pcall(logs.remove_listener, state.listener_id)
|
||||
state.listener_id = nil
|
||||
end
|
||||
|
||||
-- Remove queue listener
|
||||
if state.queue_listener_id then
|
||||
pcall(queue.remove_listener, state.queue_listener_id)
|
||||
state.queue_listener_id = nil
|
||||
end
|
||||
|
||||
-- Close queue window first
|
||||
if state.queue_win then
|
||||
pcall(vim.api.nvim_win_close, state.queue_win, true)
|
||||
state.queue_win = nil
|
||||
end
|
||||
|
||||
-- Close logs window
|
||||
if state.win then
|
||||
pcall(vim.api.nvim_win_close, state.win, true)
|
||||
state.win = nil
|
||||
end
|
||||
|
||||
-- Delete queue buffer
|
||||
if state.queue_buf then
|
||||
pcall(vim.api.nvim_buf_delete, state.queue_buf, { force = true })
|
||||
state.queue_buf = nil
|
||||
end
|
||||
|
||||
-- Delete logs buffer
|
||||
if state.buf then
|
||||
pcall(vim.api.nvim_buf_delete, state.buf, { force = true })
|
||||
state.buf = nil
|
||||
end
|
||||
|
||||
state.is_open = false
|
||||
end
|
||||
|
||||
--- Toggle the logs panel
|
||||
function M.toggle()
|
||||
if state.is_open then
|
||||
M.close()
|
||||
else
|
||||
M.open()
|
||||
end
|
||||
end
|
||||
|
||||
--- Check if panel is open
|
||||
---@return boolean
|
||||
function M.is_open()
|
||||
return state.is_open
|
||||
end
|
||||
|
||||
--- Ensure panel is open (call before starting generation)
|
||||
function M.ensure_open()
|
||||
if not state.is_open then
|
||||
M.open()
|
||||
end
|
||||
end
|
||||
|
||||
--- Setup autocmds for the logs panel
|
||||
function M.setup()
|
||||
local group = vim.api.nvim_create_augroup("CodetypeLogsPanel", { clear = true })
|
||||
|
||||
-- Close logs panel when exiting Neovim
|
||||
vim.api.nvim_create_autocmd("VimLeavePre", {
|
||||
group = group,
|
||||
callback = function()
|
||||
-- Force close to ensure cleanup even in edge cases
|
||||
M.close(true)
|
||||
end,
|
||||
desc = "Close logs panel before exiting Neovim",
|
||||
})
|
||||
|
||||
-- Also clean up when QuitPre fires (handles :qa, :wqa, etc.)
|
||||
vim.api.nvim_create_autocmd("QuitPre", {
|
||||
group = group,
|
||||
callback = function()
|
||||
-- Check if this is the last window (about to quit Neovim)
|
||||
local wins = vim.api.nvim_list_wins()
|
||||
local real_wins = 0
|
||||
for _, win in ipairs(wins) do
|
||||
local buf = vim.api.nvim_win_get_buf(win)
|
||||
local buftype = vim.bo[buf].buftype
|
||||
-- Count non-special windows
|
||||
if buftype == "" or buftype == "help" then
|
||||
real_wins = real_wins + 1
|
||||
end
|
||||
end
|
||||
-- If only logs/queue windows remain, close them
|
||||
if real_wins <= 1 then
|
||||
M.close(true)
|
||||
end
|
||||
end,
|
||||
desc = "Close logs panel on quit",
|
||||
})
|
||||
end
|
||||
M.open = require("codetyper.adapters.nvim.ui.logs_panel.open")
|
||||
M.close = require("codetyper.adapters.nvim.ui.logs_panel.close")
|
||||
M.toggle = require("codetyper.adapters.nvim.ui.logs_panel.toggle")
|
||||
M.is_open = require("codetyper.adapters.nvim.ui.logs_panel.is_open")
|
||||
M.ensure_open = require("codetyper.adapters.nvim.ui.logs_panel.ensure_open")
|
||||
M.setup = require("codetyper.adapters.nvim.ui.logs_panel.setup")
|
||||
|
||||
return M
|
||||
|
||||
59
lua/codetyper/adapters/nvim/ui/logs_panel/add_log_entry.lua
Normal file
59
lua/codetyper/adapters/nvim/ui/logs_panel/add_log_entry.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
local state = require("codetyper.state.state")
|
||||
local logs = require("codetyper.adapters.nvim.ui.logs")
|
||||
local constants = require("codetyper.adapters.nvim.ui.logs_panel.constants")
|
||||
|
||||
--- Add a log entry to the panel buffer with highlighting
|
||||
---@param entry table Log entry
|
||||
local function add_log_entry(entry)
|
||||
if not state.buf or not vim.api.nvim_buf_is_valid(state.buf) then
|
||||
return
|
||||
end
|
||||
|
||||
vim.schedule(function()
|
||||
if not state.buf or not vim.api.nvim_buf_is_valid(state.buf) then
|
||||
return
|
||||
end
|
||||
|
||||
if entry.level == "clear" then
|
||||
vim.bo[state.buf].modifiable = true
|
||||
vim.api.nvim_buf_set_lines(state.buf, 0, -1, false, {
|
||||
"Generation Logs",
|
||||
string.rep("─", constants.LOGS_WIDTH - 2),
|
||||
"",
|
||||
})
|
||||
vim.bo[state.buf].modifiable = false
|
||||
return
|
||||
end
|
||||
|
||||
vim.bo[state.buf].modifiable = true
|
||||
|
||||
local formatted = logs.format_entry(entry)
|
||||
local formatted_lines = vim.split(formatted, "\n", { plain = true })
|
||||
local line_count = vim.api.nvim_buf_line_count(state.buf)
|
||||
|
||||
vim.api.nvim_buf_set_lines(state.buf, -1, -1, false, formatted_lines)
|
||||
|
||||
local highlight_map = {
|
||||
info = "DiagnosticInfo",
|
||||
debug = "Comment",
|
||||
request = "DiagnosticWarn",
|
||||
response = "DiagnosticOk",
|
||||
tool = "DiagnosticHint",
|
||||
error = "DiagnosticError",
|
||||
}
|
||||
|
||||
local highlight_group = highlight_map[entry.level] or "Normal"
|
||||
for line_offset = 0, #formatted_lines - 1 do
|
||||
vim.api.nvim_buf_add_highlight(state.buf, constants.ns_logs, highlight_group, line_count + line_offset, 0, -1)
|
||||
end
|
||||
|
||||
vim.bo[state.buf].modifiable = false
|
||||
|
||||
if state.win and vim.api.nvim_win_is_valid(state.win) then
|
||||
local new_line_count = vim.api.nvim_buf_line_count(state.buf)
|
||||
pcall(vim.api.nvim_win_set_cursor, state.win, { new_line_count, 0 })
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return add_log_entry
|
||||
45
lua/codetyper/adapters/nvim/ui/logs_panel/close.lua
Normal file
45
lua/codetyper/adapters/nvim/ui/logs_panel/close.lua
Normal file
@@ -0,0 +1,45 @@
|
||||
local state = require("codetyper.state.state")
|
||||
local logs = require("codetyper.adapters.nvim.ui.logs")
|
||||
local queue = require("codetyper.core.events.queue")
|
||||
|
||||
--- Close the logs panel and clean up listeners, windows, buffers
|
||||
---@param force? boolean Force close even if not marked as open
|
||||
local function close(force)
|
||||
if not state.is_open and not force then
|
||||
return
|
||||
end
|
||||
|
||||
if state.listener_id then
|
||||
pcall(logs.remove_listener, state.listener_id)
|
||||
state.listener_id = nil
|
||||
end
|
||||
|
||||
if state.queue_listener_id then
|
||||
pcall(queue.remove_listener, state.queue_listener_id)
|
||||
state.queue_listener_id = nil
|
||||
end
|
||||
|
||||
if state.queue_win then
|
||||
pcall(vim.api.nvim_win_close, state.queue_win, true)
|
||||
state.queue_win = nil
|
||||
end
|
||||
|
||||
if state.win then
|
||||
pcall(vim.api.nvim_win_close, state.win, true)
|
||||
state.win = nil
|
||||
end
|
||||
|
||||
if state.queue_buf then
|
||||
pcall(vim.api.nvim_buf_delete, state.queue_buf, { force = true })
|
||||
state.queue_buf = nil
|
||||
end
|
||||
|
||||
if state.buf then
|
||||
pcall(vim.api.nvim_buf_delete, state.buf, { force = true })
|
||||
state.buf = nil
|
||||
end
|
||||
|
||||
state.is_open = false
|
||||
end
|
||||
|
||||
return close
|
||||
8
lua/codetyper/adapters/nvim/ui/logs_panel/constants.lua
Normal file
8
lua/codetyper/adapters/nvim/ui/logs_panel/constants.lua
Normal file
@@ -0,0 +1,8 @@
|
||||
local constants = {
|
||||
ns_logs = vim.api.nvim_create_namespace("codetyper_logs_panel"),
|
||||
ns_queue = vim.api.nvim_create_namespace("codetyper_queue_panel"),
|
||||
LOGS_WIDTH = 60,
|
||||
QUEUE_HEIGHT = 8,
|
||||
}
|
||||
|
||||
return constants
|
||||
11
lua/codetyper/adapters/nvim/ui/logs_panel/ensure_open.lua
Normal file
11
lua/codetyper/adapters/nvim/ui/logs_panel/ensure_open.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
local state = require("codetyper.state.state")
|
||||
local open = require("codetyper.adapters.nvim.ui.logs_panel.open")
|
||||
|
||||
--- Ensure the logs panel is open (call before starting generation)
|
||||
local function ensure_open()
|
||||
if not state.is_open then
|
||||
open()
|
||||
end
|
||||
end
|
||||
|
||||
return ensure_open
|
||||
9
lua/codetyper/adapters/nvim/ui/logs_panel/is_open.lua
Normal file
9
lua/codetyper/adapters/nvim/ui/logs_panel/is_open.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
local state = require("codetyper.state.state")
|
||||
|
||||
--- Check if the logs panel is open
|
||||
---@return boolean
|
||||
local function is_open()
|
||||
return state.is_open
|
||||
end
|
||||
|
||||
return is_open
|
||||
90
lua/codetyper/adapters/nvim/ui/logs_panel/open.lua
Normal file
90
lua/codetyper/adapters/nvim/ui/logs_panel/open.lua
Normal file
@@ -0,0 +1,90 @@
|
||||
local state = require("codetyper.state.state")
|
||||
local logs = require("codetyper.adapters.nvim.ui.logs")
|
||||
local queue = require("codetyper.core.events.queue")
|
||||
local constants = require("codetyper.adapters.nvim.ui.logs_panel.constants")
|
||||
local add_log_entry = require("codetyper.adapters.nvim.ui.logs_panel.add_log_entry")
|
||||
local update_title = require("codetyper.adapters.nvim.ui.logs_panel.update_title")
|
||||
local update_queue_display = require("codetyper.adapters.nvim.ui.logs_panel.update_queue_display")
|
||||
local close = require("codetyper.adapters.nvim.ui.logs_panel.close")
|
||||
|
||||
--- Open the logs panel with logs window and queue window
|
||||
local function open()
|
||||
if state.is_open then
|
||||
return
|
||||
end
|
||||
|
||||
logs.clear()
|
||||
|
||||
state.buf = vim.api.nvim_create_buf(false, true)
|
||||
vim.bo[state.buf].buftype = "nofile"
|
||||
vim.bo[state.buf].bufhidden = "hide"
|
||||
vim.bo[state.buf].swapfile = false
|
||||
|
||||
vim.cmd("botright vsplit")
|
||||
state.win = vim.api.nvim_get_current_win()
|
||||
vim.api.nvim_win_set_buf(state.win, state.buf)
|
||||
vim.api.nvim_win_set_width(state.win, constants.LOGS_WIDTH)
|
||||
|
||||
vim.wo[state.win].number = false
|
||||
vim.wo[state.win].relativenumber = false
|
||||
vim.wo[state.win].signcolumn = "no"
|
||||
vim.wo[state.win].wrap = true
|
||||
vim.wo[state.win].linebreak = true
|
||||
vim.wo[state.win].winfixwidth = true
|
||||
vim.wo[state.win].cursorline = false
|
||||
|
||||
vim.bo[state.buf].modifiable = true
|
||||
vim.api.nvim_buf_set_lines(state.buf, 0, -1, false, {
|
||||
"Generation Logs",
|
||||
string.rep("─", constants.LOGS_WIDTH - 2),
|
||||
"",
|
||||
})
|
||||
vim.bo[state.buf].modifiable = false
|
||||
|
||||
state.queue_buf = vim.api.nvim_create_buf(false, true)
|
||||
vim.bo[state.queue_buf].buftype = "nofile"
|
||||
vim.bo[state.queue_buf].bufhidden = "hide"
|
||||
vim.bo[state.queue_buf].swapfile = false
|
||||
|
||||
vim.cmd("belowright split")
|
||||
state.queue_win = vim.api.nvim_get_current_win()
|
||||
vim.api.nvim_win_set_buf(state.queue_win, state.queue_buf)
|
||||
vim.api.nvim_win_set_height(state.queue_win, constants.QUEUE_HEIGHT)
|
||||
|
||||
vim.wo[state.queue_win].number = false
|
||||
vim.wo[state.queue_win].relativenumber = false
|
||||
vim.wo[state.queue_win].signcolumn = "no"
|
||||
vim.wo[state.queue_win].wrap = true
|
||||
vim.wo[state.queue_win].linebreak = true
|
||||
vim.wo[state.queue_win].winfixheight = true
|
||||
vim.wo[state.queue_win].cursorline = false
|
||||
|
||||
local logs_keymap_opts = { buffer = state.buf, noremap = true, silent = true }
|
||||
vim.keymap.set("n", "q", close, logs_keymap_opts)
|
||||
vim.keymap.set("n", "<Esc>", close, logs_keymap_opts)
|
||||
|
||||
local queue_keymap_opts = { buffer = state.queue_buf, noremap = true, silent = true }
|
||||
vim.keymap.set("n", "q", close, queue_keymap_opts)
|
||||
vim.keymap.set("n", "<Esc>", close, queue_keymap_opts)
|
||||
|
||||
state.listener_id = logs.add_listener(function(entry)
|
||||
add_log_entry(entry)
|
||||
if entry.level == "response" then
|
||||
vim.schedule(update_title)
|
||||
end
|
||||
end)
|
||||
|
||||
state.queue_listener_id = queue.add_listener(function()
|
||||
update_queue_display()
|
||||
end)
|
||||
|
||||
update_queue_display()
|
||||
|
||||
state.is_open = true
|
||||
|
||||
vim.cmd("wincmd p")
|
||||
|
||||
logs.info("Logs panel opened")
|
||||
end
|
||||
|
||||
return open
|
||||
35
lua/codetyper/adapters/nvim/ui/logs_panel/setup.lua
Normal file
35
lua/codetyper/adapters/nvim/ui/logs_panel/setup.lua
Normal file
@@ -0,0 +1,35 @@
|
||||
local close = require("codetyper.adapters.nvim.ui.logs_panel.close")
|
||||
|
||||
--- Setup autocmds for the logs panel
|
||||
local function setup()
|
||||
local group = vim.api.nvim_create_augroup("CodetypeLogsPanel", { clear = true })
|
||||
|
||||
vim.api.nvim_create_autocmd("VimLeavePre", {
|
||||
group = group,
|
||||
callback = function()
|
||||
close(true)
|
||||
end,
|
||||
desc = "Close logs panel before exiting Neovim",
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd("QuitPre", {
|
||||
group = group,
|
||||
callback = function()
|
||||
local wins = vim.api.nvim_list_wins()
|
||||
local real_wins = 0
|
||||
for _, win in ipairs(wins) do
|
||||
local buf = vim.api.nvim_win_get_buf(win)
|
||||
local buftype = vim.bo[buf].buftype
|
||||
if buftype == "" or buftype == "help" then
|
||||
real_wins = real_wins + 1
|
||||
end
|
||||
end
|
||||
if real_wins <= 1 then
|
||||
close(true)
|
||||
end
|
||||
end,
|
||||
desc = "Close logs panel on quit",
|
||||
})
|
||||
end
|
||||
|
||||
return setup
|
||||
14
lua/codetyper/adapters/nvim/ui/logs_panel/toggle.lua
Normal file
14
lua/codetyper/adapters/nvim/ui/logs_panel/toggle.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
local state = require("codetyper.state.state")
|
||||
local open = require("codetyper.adapters.nvim.ui.logs_panel.open")
|
||||
local close = require("codetyper.adapters.nvim.ui.logs_panel.close")
|
||||
|
||||
--- Toggle the logs panel open/closed
|
||||
local function toggle()
|
||||
if state.is_open then
|
||||
close()
|
||||
else
|
||||
open()
|
||||
end
|
||||
end
|
||||
|
||||
return toggle
|
||||
@@ -0,0 +1,72 @@
|
||||
local state = require("codetyper.state.state")
|
||||
local queue = require("codetyper.core.events.queue")
|
||||
local constants = require("codetyper.adapters.nvim.ui.logs_panel.constants")
|
||||
|
||||
--- Update the queue display buffer with pending and processing events
|
||||
local function update_queue_display()
|
||||
if not state.queue_buf or not vim.api.nvim_buf_is_valid(state.queue_buf) then
|
||||
return
|
||||
end
|
||||
|
||||
vim.schedule(function()
|
||||
if not state.queue_buf or not vim.api.nvim_buf_is_valid(state.queue_buf) then
|
||||
return
|
||||
end
|
||||
|
||||
vim.bo[state.queue_buf].modifiable = true
|
||||
|
||||
local lines = {
|
||||
"Queue",
|
||||
string.rep("─", constants.LOGS_WIDTH - 2),
|
||||
}
|
||||
|
||||
local pending_events = queue.get_pending()
|
||||
local processing_events = queue.get_processing()
|
||||
|
||||
for _, event in ipairs(processing_events) do
|
||||
local filename = vim.fn.fnamemodify(event.target_path or "", ":t")
|
||||
local line_num = event.range and event.range.start_line or 0
|
||||
local prompt_preview = (event.prompt_content or ""):sub(1, 25):gsub("\n", " ")
|
||||
if #(event.prompt_content or "") > 25 then
|
||||
prompt_preview = prompt_preview .. "..."
|
||||
end
|
||||
table.insert(lines, string.format("▶ %s:%d %s", filename, line_num, prompt_preview))
|
||||
end
|
||||
|
||||
for _, event in ipairs(pending_events) do
|
||||
local filename = vim.fn.fnamemodify(event.target_path or "", ":t")
|
||||
local line_num = event.range and event.range.start_line or 0
|
||||
local prompt_preview = (event.prompt_content or ""):sub(1, 25):gsub("\n", " ")
|
||||
if #(event.prompt_content or "") > 25 then
|
||||
prompt_preview = prompt_preview .. "..."
|
||||
end
|
||||
table.insert(lines, string.format("○ %s:%d %s", filename, line_num, prompt_preview))
|
||||
end
|
||||
|
||||
if #pending_events == 0 and #processing_events == 0 then
|
||||
table.insert(lines, " (empty)")
|
||||
end
|
||||
|
||||
vim.api.nvim_buf_set_lines(state.queue_buf, 0, -1, false, lines)
|
||||
|
||||
vim.api.nvim_buf_clear_namespace(state.queue_buf, constants.ns_queue, 0, -1)
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, constants.ns_queue, "Title", 0, 0, -1)
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, constants.ns_queue, "Comment", 1, 0, -1)
|
||||
|
||||
local highlight_line = 2
|
||||
for _ = 1, #processing_events do
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, constants.ns_queue, "DiagnosticWarn", highlight_line, 0, 1)
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, constants.ns_queue, "String", highlight_line, 2, -1)
|
||||
highlight_line = highlight_line + 1
|
||||
end
|
||||
for _ = 1, #pending_events do
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, constants.ns_queue, "Comment", highlight_line, 0, 1)
|
||||
vim.api.nvim_buf_add_highlight(state.queue_buf, constants.ns_queue, "Normal", highlight_line, 2, -1)
|
||||
highlight_line = highlight_line + 1
|
||||
end
|
||||
|
||||
vim.bo[state.queue_buf].modifiable = false
|
||||
end)
|
||||
end
|
||||
|
||||
return update_queue_display
|
||||
21
lua/codetyper/adapters/nvim/ui/logs_panel/update_title.lua
Normal file
21
lua/codetyper/adapters/nvim/ui/logs_panel/update_title.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
local state = require("codetyper.state.state")
|
||||
local logs = require("codetyper.adapters.nvim.ui.logs")
|
||||
|
||||
--- Update the panel title with token counts and provider info
|
||||
local function update_title()
|
||||
if not state.win or not vim.api.nvim_win_is_valid(state.win) then
|
||||
return
|
||||
end
|
||||
|
||||
local prompt_tokens, response_tokens = logs.get_token_totals()
|
||||
local provider, _ = logs.get_provider_info()
|
||||
|
||||
if provider and state.buf and vim.api.nvim_buf_is_valid(state.buf) then
|
||||
vim.bo[state.buf].modifiable = true
|
||||
local title = string.format("%s | %d/%d tokens", (provider or ""):upper(), prompt_tokens, response_tokens)
|
||||
vim.api.nvim_buf_set_lines(state.buf, 0, 1, false, { title })
|
||||
vim.bo[state.buf].modifiable = false
|
||||
end
|
||||
end
|
||||
|
||||
return update_title
|
||||
@@ -17,6 +17,10 @@ local state = {
|
||||
total_response_tokens = 0,
|
||||
current_provider = nil,
|
||||
current_model = nil,
|
||||
queue_buf = nil,
|
||||
queue_win = nil,
|
||||
listener_id = nil,
|
||||
queue_listener_id = nil,
|
||||
}
|
||||
|
||||
return state
|
||||
|
||||
Reference in New Issue
Block a user