diff options
| author | Bogdan Nikolov <84232456+0xr3ngar@users.noreply.github.com> | 2026-02-19 20:30:08 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-19 20:30:08 +0100 |
| commit | 725bf38ffc08cb8b537cbff322ef2d889b197dad (patch) | |
| tree | 2fa53c6b40463b8a18d9e175617b9b413a844e70 /lua/99/init.lua | |
| parent | 6d219f47aa29cafb1ec39c41d4dd0a4875a74506 (diff) | |
| parent | d34e4dcbcc1f95d8f31f851baad18da12c59e7df (diff) | |
| download | a4-725bf38ffc08cb8b537cbff322ef2d889b197dad.tar.xz a4-725bf38ffc08cb8b537cbff322ef2d889b197dad.zip | |
Merge branch 'master' into master
Diffstat (limited to 'lua/99/init.lua')
| -rw-r--r-- | lua/99/init.lua | 271 |
1 files changed, 171 insertions, 100 deletions
diff --git a/lua/99/init.lua b/lua/99/init.lua index ad16465..a512ab6 100644 --- a/lua/99/init.lua +++ b/lua/99/init.lua @@ -43,19 +43,22 @@ end --- @alias _99.Cleanup fun(): nil +--- @class _99.RequestEntry.Data.Search +--- @field type "search" +--- @field qfix_items _99.Search.Result[] + +--- @class _99.RequestEntry.Data.Visual +--- @field type "visual" + +-- luacheck: ignore +--- @alias _99.RequestEntry.Data _99.RequestEntry.Data.Search | _99.RequestEntry.Data.Tutorial | _99.RequestEntry.Data.Visual + --- @class _99.RequestEntry ---- @field id number ---- @field operation string ---- @field status "running" | "success" | "failed" | "cancelled" ---- @field filename string ---- @field lnum number ---- @field col number +--- @field context _99.RequestContext +--- @field status _99.Request.State +--- @field point _99.Point --- @field started_at number - ---- @class _99.ActiveRequest ---- @field clean_up _99.Cleanup ---- @field request_id number ---- @field name string +--- @field operation_data _99.RequestEntry.Data | nil --- @class _99.StateProps --- @field model string @@ -67,10 +70,10 @@ end --- @field display_errors boolean --- @field auto_add_skills boolean --- @field provider_override _99.Providers.BaseProvider? ---- @field __active_requests table<number, _99.ActiveRequest> --- @field __view_log_idx number --- @field __request_history _99.RequestEntry[] --- @field __request_by_id table<number, _99.RequestEntry> +--- @field tmp_dir string | nil --- @return _99.StateProps local function create_99_state() @@ -84,15 +87,15 @@ local function create_99_state() display_errors = false, provider_override = nil, auto_add_skills = false, - __active_requests = {}, __view_log_idx = 1, __request_history = {}, __request_by_id = {}, + tmp_dir = nil, } end --- @class _99.Completion ---- @field source "cmp" | nil +--- @field source "cmp" | "blink" | nil --- @field custom_rules string[] --- @field files _99.Files.Config? @@ -106,6 +109,7 @@ end --- @field display_errors? boolean --- @field auto_add_skills? boolean --- @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 @@ -123,11 +127,11 @@ end --- @field provider_override _99.Providers.BaseProvider? --- @field auto_add_skills boolean --- @field rules _99.Agents.Rules ---- @field __active_requests table<number, _99.ActiveRequest> --- @field __view_log_idx number --- @field __request_history _99.RequestEntry[] --- @field __request_by_id table<number, _99.RequestEntry> --- @field __active_marks _99.Mark[] +--- @field tmp_dir string | nil local _99_State = {} _99_State.__index = _99_State @@ -152,49 +156,63 @@ function _99_State:refresh_rules() Extensions.refresh(self) end +--- @param tutorial _99.RequestEntry.Data.Tutorial +function _99_State:open_tutorial(tutorial) end + --- @param context _99.RequestContext --- @return _99.RequestEntry function _99_State:track_request(context) + assert( + context.operation, + "must have an operation defined to track the request" + ) + local point = context.range and context.range.start or Point:from_cursor() local entry = { - id = context.xid, - operation = context.operation or "request", - status = "running", - filename = context.full_path, - lnum = point.row, - col = point.col, + context = context, + status = "requesting", + point = point, started_at = time.now(), + operation_data = nil, } table.insert(self.__request_history, entry) - self.__request_by_id[entry.id] = entry + self.__request_by_id[context.xid] = entry return entry end ---- @param id number ---- @param status "success" | "failed" | "cancelled" -function _99_State:finish_request(id, status) +--- @param context _99.RequestContext +--- @param status _99.Request.ResponseState +function _99_State:finish_request(context, status) + local id = context.xid local entry = self.__request_by_id[id] - if entry then - entry.status = status + if not entry then + return end + + entry.status = status end ---- @param id number -function _99_State:remove_request(id) - for i, entry in ipairs(self.__request_history) do - if entry.id == id then - table.remove(self.__request_history, i) - break - end +--- @param context _99.RequestContext +---@param data _99.RequestEntry.Data +function _99_State:add_data(context, data) + local id = context.xid + local entry = self.__request_by_id[id] + if not entry then + return end - self.__request_by_id[id] = nil + local logger = Logger:set_id(id) + logger:assert( + entry.context.operation == data.type, + "the data type is not the same as the operation" + ) + entry.operation_data = data end --- @return number function _99_State:previous_request_count() local count = 0 for _, entry in ipairs(self.__request_history) do - if entry.status ~= "running" then + if entry.status ~= "requesting" then count = count + 1 end end @@ -204,31 +222,15 @@ end function _99_State:clear_previous_requests() local keep = {} for _, entry in ipairs(self.__request_history) do - if entry.status == "running" then + if entry.status == "requesting" then table.insert(keep, entry) else - self.__request_by_id[entry.id] = nil + self.__request_by_id[entry.context.xid] = nil end end self.__request_history = keep end -local _active_request_id = 0 ----@param clean_up _99.Cleanup ----@param request_id number ----@param name string ----@return number -function _99_State:add_active_request(clean_up, request_id, name) - _active_request_id = _active_request_id + 1 - Logger:debug("adding active request", "id", _active_request_id) - self.__active_requests[_active_request_id] = { - clean_up = clean_up, - request_id = request_id, - name = name, - } - return _active_request_id -end - --- @param mark _99.Mark function _99_State:add_mark(mark) table.insert(self.__active_marks, mark) @@ -236,19 +238,25 @@ end function _99_State:active_request_count() local count = 0 - for _ in pairs(self.__active_requests) do - count = count + 1 + for _, r in pairs(self.__request_history) do + if r.status == "requesting" then + count = count + 1 + end end return count end ----@param id number -function _99_State:remove_active_request(id) - local logger = Logger:set_id(id) - local r = self.__active_requests[id] - logger:assert(r, "there is no active request for id. implementation broken") - logger:debug("removing active request") - self.__active_requests[id] = nil +--- @param type "search" | "visual" | "tutorial" +--- @return _99.RequestEntry.Data +function _99_State:get_request_data_by_type(type) + local out = {} + for _, r in ipairs(self.__request_history) do + local data = r.operation_data + if data and data.type == type then + table.insert(out, data) + end + end + return out end local _99_state = _99_State.new() @@ -275,8 +283,11 @@ end --- @param name string --- @param context _99.RequestContext --- @param opts _99.ops.Opts -local function capture_prompt(cb, name, context, opts) +--- @param capture_content string[] | nil +local function capture_prompt(cb, name, context, opts, capture_content) Window.capture_input(name, { + content = capture_content, + --- @param ok boolean --- @param response string cb = function(ok, response) @@ -333,6 +344,56 @@ function _99.info() Window.display_centered_message(info) end +--- @param tutorials _99.RequestEntry.Data.Tutorial[] +--- @return string[] +local function tutorial_to_string(tutorials) + local out = {} + for _, t in ipairs(tutorials) do + table.insert(out, string.format("%d: %s", t.xid, t.tutorial[1])) + end + return out +end + +--- @param xid number | nil +--- @param opts? _99.window.SplitWindowOpts +function _99.open_tutorial(xid, opts) + opts = opts or { split_direction = "vertical" } + if xid == nil then + local tutorials = _99_state:get_request_data_by_type("tutorial") + if #tutorials == 0 then + print("no tutorials available") + elseif #tutorials == 1 then + local data = tutorials[1].operation_data + assert(data, "tutorial is malformed") + Window.create_split(data.tutorial, data.buffer, opts) + else + local context = get_context("tutorial-lookup") + capture_prompt(function(_, o) + local response = o.additional_prompt + local lines = vim.split(response, "\n") + for _, l in ipairs(lines) do + local id = tonumber(vim.split(l, ":")[1]) + if not id then + error( + "do not alter the tutoria lines, just delete the ones you dont want" + ) + end + local tut = _99_state.__request_by_id[id] + local data = tut and tut.operation_data + assert(data and data.type == "tutorial", "invalid tutorial selected") + Window.create_split(data.tutorial, data.buffer, opts) + end + end, "Select Tutorial", context, {}, tutorial_to_string(tutorials)) + end + return + end + + local tutorial = _99_state.__request_by_id[xid] + local data = tutorial and tutorial.operation_data + assert(data and data.type == "tutorial", "cannot open a non tutorial") + Window.create_split(data.tutorial, data.buffer, opts) +end + --- @param path string function _99:rule_from_path(path) _ = self @@ -341,36 +402,27 @@ function _99:rule_from_path(path) end --- @param opts? _99.ops.SearchOpts +--- @return number function _99.search(opts) local o = process_opts(opts) --[[ @as _99.ops.SearchOpts ]] local context = get_context("search") if o.additional_prompt then ops.search(context, o) - return else capture_prompt(ops.search, "Search", context, o) end + return context.xid end --- @param opts _99.ops.Opts -function _99.visual_prompt(opts) - vim.notify( - "use visual, visual_prompt has been deprecated", - vim.log.levels.WARN - ) - _99.visual(opts) -end - -function _99.fill_in_function() - error( - "function has been removed. Just use visual. I really hate fill in function, sorry :)" - ) -end - -function _99.fill_in_function_prompt() - error( - "function has been removed. Just use visual. I really hate fill in function, sorry :)" - ) +function _99.tutorial(opts) + opts = process_opts(opts) + local context = get_context("tutorial") + if opts.additional_prompt then + ops.tutorial(context, opts) + else + capture_prompt(ops.tutorial, "Tutorial", context, opts) + end end --- @param opts _99.ops.Opts? @@ -421,12 +473,18 @@ function _99.next_request_logs() Window.display_full_screen_message(logs[_99_state.__view_log_idx]) end +--- @class _99.QFixEntry +--- @field filename string +--- @field lnum number +--- @field col number +--- @field text string + function _99.stop_all_requests() - for _, active in pairs(_99_state.__active_requests) do - _99_state:remove_request(active.request_id) - active.clean_up() + for _, request in pairs(_99_state.__request_by_id) do + if request.status == "requesting" then + request.context:stop() + end end - _99_state.__active_requests = {} end function _99.clear_all_marks() @@ -436,17 +494,18 @@ function _99.clear_all_marks() _99_state.__active_marks = {} end -function _99.previous_requests_to_qfix() - local items = {} - for _, entry in ipairs(_99_state.__request_history) do - table.insert(items, { - filename = entry.filename, - lnum = entry.lnum, - col = entry.col, - text = string.format("[%s] %s", entry.status, entry.operation), - }) - end - vim.fn.setqflist({}, "r", { title = "99 Requests", items = items }) +--- @param xid number | nil +function _99.qfix_search_results(xid) + --- @type _99.RequestEntry + local entry = _99_state.__request_by_id[xid] + assert(entry, "qfix_search_results could not find id: " .. xid) + + local data = entry.operation_data + assert(data, "there must be data associated with request entry") + assert(data.type == "search", "the operation_data must be type search") + + local items = data.qfix_items + vim.fn.setqflist({}, "r", { title = "99 Search Results", items = items }) vim.cmd("copen") end @@ -497,11 +556,15 @@ local function show_in_flight_requests() return shut_down_in_flight_requests_window() end + --- @type string[] local lines = { throb .. " requests(" .. tostring(count) .. ") " .. throb, } - for _, r in pairs(_99_state.__active_requests) do - table.insert(lines, r.name) + + for _, r in pairs(_99_state.__request_by_id) do + if r.status == "requesting" then + table.insert(lines, r.context.operation) + end end Window.resize(win, #lines[1], #lines) @@ -562,6 +625,11 @@ function _99.setup(opts) end end + if opts.tmp_dir then + assert(type(opts.tmp_dir) == "string", "opts.tmp_dir must be a string") + end + _99_state.tmp_dir = opts.tmp_dir + _99_state.display_errors = opts.display_errors or false _99_state:refresh_rules() Languages.initialize(_99_state) @@ -627,4 +695,7 @@ function _99.__debug() end _99.Providers = Providers +_99.Extensions = { + Worker = require("99.extensions.work.worker"), +} return _99 |
