diff options
| author | ThePrimeAgain <theprimeagain@theprimeagain.com> | 2025-12-01 16:01:40 -0700 |
|---|---|---|
| committer | ThePrimeAgain <theprimeagain@theprimeagain.com> | 2025-12-01 16:01:40 -0700 |
| commit | 7438d6024d57736ec2fe8e0cc8feeb4f5c817d33 (patch) | |
| tree | 0e44b283b395817fae12934809dc8019ae0b15ed | |
| parent | 00c5d9a9ca2d978641e7d30ab70bb34249011dec (diff) | |
| download | a4-7438d6024d57736ec2fe8e0cc8feeb4f5c817d33.tar.xz a4-7438d6024d57736ec2fe8e0cc8feeb4f5c817d33.zip | |
getting to the point of making this look pretty
| -rw-r--r-- | AGENT.md | 2 | ||||
| -rw-r--r-- | lua/99/editor/location.lua | 17 | ||||
| -rw-r--r-- | lua/99/editor/lsp.lua | 2 | ||||
| -rw-r--r-- | lua/99/editor/treesitter.lua | 7 | ||||
| -rw-r--r-- | lua/99/init.lua | 16 | ||||
| -rw-r--r-- | lua/99/logger/logger.lua | 8 | ||||
| -rw-r--r-- | lua/99/ops/context.lua | 32 | ||||
| -rw-r--r-- | lua/99/ops/fill-in-function.lua | 36 | ||||
| -rw-r--r-- | lua/99/ops/implement-fn.lua | 31 | ||||
| -rw-r--r-- | scratch/refresh.lua | 1 |
10 files changed, 125 insertions, 27 deletions
diff --git a/AGENT.md b/AGENT.md new file mode 100644 index 0000000..fc195c1 --- /dev/null +++ b/AGENT.md @@ -0,0 +1,2 @@ +always use vim functions +never use lua std functions from io (when possible) diff --git a/lua/99/editor/location.lua b/lua/99/editor/location.lua index b4b3de8..fef40fb 100644 --- a/lua/99/editor/location.lua +++ b/lua/99/editor/location.lua @@ -1,8 +1,9 @@ -local Point = require("99.geo") +local Range = require("99.geo").Range --- @class _99.Location --- @field full_path string --- @field range Range +--- @field node TSNode --- @field buffer number --- @field marks table<string, string> local Location = {} @@ -19,4 +20,18 @@ function Location.from_range(range) }, Location) end +--- @param node TSNode +--- @param range Range +function Location.from_ts_node(node, range) + local full_path = vim.api.nvim_buf_get_name(range.buffer) + + return setmetatable({ + buffer = range.buffer, + full_path = full_path, + range = range, + node = node, + marks = {} + }, Location) +end + return Location diff --git a/lua/99/editor/lsp.lua b/lua/99/editor/lsp.lua index ddb2486..590409b 100644 --- a/lua/99/editor/lsp.lua +++ b/lua/99/editor/lsp.lua @@ -41,7 +41,7 @@ local function get_lsp_definitions(buffer, position, cb) end --- @class Lsp ---- @field config _99Options +--- @field config _99.Options local Lsp = {} Lsp.__index = Lsp diff --git a/lua/99/editor/treesitter.lua b/lua/99/editor/treesitter.lua index b76939d..7e0ddea 100644 --- a/lua/99/editor/treesitter.lua +++ b/lua/99/editor/treesitter.lua @@ -100,8 +100,13 @@ function Scope:has_scope() return #self.range > 0 end ---- @return Range | nil +--- @return TSNode | nil function Scope:get_inner_scope() + return self.scope[#self.scope] +end + +--- @return Range | nil +function Scope:get_inner_range() return self.range[#self.range] end diff --git a/lua/99/init.lua b/lua/99/init.lua index f336f09..938fadc 100644 --- a/lua/99/init.lua +++ b/lua/99/init.lua @@ -2,9 +2,10 @@ local Logger = require("99.logger.logger") local Level = require("99.logger.level") local ops = require("99.ops") ---- @class _99Options +--- @class _99.Options --- @field logger _99.Logger.Options? --- @field model string? +--- @field md_files 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 @@ -12,12 +13,14 @@ local ops = require("99.ops") --- @field model string --- @field md_files string[] --- @field prompts _99.Prompts +--- @field ai_stdout_rows number --- @type _99.State local _99_state = { model = "anthropic/claude-sonnet-4-5", md_files = {}, prompts = require("99.prompt_settings"), + ai_stdout_rows = 3, } --- @class _99 @@ -39,15 +42,24 @@ function _99.fill_in_function() fif:start() end ---- @param opts _99Options? +--- @param opts _99.Options? function _99.setup(opts) opts = opts or {} + print("configuring logger") Logger:configure(opts.logger) if opts.model then + assert(type(opts.model) == "string", "opts.model is not a string") _99_state.model = opts.model end + + if opts.md_files then + assert(type(opts.md_files) == "table", "opts.md_files is not a table") + for _, md in ipairs(opts.md_files) do + _99.add_md_file(md) + end + end end --- @param md string diff --git a/lua/99/logger/logger.lua b/lua/99/logger/logger.lua index 8f03092..088a04f 100644 --- a/lua/99/logger/logger.lua +++ b/lua/99/logger/logger.lua @@ -132,17 +132,17 @@ function Logger:configure(opts) end if opts.level then - Logger:set_level(opts.level) + self:set_level(opts.level) end if opts.path then - Logger:file_sink(opts.path) + self:file_sink(opts.path) else - Logger:print_sink() + self:print_sink() end if opts.print_on_error then - Logger:on_error_print_message() + self:on_error_print_message() end end diff --git a/lua/99/ops/context.lua b/lua/99/ops/context.lua index 0428671..1e14510 100644 --- a/lua/99/ops/context.lua +++ b/lua/99/ops/context.lua @@ -1,3 +1,5 @@ +local Logger = require("99.logger.logger") + --- 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. @@ -34,16 +36,38 @@ function Context:add_md_file_name(md_file_name) return self end -function Context:_read_md_files() - --- @ai use location's buffer's full path and walk back until we are at cwd - --- @ai and read each of the md_file_names. if it exists then add it to - --- @ai ai_context. +--- @param location _99.Location +function Context:_read_md_files(location) + local cwd = vim.uv.cwd() + local dir = vim.fn.fnamemodify(location.full_path, ":h") + + Logger:info("_read_md_files", "cwd", cwd, "dir", dir) + while dir:find(cwd, 1, true) == 1 do + for _, md_file_name in ipairs(self.md_file_names) do + local md_path = dir .. "/" .. md_file_name + local file = io.open(md_path, "r") + Logger:info("_read_md_files#while#for", "md_path", md_path) + if file then + local content = file:read("*a") + file:close() + table.insert(self.ai_context, content) + end + end + + if dir == cwd then + break + end + + dir = vim.fn.fnamemodify(dir, ":h") + Logger:info("_read_md_files#while", "new dir selected", dir) + end end --- @param _99 _99.State --- @param location _99.Location --- @return self function Context:finalize(_99, location) + self:_read_md_files(location) table.insert(self.ai_context, _99.prompts.get_file_location(location)) table.insert(self.ai_context, _99.prompts.get_range_text(location.range)) table.insert(self.ai_context, _99.prompts.tmp_file_location(self.tmp_file)) diff --git a/lua/99/ops/fill-in-function.lua b/lua/99/ops/fill-in-function.lua index ed28447..b222d1c 100644 --- a/lua/99/ops/fill-in-function.lua +++ b/lua/99/ops/fill-in-function.lua @@ -35,22 +35,50 @@ local function update_file_with_changes(res, location) end --- @param _99 _99.State +--- @param location _99.Location +local function add_space_in_function(_99, location) + if _99.ai_stdout_rows == 0 then + return + end + + local buffer = location.buffer + local range = location.range + local function_end_row, _ = range.end_:to_vim() + + local empty_lines = {} + for i = 1, _99.ai_stdout_rows do + empty_lines[i] = "" + end + + vim.api.nvim_buf_set_lines(buffer, function_end_row, function_end_row, false, empty_lines) + + location.marks.ai_stdout_start = marks(buffer, range) +end + +local function print_hello_world() + print("Hello, World!") +end + +--- @param _99 _99.State --- @return _99.Request local function fill_in_function(_99) local ts = editor.treesitter local cursor = Point:from_cursor() local scopes = ts.function_scopes(cursor) - local range = scopes:get_inner_scope() + local scope = scopes:get_inner_scope() + local range = scopes:get_inner_range() - if not range then + if not range or not scope then Logger:error("fill_in_function: unable to find any containing function") error("you cannot call fill_in_function not in a function") end - local location = editor.Location.from_range(range) + local location = editor.Location.from_ts_node(scope, range) local context = Context.new(_99):finalize(_99, location) local request = Request.new({ model = _99.model, + on_stdout = function(line) + end, on_complete = function(_, ok, response) if not ok then Logger:fatal("unable to fill in function, enable and check logger for more details") @@ -64,6 +92,8 @@ local function fill_in_function(_99) location.marks.function_location = marks(location.buffer, range) request:add_prompt_content(_99.prompts.prompts.fill_in_function) + add_space_in_function(_99, location) + return request end diff --git a/lua/99/ops/implement-fn.lua b/lua/99/ops/implement-fn.lua index ef28c10..3d445a7 100644 --- a/lua/99/ops/implement-fn.lua +++ b/lua/99/ops/implement-fn.lua @@ -1,32 +1,43 @@ +local Context = require("99.ops.context") +local Location = require("99.editor.location") local Logger = require("99.logger.logger") local Request = require("99.request") local editor = require("99.editor") -local Range = require("99.geo").Range +local geo = require("99.geo") +local Range = geo.Range +local Point = geo.Point local function update_code(request, ok, res) if not ok then error("unable to implement function. check logger for more details") end - Logger:fatal("not implemented yet") + Logger:fatal("not implemented yet") end --- @param _99 _99.State ---- @return _99.Request? +--- @return _99.Request local function implement_fn(_99) + local ts = editor.treesitter + local cursor = Point:from_cursor() + local scopes = ts.function_scopes(cursor) + + local range = scopes:get_inner_scope() + + local context = Context.new(_99) local request = Request.new({ - model = _99.model, - md_files = _99.md_files, on_complete = update_code, + model = _99.model, + context = context, }) local ts = editor.treesitter local ident = ts.identifier(request.buffer, request.cursor) - print_ident(ident) + print_ident(ident) - if not ident then - Logger:error("implement_fn was called but cursor was not on a function call", "cursor", request.cursor) - return nil - end + if not ident then + Logger:error("implement_fn was called but cursor was not on a function call", "cursor", request.cursor) + return nil + end Range:from_ts_node(ident, request.buffer) diff --git a/scratch/refresh.lua b/scratch/refresh.lua index c90f76f..3612efd 100644 --- a/scratch/refresh.lua +++ b/scratch/refresh.lua @@ -1,5 +1,4 @@ local function pick_a_number_that_is_42() - return 42 end function return_42() |
