From a9ebcd2aaeadba6ccf4e39bfb993e337c83e9352 Mon Sep 17 00:00:00 2001 From: theprimeagain Date: Sun, 22 Feb 2026 07:32:21 -0700 Subject: state refactor --- lua/99/init.lua | 175 +++--------------------------------------------------- lua/99/prompt.lua | 2 +- lua/99/state.lua | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 169 deletions(-) create mode 100644 lua/99/state.lua (limited to 'lua') diff --git a/lua/99/init.lua b/lua/99/init.lua index 500c6dc..4dffdfc 100644 --- a/lua/99/init.lua +++ b/lua/99/init.lua @@ -4,8 +4,7 @@ local ops = require("99.ops") local Languages = require("99.language") local Window = require("99.window") local Prompt = require("99.prompt") -local geo = require("99.geo") -local Range = geo.Range +local State = require("99.state") local Extensions = require("99.extensions") local Agents = require("99.extensions.agents") local Providers = require("99.providers") @@ -38,38 +37,6 @@ local function process_opts(opts) return opts end ---- @class _99.StateProps ---- @field model string ---- @field md_files string[] ---- @field prompts _99.Prompts ---- @field ai_stdout_rows number ---- @field show_in_flight_requests boolean ---- @field languages string[] ---- @field display_errors boolean ---- @field auto_add_skills boolean ---- @field provider_override _99.Providers.BaseProvider? ---- @field __view_log_idx number ---- @field __tmp_dir string | nil - ---- @return _99.StateProps -local function create_99_state() - return { - model = "opencode/claude-sonnet-4-5", - md_files = {}, - prompts = require("99.prompt-settings"), - ai_stdout_rows = 3, - show_in_flight_requests = false, - languages = { "lua", "go", "java", "elixir", "cpp", "ruby" }, - display_errors = false, - provider_override = nil, - auto_add_skills = false, - __view_log_idx = 1, - __request_history = {}, - __request_by_id = {}, - tmp_dir = nil, - } -end - --- @class _99.Completion --- @field source "cmp" | "blink" | nil --- @field custom_rules string[] @@ -87,126 +54,8 @@ end --- @field completion _99.Completion? --- @field tmp_dir? string ---- unanswered question -- will i need to queue messages one at a time or ---- just send them all... So to prepare ill be sending around this state object ---- @class _99.State ---- @field completion _99.Completion ---- @field model string ---- @field md_files string[] ---- @field prompts _99.Prompts ---- @field ai_stdout_rows number ---- @field languages string[] ---- @field display_errors boolean ---- @field show_in_flight_requests boolean ---- @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 ---- @field __active_marks _99.Mark[] ---- @field __tmp_dir string | nil -local _99_State = {} -_99_State.__index = _99_State - ---- @return _99.State -function _99_State.new() - local props = create_99_state() - ---@diagnostic disable-next-line: return-type-mismatch - return setmetatable(props, _99_State) -end - ---- @return string -function _99_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 -end - ---- TODO: This is something to understand. I bet that this is going to need ---- a lot of performance tuning. I am just reading every file, and this could ---- take a decent amount of time if there are lots of rules. ---- ---- Simple perfs: ---- 1. read 4096 bytes at a tiem instead of whole file and parse out lines ---- 2. don't show the docs ---- 3. do the operation once at setup instead of every time. ---- likely not needed to do this all the time. -function _99_State:refresh_rules() - self.rules = Agents.rules(self) - Extensions.refresh(self) -end - ---- @param tutorial _99.Prompt.Data.Tutorial -function _99_State:open_tutorial(tutorial) - -- TODO: this is a task item for when i start the work item "Tutorial Navigation" - _ = self - _ = tutorial -end - ---- @param context _99.Prompt -function _99_State:track_request(context) - assert(context:valid(), "context is not valid") - table.insert(self.__request_history, context) - self.__request_by_id[context.xid] = context -end - ---- @return number -function _99_State:previous_request_count() - local count = 0 - for _, entry in ipairs(self.__request_history) do - if entry.state ~= "requesting" then - count = count + 1 - end - end - return count -end - -function _99_State:clear_previous_requests() - local keep = {} - for _, entry in ipairs(self.__request_history) do - if entry.state == "requesting" then - table.insert(keep, entry) - else - self.__request_by_id[entry.xid] = nil - end - end - self.__request_history = keep -end - ---- @param mark _99.Mark -function _99_State:add_mark(mark) - table.insert(self.__active_marks, mark) -end - -function _99_State:active_request_count() - local count = 0 - for _, r in pairs(self.__request_history) do - if r.state == "requesting" then - count = count + 1 - end - end - return count -end - ---- @param type "search" | "visual" | "tutorial" ---- @return _99.Prompt.Data -function _99_State:get_request_data_by_type(type) - local out = {} - for _, r in ipairs(self.__request_history) do - local data = r.data - if data and data.type == type then - table.insert(out, data) - end - end - return out -end - -local _99_state = _99_State.new() +--- @type _99.State +local _99_state --- @class _99 local _99 = { @@ -259,7 +108,7 @@ function _99.info() _99_state:refresh_rules() table.insert( info, - string.format("Previous Requests: %d", _99_state:previous_request_count()) + string.format("Previous Requests: %d", _99_state:completed_prompts()) ) table.insert( info, @@ -424,7 +273,7 @@ function _99.qfix_search_results(xid) end function _99.clear_previous_requests() - _99_state:clear_previous_requests() + _99_state:clear_history() end --- if you touch this function you will be fired @@ -495,22 +344,12 @@ end function _99.setup(opts) opts = opts or {} - _99_state = _99_State.new() - _99_state.show_in_flight_requests = opts.show_in_flight_requests or false - _99_state.provider_override = opts.provider - _99_state.completion = opts.completion - or { - source = nil, - custom_rules = {}, - } - _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 {} + _99_state = State.new(opts) local crules = _99_state.completion.custom_rules for i, rule in ipairs(crules) do local str = expand(rule) - assert(type(str) == "string", "rule path must be a string") + assert(type(str) == "string", "error parsing rule: path must be a string") crules[i] = str end diff --git a/lua/99/prompt.lua b/lua/99/prompt.lua index 690c94d..ec1d0ae 100644 --- a/lua/99/prompt.lua +++ b/lua/99/prompt.lua @@ -178,7 +178,7 @@ function Prompt:_observer(obs) return { on_start = function() self.state = "requesting" - self._99:track_request(self) + self._99:track_prompt_request(self) if obs then obs.on_start() diff --git a/lua/99/state.lua b/lua/99/state.lua new file mode 100644 index 0000000..790d0ed --- /dev/null +++ b/lua/99/state.lua @@ -0,0 +1,169 @@ +local Agents = require("99.extensions.agents") +local Extensions = require("99.extensions") + +--- @class _99.StateProps +--- @field model string +--- @field md_files string[] +--- @field prompts _99.Prompts +--- @field ai_stdout_rows number +--- @field show_in_flight_requests boolean +--- @field languages string[] +--- @field display_errors boolean +--- @field auto_add_skills boolean +--- @field provider_override _99.Providers.BaseProvider | nil +--- @field __view_log_idx number +--- @field __tmp_dir string | nil + +--- unanswered question -- will i need to queue messages one at a time or +--- just send them all... So to prepare ill be sending around this state object +--- @class _99.State +--- @field completion _99.Completion +--- @field model string +--- @field md_files string[] +--- @field prompts _99.Prompts +--- @field ai_stdout_rows number +--- @field languages string[] +--- @field display_errors boolean +--- @field show_in_flight_requests boolean +--- @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 +--- @field __active_marks _99.Mark[] +--- @field __tmp_dir string | nil +local State = {} +State.__index = State + +--- @return _99.StateProps +local function create() + return { + model = "opencode/claude-sonnet-4-5", + md_files = {}, + prompts = require("99.prompt-settings"), + ai_stdout_rows = 3, + show_in_flight_requests = false, + languages = { "lua", "go", "java", "elixir", "cpp", "ruby" }, + display_errors = false, + provider_override = nil, + auto_add_skills = false, + __view_log_idx = 1, + __request_history = {}, + __request_by_id = {}, + tmp_dir = nil, + } +end + +--- @param opts _99.Options +--- @return _99.State +function State.new(opts) + local props = create() + local _99_state = setmetatable(props, State) --[[@as _99.State]] + + _99_state.show_in_flight_requests = opts.show_in_flight_requests or false + _99_state.provider_override = opts.provider + _99_state.completion = opts.completion + or { + source = nil, + custom_rules = {}, + } + _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 {} + + 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 +end + +--- TODO: This is something to understand. I bet that this is going to need +--- a lot of performance tuning. I am just reading every file, and this could +--- take a decent amount of time if there are lots of rules. +--- +--- Simple perfs: +--- 1. read 4096 bytes at a tiem instead of whole file and parse out lines +--- 2. don't show the docs +--- 3. do the operation once at setup instead of every time. +--- likely not needed to do this all the time. +function State:refresh_rules() + self.rules = Agents.rules(self) + Extensions.refresh(self) +end + +--- @param context _99.Prompt +function State:track_prompt_request(context) + assert(context:valid(), "context is not valid") + table.insert(self.__request_history, context) + self.__request_by_id[context.xid] = context +end + +--- @return number +function State:completed_prompts() + local count = 0 + for _, entry in ipairs(self.__request_history) do + if entry.state ~= "requesting" then + count = count + 1 + end + end + return count +end + +function State:clear_history() + local keep = {} + for _, entry in ipairs(self.__request_history) do + if entry.state == "requesting" then + table.insert(keep, entry) + else + self.__request_by_id[entry.xid] = nil + end + end + self.__request_history = keep +end + +--- @param mark _99.Mark +function State:add_mark(mark) + table.insert(self.__active_marks, mark) +end + +--- @param mark _99.Mark +function State:clear_marks(mark) + for _, active_mark in ipairs(self.__active_marks or {}) do + active_mark:delete() + end + self.__active_marks = {} +end + +function State:active_request_count() + local count = 0 + for _, r in pairs(self.__request_history) do + if r.state == "requesting" then + count = count + 1 + end + end + return count +end + +--- @param type "search" | "visual" | "tutorial" +--- @return _99.Prompt.Data +function State:get_request_data_by_type(type) + local out = {} + for _, r in ipairs(self.__request_history) do + local data = r.data + if data and data.type == type then + table.insert(out, data) + end + end + return out +end + +return State -- cgit v1.3-3-g829e