From 3e334a0e08cd6618d7ee50fdf7810712265a3a77 Mon Sep 17 00:00:00 2001 From: theprimeagain Date: Mon, 16 Feb 2026 12:12:35 -0700 Subject: Tutorials are ready (ish) --- lua/99/window/init.lua | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'lua/99/window/init.lua') diff --git a/lua/99/window/init.lua b/lua/99/window/init.lua index b4b1cb4..d7018c8 100644 --- a/lua/99/window/init.lua +++ b/lua/99/window/init.lua @@ -27,6 +27,10 @@ local nvim_buf_is_valid = vim.api.nvim_buf_is_valid --- @field win_id number --- @field buf_id number +--- @class _99.window.SplitWindow +--- @field win number +--- @field buffer number + --- @param lines string[] --- @return string[] local function ensure_no_new_lines(lines) @@ -347,6 +351,7 @@ end --- @class _99.window.CaptureInputOpts --- @field cb fun(success: boolean, result: string): nil --- @field on_load? fun(): nil +--- @field content? string[] --- @field rules _99.Agents.Rules --- @param name string @@ -423,6 +428,16 @@ function M.capture_input(name, opts) if opts.on_load then vim.schedule(opts.on_load) end + + if opts.content then + vim.api.nvim_buf_set_lines( + win.buf_id, + 0, + -1, + false, + ensure_no_new_lines(opts.content) + ) + end end function M.clear_active_popups() @@ -493,4 +508,54 @@ function M.close(win) end end end + +--- @class _99.window.SplitWindowOpts +--- @field split_direction "vertical" | "horizontal" | nil +--- @field filetype string + +--- @param content string[] +---@param buffer number | nil +---@param opts _99.window.SplitWindowOpts | nil +--- @return _99.window.SplitWindow +function M.create_split(content, buffer, opts) + opts = opts or { split_direction = "vertical" } + + opts.split_direction = opts.split_direction or "vertical" + opts.filetype = opts.filetype or "markdown" + + local split_direction = opts.split_direction + assert( + split_direction == "vertical" or split_direction == "horizontal", + "unknown split direction: " + .. vim.inspect(split_direction) + .. " : must be horizontal or vertical" + ) + + if split_direction == "horizontal" then + vim.cmd("split") + else + vim.cmd("vsplit") + end + + local win_id = vim.api.nvim_get_current_win() + local buf_id = buffer + if not buf_id or not nvim_buf_is_valid(buf_id) then + buf_id = vim.api.nvim_create_buf(false, false) + vim.api.nvim_buf_set_lines( + buf_id, + 0, + -1, + false, + ensure_no_new_lines(content) + ) + end + + vim.api.nvim_win_set_buf(win_id, buf_id) + vim.bo[buf_id].filetype = opts.filetype + + return { + win = win_id, + buffer = buf_id, + } +end return M -- cgit v1.3-3-g829e From 045e6056508a2a5c7bdeebae46875b7bba3a6f21 Mon Sep 17 00:00:00 2001 From: theprimeagain Date: Wed, 18 Feb 2026 08:28:21 -0700 Subject: worker extension --- lua/99/extensions/work/worker.lua | 75 +++++++++++++++++++++++++++++++++++++++ lua/99/init.lua | 40 ++++++++++----------- lua/99/ops/search.lua | 14 ++++---- lua/99/window/init.lua | 8 +++-- 4 files changed, 107 insertions(+), 30 deletions(-) create mode 100644 lua/99/extensions/work/worker.lua (limited to 'lua/99/window/init.lua') diff --git a/lua/99/extensions/work/worker.lua b/lua/99/extensions/work/worker.lua new file mode 100644 index 0000000..dbcf9b3 --- /dev/null +++ b/lua/99/extensions/work/worker.lua @@ -0,0 +1,75 @@ +local Window = require("99.window") + +--- @class _99.Extension.Worker +local M = {} + +--- @class _99.WorkOpts +--- @field description string | nil + +--- @param opts _99.WorkOpts | nil +function M.set_work(opts) + opts = opts or {} + local description = opts.description + if description then + M.current_work_item = description + else + Window.capture_input(" Work ", { + cb = function(success, result) + if not success then + return + end + M.current_work_item = result + end, + + content = { "Put in the description of the work you want to complete" }, + }) + end + + -- i think this makes sense. last work search should be cleared + M.last_work_search = nil +end + +--- craft_prompt can be overridden so you can create your own prompt +--- @param worker _99.Extension.Worker +--- @return string +function M.craft_prompt(worker) + return string.format( + [[ + +You are to take the current git diff and git diff --staged and figure out what is left to change to complete the work item. +The work item is described in + +Carefully review everything in git diff and git diff --staged and before you respond. +respond with proper Search Format described in and an example in + +If you see bugs, also report those + + +%s + +]], + worker.current_work_item + ) +end + +function M.work() + assert( + M.current_work_item, + 'you must call "set_work" and set your current work item before calling this' + ) + local _99 = require("99") + M.last_work_search = _99.search({ + additional_prompt = M.craft_prompt(M), + }) +end + +function M.last_search_results() + if M.last_work_search == nil then + print("no previous search results") + return + end + + require("99").qfix_search_results(M.last_work_search) +end + +return M diff --git a/lua/99/init.lua b/lua/99/init.lua index f8755dd..a51cc51 100644 --- a/lua/99/init.lua +++ b/lua/99/init.lua @@ -45,6 +45,7 @@ end --- @class _99.RequestEntry.Data.Search --- @field type "search" +--- @field qfix_items _99.Search.Result[] --- @class _99.RequestEntry.Data.Visual --- @field type "visual" @@ -397,15 +398,16 @@ 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 @@ -473,21 +475,6 @@ end --- @field col number --- @field text string ---- @param entry _99.RequestEntry ---- @return _99.QFixEntry -local function request_entry_to_qfix_item(entry) - local context = entry.context - local point = entry.point - local text = string.format("[%s] %s", entry.status, entry.context.operation) - - return { - filename = context and context.full_path or "", - lnum = point and point.row or 0, - col = point and point.col or 0, - text = text, - } -end - function _99.stop_all_requests() for _, request in pairs(_99_state.__request_by_id) do if request.status == "requesting" then @@ -503,12 +490,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, request_entry_to_qfix_item(entry)) - 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 @@ -673,4 +666,7 @@ function _99.__debug() end _99.Providers = Providers +_99.Extensions = { + Worker = require("99.extensions.work.worker"), +} return _99 diff --git a/lua/99/ops/search.lua b/lua/99/ops/search.lua index f819e4b..d6e5428 100644 --- a/lua/99/ops/search.lua +++ b/lua/99/ops/search.lua @@ -36,10 +36,9 @@ local function parse_line(line) } end ---- @param _99 _99.State +--- @param context _99.RequestContext --- @param response string -local function create_search_locations(_99, response) - _ = _99 +local function create_search_locations(context, response) local lines = vim.split(response, "\n") local qf_list = {} @@ -49,10 +48,13 @@ local function create_search_locations(_99, response) table.insert(qf_list, res) end end + context._99:add_data(context, { + type = "search", + qfix_items = qf_list, + }) if #qf_list > 0 then - vim.fn.setqflist(qf_list, "r") - vim.cmd("copen") + require("99").qfix_search_results(context.xid) else vim.notify("No search results found", vim.log.levels.INFO) end @@ -89,7 +91,7 @@ local function search(context, opts) response or "no response provided" ) elseif status == "success" then - create_search_locations(context._99, response) + create_search_locations(context, response) end end)) end diff --git a/lua/99/window/init.lua b/lua/99/window/init.lua index d7018c8..8db5b2f 100644 --- a/lua/99/window/init.lua +++ b/lua/99/window/init.lua @@ -283,9 +283,13 @@ local function set_defaul_win_options(win, name) end --- @param win _99.window.Window ---- @param rules _99.Agents.Rules +--- @param rules _99.Agents.Rules? --- @param group any local function highlight_rules_found(win, rules, group) + if rules == nil then + return + end + local rule_nsid = vim.api.nvim_create_namespace("99.window.rules") local function check_and_highlight_rules() if not nvim_win_is_valid(win.win_id) then @@ -352,7 +356,7 @@ end --- @field cb fun(success: boolean, result: string): nil --- @field on_load? fun(): nil --- @field content? string[] ---- @field rules _99.Agents.Rules +--- @field rules? _99.Agents.Rules --- @param name string --- @param opts _99.window.CaptureInputOpts -- cgit v1.3-3-g829e