diff options
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/99/init.lua | 7 | ||||
| -rw-r--r-- | lua/99/prompt.lua | 4 | ||||
| -rw-r--r-- | lua/99/state.lua | 44 | ||||
| -rw-r--r-- | lua/99/state/tracking.lua | 21 | ||||
| -rw-r--r-- | lua/99/utils.lua | 17 | ||||
| -rw-r--r-- | lua/99/window/status-window.lua (renamed from lua/99/window/in-flight.lua) | 120 |
6 files changed, 155 insertions, 58 deletions
diff --git a/lua/99/init.lua b/lua/99/init.lua index 82cf118..2310784 100644 --- a/lua/99/init.lua +++ b/lua/99/init.lua @@ -5,7 +5,7 @@ local Logger = require("99.logger.logger") local Level = require("99.logger.level") local ops = require("99.ops") local Window = require("99.window") -local show_in_flight_requests = require("99.window.in-flight") +local StatusWindow = require("99.window.status-window") local Prompt = require("99.prompt") local State = require("99.state") local Extensions = require("99.extensions") @@ -49,7 +49,7 @@ end --- @docs base --- @field logger? _99.Logger.Options --- @field model? string ---- @field in_flight_options? _99.InFlight.Opts +--- @field in_flight_options? _99.StatusWindow.Opts --- @field md_files? string[] --- @field provider? _99.Providers.BaseProvider --- @field display_errors? boolean @@ -496,7 +496,8 @@ function _99.setup(opts) Extensions.init(_99_state) Extensions.capture_project_root() - show_in_flight_requests(_99_state, _99_state.in_flight_options) + local sw = StatusWindow.new(_99_state, opts.in_flight_options) + sw:start() end --- @param md string diff --git a/lua/99/prompt.lua b/lua/99/prompt.lua index 429ad7b..23b2309 100644 --- a/lua/99/prompt.lua +++ b/lua/99/prompt.lua @@ -51,7 +51,7 @@ local filetype_map = { --- @field xid number TODO: we should probably get rid of this. The request pattern is not quite correct --- @field tutorial string[] ---- @class _99.Prompt +--- @class _99.Prompt.Properties --- @field md_file_names string[] --- @field model string --- @field user_prompt string @@ -65,6 +65,8 @@ local filetype_map = { --- @field marks table<string, _99.Mark> --- @field logger _99.Logger --- @field xid number + +--- @class _99.Prompt : _99.Prompt.Properties --- @field clean_ups (fun(): nil)[] --- @field _99 _99.State ---@diagnostic disable-next-line: undefined-doc-name diff --git a/lua/99/state.lua b/lua/99/state.lua index 2182c98..050a5c4 100644 --- a/lua/99/state.lua +++ b/lua/99/state.lua @@ -1,3 +1,4 @@ +local utils = require("99.utils") local Agents = require("99.extensions.agents") local Extensions = require("99.extensions") @@ -25,13 +26,8 @@ end --- @field prompts _99.Prompts --- @field ai_stdout_rows number --- @field display_errors boolean ---- @field in_flight_options _99.InFlight.Opts | nil ---- @field show_in_flight_requests_window _99.window.Window | nil ---- @field show_in_flight_requests_throbber _99.Throbber | nil --- @field provider_override _99.Providers.BaseProvider? ---- @field auto_add_skills boolean --- @field rules _99.Agents.Rules ---- @field __view_log_idx number --- @field __request_history _99.Prompt[] --- @field __request_by_id table<number, _99.Prompt> --- @field __active_marks _99.Mark[] @@ -44,41 +40,59 @@ local function create() return { model = "opencode/claude-sonnet-4-5", md_files = {}, - prompts = require("99.prompt-settings"), ai_stdout_rows = 3, display_errors = false, provider_override = nil, - auto_add_skills = false, - __view_log_idx = 1, __request_history = {}, __request_by_id = {}, tmp_dir = nil, } end +--- @param oos _99.Options | _99.State +local function get_tmp_dir(oos) + local tmp_dir = oos.tmp_dir and type(oos.tmp_dir) == "string" and oos.tmp_dir + or oos.__tmp_dir and oos.__tmp_dir + or "./tmp" + if tmp_dir then + tmp_dir = vim.fn.expand(tmp_dir) + end + return tmp_dir +end + +--- @param opts _99.Options +--- @return _99.StateProps | nil +local function read_state_from_tmp(opts) + local state_file = utils.named_tmp_file(get_tmp_dir(opts), "99-state") + local fd = vim.uv.fs_open(state_file, "r", 438) + if not fd then + return nil + end + return utils.read_file_json_safe(state_file) --[[@as _99.StateProps]] +end + --- @param opts _99.Options --- @return _99.State function State.new(opts) - local props = create() + local props = read_state_from_tmp(opts) or create() local _99_state = setmetatable(props, State) --[[@as _99.State]] _99_state.in_flight_options = opts.in_flight_options or { enable = true } _99_state.provider_override = opts.provider _99_state.completion = opts.completion or default_completion() _99_state.completion.custom_rules = _99_state.completion.custom_rules or {} - _99_state.auto_add_skills = opts.auto_add_skills or false _99_state.completion.files = _99_state.completion.files or {} + --- TODO: Prompt overrides would be a great thing, we just have to get there + --- for now, i am going to have this as just a hardcoded ... thing + _99_state.prompts = require("99.prompt-settings") + return _99_state end --- @return string function State:tmp_dir() - local tmp_dir = self.__tmp_dir or "./tmp" - if tmp_dir then - tmp_dir = vim.fn.expand(tmp_dir) - end - return tmp_dir + return get_tmp_dir(self) end --- TODO: This is something to understand. I bet that this is going to need diff --git a/lua/99/state/tracking.lua b/lua/99/state/tracking.lua new file mode 100644 index 0000000..afcddd0 --- /dev/null +++ b/lua/99/state/tracking.lua @@ -0,0 +1,21 @@ +-- --- @class _99.State.Tracking.Options +-- --- @field __request_history _99.Prompt[] | nil +-- --- vj +-- --- @field __request_by_id table<number, _99.Prompt> | nil +-- --- v +-- --- @field __active_marks _99.Mark[] | nil +-- +-- --- @class _99.State.Tracking +-- --- @field __request_history _99.Prompt[] +-- --- @field __request_by_id table<number, _99.Prompt> +-- --- @field __active_marks _99.Mark[] +-- local Tracking = {} +-- +-- --- @param previous_state +-- function Tracking.new(previous_state) +-- end +-- +-- +-- return Tracking +-- +return {} diff --git a/lua/99/utils.lua b/lua/99/utils.lua index e15e178..724b3c6 100644 --- a/lua/99/utils.lua +++ b/lua/99/utils.lua @@ -40,4 +40,21 @@ function M.named_tmp_file(dir, name) return string.format("%s/99-%s", dir, name) end +--- @param path string +--- @return table | nil +function M.read_file_json_safe(path) + local ok, fh = pcall(io.open, path, "r") + if ok and fh then + local ok2, content = pcall(fh.read, fh, "*a") + pcall(fh.close, fh) + if not ok2 then + return nil + end + local ok3, obj = pcall(vim.json, content) + if ok3 and obj then + return obj + end + end +end + return M diff --git a/lua/99/window/in-flight.lua b/lua/99/window/status-window.lua index 9605688..676042b 100644 --- a/lua/99/window/in-flight.lua +++ b/lua/99/window/status-window.lua @@ -2,8 +2,21 @@ local Window = require("99.window") local Consts = require("99.consts") local Throbber = require("99.ops.throbber") ---- @param opts _99.InFlight.Opts | nil ---- @return _99.InFlight.Opts +--- @alias _99.StatusWindow.State "init" | "running" + +--- @class _99.StatusWindow.Opts +--- this is pure a class for testing. helps controls timings +--- @docs include +--- @field throbber_opts _99.Throbber.Opts | nil +--- options for the throbber in the top left +--- @field in_flight_interval number | nil +--- frequency in which the in-flight interval checks to see if it should be +--- displayed / removed +--- @field enable boolean | nil +--- defaults to true + +--- @param opts _99.StatusWindow.Opts | nil +--- @return _99.StatusWindow.Opts local function default_opts(opts) opts = opts or {} opts.throbber_opts = opts.throbber_opts @@ -18,53 +31,56 @@ local function default_opts(opts) return opts end +--- @class _99.StatusWindow +--- @field opts _99.StatusWindow.Opts +--- @field state _99.StatusWindow.State +--- @field win _99.window.Window | nil +--- @field throbber _99.Throbber | nil +--- @field _99 _99.State +local StatusWindow = {} +StatusWindow.__index = StatusWindow + --- @param _99 _99.State -local function shut_down_in_flight_requests_window(_99) - if _99.show_in_flight_requests_throbber then - _99.show_in_flight_requests_throbber:stop() +--- @param opts _99.StatusWindow.Opts | nil +function StatusWindow.new(_99, opts) + return setmetatable({ + opts = default_opts(opts), + state = "init", + _99 = _99, + }, StatusWindow) +end + +function StatusWindow:_shutdown_status_window() + if self.throbber then + self.throbber:stop() end - local win = _99.show_in_flight_requests_window + local win = self.win if win ~= nil then Window.close(win) end - _99.show_in_flight_requests_window = nil - _99.show_in_flight_requests_throbber = nil + self.win = nil + self.throbber = nil end ---- @class _99.InFlight.Opts ---- this is pure a class for testing. helps controls timings ---- @docs include ---- @field throbber_opts _99.Throbber.Opts | nil ---- options for the throbber in the top left ---- @field in_flight_interval number | nil ---- frequency in which the in-flight interval checks to see if it should be ---- displayed / removed ---- @field enable boolean | nil ---- defaults to true - ---- @param _99 _99.State ---- @param opts _99.InFlight.Opts | nil -local function show_in_flight_requests(_99, opts) - --- TODO: I dont like this. i dont like that i have to redo this every single - --- time i cycle, but its not a big deal right now. either way ill address this later - opts = default_opts(opts) - if opts.enable == false then +function StatusWindow:_run_loop() + if self.state ~= "running" then + self:_shutdown_status_window() return end vim.defer_fn(function() - show_in_flight_requests(_99, opts) - end, opts.in_flight_interval) + self:_run_loop() + end, self.opts.in_flight_interval) Window.refresh_active_windows() - local current_win = _99.show_in_flight_requests_window + local current_win = self.win if current_win ~= nil and not Window.is_active_window(current_win) then - shut_down_in_flight_requests_window(_99) + self:_shutdown_status_window() end local active_window = Window.has_active_status_window() local active_other_window = Window.has_active_windows() - local active_requests = _99:active_request_count() + local active_requests = self._99:active_request_count() if active_window == false and active_other_window or active_window and active_requests > 0 @@ -73,7 +89,7 @@ local function show_in_flight_requests(_99, opts) return end - if _99.show_in_flight_requests_window == nil then + if current_win == nil then local ok, win = pcall(Window.status_window) if not ok then --- TODO: There needs to be a way to display logs for "all active requests" @@ -82,11 +98,11 @@ local function show_in_flight_requests(_99, opts) end local throb = Throbber.new(function(throb) - local count = _99:active_request_count() + local count = self._99:active_request_count() local win_valid = Window.valid(win) if count == 0 or not win_valid then - return shut_down_in_flight_requests_window(_99) + return self:_shutdown_status_window() end --- @type string[] @@ -94,7 +110,7 @@ local function show_in_flight_requests(_99, opts) throb .. " requests(" .. tostring(count) .. ") " .. throb, } - for _, c in pairs(_99.__request_by_id) do + for _, c in pairs(self._99.__request_by_id) do if c.state == "requesting" then table.insert(lines, c.operation) end @@ -102,13 +118,39 @@ local function show_in_flight_requests(_99, opts) Window.resize(win, #lines[1], #lines) vim.api.nvim_buf_set_lines(win.buf_id, 0, -1, false, lines) - end, opts.throbber_opts) + end, self.opts.throbber_opts) - _99.show_in_flight_requests_window = win - _99.show_in_flight_requests_throbber = throb + self.win = win + self.throbber = throb throb:start() end end -return show_in_flight_requests +function StatusWindow:start() + if not self.opts.enable then + return + end + + assert( + self.state == "init", + "you cannot start an inflight request if we are not in init state: " + .. self.state + ) + + self.state = "running" + self:_run_loop() +end + +function StatusWindow:stop() + if not self.opts.enable then + return + end + assert( + self.state == "running", + "you cannot stop a running status window if its not running" + ) + self.state = "init" +end + +return StatusWindow |
