1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
local Agents = require("99.extensions.agents")
local Extensions = require("99.extensions")
local function default_completion()
return { source = nil, custom_rules = {} }
end
--- @class _99.StateProps
--- @field model string
--- @field md_files string[]
--- @field prompts _99.Prompts
--- @field ai_stdout_rows number
--- @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 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[]
--- @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,
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.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 {}
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
--- @return _99.Prompt[]
function State:requests()
return self.__request_history
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
function State:clear_marks()
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[]
function State:request_by_type(type)
local out = {} --[[ @as _99.Prompt[] ]]
for _, r in ipairs(self.__request_history) do
if r.operation == type then
table.insert(out, r)
end
end
return out
end
return State
|