summaryrefslogtreecommitdiff
path: root/lua/99/request/init.lua
diff options
context:
space:
mode:
authorThePrimeAgain <theprimeagain@theprimeagain.com>2025-11-26 09:21:53 -0700
committerThePrimeAgain <theprimeagain@theprimeagain.com>2025-11-26 09:21:53 -0700
commit82b05b232f6a8a2f26432a68759633783efb05ab (patch)
tree3644a2dba6be9a2832880d076199d7553eac91dd /lua/99/request/init.lua
parentf901b32322e22f4cd2bf3c01896cbbcb37fecea8 (diff)
downloada4-82b05b232f6a8a2f26432a68759633783efb05ab.tar.xz
a4-82b05b232f6a8a2f26432a68759633783efb05ab.zip
fill in the function
Diffstat (limited to 'lua/99/request/init.lua')
-rw-r--r--lua/99/request/init.lua135
1 files changed, 135 insertions, 0 deletions
diff --git a/lua/99/request/init.lua b/lua/99/request/init.lua
new file mode 100644
index 0000000..d020caa
--- /dev/null
+++ b/lua/99/request/init.lua
@@ -0,0 +1,135 @@
+local Logger = require("99.logger.logger")
+local editor = require("99.editor")
+local geo = require("99.geo")
+local Point = geo.Point
+
+--- TODO: some people change their current working directory as they open new
+--- directories. if this is still the case in neovim land, then we will need
+--- to make the _99_state have the project directory.
+--- @return string
+local function random_file()
+ return string.format("%s/tmp/99-%d", vim.uv.cwd(), math.floor(math.random() * 10000))
+end
+
+--- no, i am not going to use a uuid, in case of collision, call the police
+--- @return string
+local function get_id()
+ return tostring(math.floor(math.random() * 100000000))
+end
+
+--- @alias _99.Request.State "ready" | "calling-model" | "parsing-result" | "updating-file"
+
+--- @class _99.Request.Opts
+--- @field model string
+--- @field md_files string[]
+
+--- @class _99.Request
+--- @field query string
+--- @field tmp_name string
+--- @field state _99.Request.State
+--- @field buffer number
+--- @field model string
+--- @field id string
+--- @field mark string
+--- @field scopes Scope
+--- @field system_prompt string
+local Request = {}
+Request.__index = Request
+
+--- @param opts _99.Request.Opts
+function Request.new(opts)
+ assert(opts.model, "you must provide a model for hange requests to work")
+
+ local ts = editor.treesitter
+ local cursor = Point:from_cursor()
+ local scopes = ts.function_scopes(cursor)
+ local buffer = vim.api.nvim_get_current_buf()
+
+ return setmetatable({
+ cursor = cursor,
+ scopes = scopes,
+ buffer = buffer,
+ model = opts.model,
+ tmp_name = random_file(),
+ id = get_id(),
+ state = "ready",
+ mark = "",
+ }, Request)
+end
+
+function Request:has_scopes()
+ return self.scopes ~= nil and #self.scopes > 0
+end
+
+function Request:get_inner_scope()
+ assert(self:has_scopes(), "you cannot get inner scope if you dont have scopes")
+ return self.scopes.range[#self.scopes.range]
+end
+
+--- @param prompt string
+function Request:set_system_prompt(prompt)
+ self.system_prompt = prompt
+end
+
+function Request:_retrieve_response()
+ local success, result = pcall(function()
+ return vim.fn.readfile(self.tmp_name)
+ end)
+
+ if not success then
+ Logger:error("retrieve_results: failed to read file", "tmp_name", self.tmp_name, "error", result)
+ return false, ""
+ end
+
+ return true, table.concat(result, "\n")
+end
+
+--- @param res string
+function Request:_update_file_with_changes(res)
+ local mark_pos = vim.api.nvim_buf_get_mark(self.buffer, self.mark)
+ local mark_point = Point:new(mark_pos[1], mark_pos[2] + 1)
+
+ local ts = editor.treesitter
+ local scopes = ts.function_scopes(mark_point)
+
+ if not scopes or not scopes:has_scope() then
+ Logger:error("update_file_with_changes: unable to find function at mark location")
+ return
+ end
+
+ local range = scopes.range[#scopes.range]
+
+ local function_start_row, _ = range.start:to_vim()
+ local function_end_row, _ = range.end_:to_vim()
+
+ local lines = vim.split(res, "\n")
+ vim.api.nvim_buf_set_lines(self.buffer, function_start_row, function_end_row + 1, false, lines)
+end
+
+function Request:start()
+ Logger:debug("99#make_query", "id", self.id, "query", self.query)
+ vim.system({ "opencode", "run", "-m", "anthropic/claude-sonnet-4-5", self.query }, {
+ text = true,
+ stdout = vim.schedule_wrap(function(err, data)
+ Logger:debug("STDOUT#data", "id", self.id, "data", data)
+ Logger:debug("STDOUT#error", "id", self.id, "err", err)
+ end),
+ stderr = vim.schedule_wrap(function(err, data)
+ Logger:debug("STDERR#data", "id", self.id, "data", data)
+ Logger:debug("STDERR#error", "id", self.id, "err", err)
+ end),
+ }, function(obj)
+ if obj.code ~= 0 then
+ Logger:fatal("opencode make_query failed", "request", self, "obj from results", obj)
+ return
+ end
+ vim.schedule(function()
+ local ok, res = self:_retrieve_response()
+ if ok then
+ self:_update_file_with_changes(res)
+ end
+ end)
+ end)
+end
+
+return Request