summaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
authortheprimeagain <the.primeagen@gmail.com>2026-02-26 07:11:49 -0700
committertheprimeagain <the.primeagen@gmail.com>2026-02-26 07:11:49 -0700
commitcbc24f940f49b28da62642bca10206f3933bec77 (patch)
treed9429175bdb3320501358380ff91159a1bb4a30e /lua
parent9be01a1a50a61635ea7169e01c85fab41638ad66 (diff)
downloada4-cbc24f940f49b28da62642bca10206f3933bec77.tar.xz
a4-cbc24f940f49b28da62642bca10206f3933bec77.zip
tutorial
Diffstat (limited to 'lua')
-rw-r--r--lua/99/geo.lua8
-rw-r--r--lua/99/init.lua253
-rw-r--r--lua/99/ops/init.lua2
-rw-r--r--lua/99/ops/search.lua4
-rw-r--r--lua/99/ops/tutorial.lua3
-rw-r--r--lua/99/ops/vibe.lua4
-rw-r--r--lua/99/prompt-settings.lua5
-rw-r--r--lua/99/prompt.lua3
-rw-r--r--lua/99/state.lua10
-rw-r--r--lua/99/test/geo_spec.lua22
-rw-r--r--lua/99/test/open_spec.lua99
-rw-r--r--lua/99/test/qfix_navigation_spec.lua70
-rw-r--r--lua/99/test/utils_spec.lua19
-rw-r--r--lua/99/test/vibe_search_spec.lua56
-rw-r--r--lua/99/utils.lua15
-rw-r--r--lua/99/window/init.lua39
16 files changed, 252 insertions, 360 deletions
diff --git a/lua/99/geo.lua b/lua/99/geo.lua
index 48e60ad..01c8f71 100644
--- a/lua/99/geo.lua
+++ b/lua/99/geo.lua
@@ -204,6 +204,14 @@ function Point.from_mark(mark)
}, Point)
end
+--- Returns the line in the editor that this point is on
+--- @param buffer number
+function Point:line(buffer)
+ local row, _ = self:to_vim()
+ local lines = vim.api.nvim_buf_get_lines(buffer, row, row + 1, false)
+ return lines[1]
+end
+
function Point.zero()
return Point.from_0_based(0, 0)
end
diff --git a/lua/99/init.lua b/lua/99/init.lua
index 52ba23b..f623db2 100644
--- a/lua/99/init.lua
+++ b/lua/99/init.lua
@@ -1,3 +1,6 @@
+--- TODO: I would like to clean up this file. I will probably need to create a
+--- task for me to do in the future to make this a bit more clean and only have
+--- stuff that makes sense for the api to be in here... but for now.. ia m sorry
local Logger = require("99.logger.logger")
local Level = require("99.logger.level")
local ops = require("99.ops")
@@ -186,9 +189,12 @@ local _99_state
--- @field search fun(opts: _99.ops.SearchOpts): _99.TraceID
--- Performs a search across your project with the prompt you provide and return out a list of
--- locations with notes that will be put into your quick fix list.
---- @field vibe_search fun(opts?: _99.ops.Opts): _99.TraceID | nil
---- Select a previous search, edit it, then pass it to vibe.
--- @field vibe fun(opts?: _99.ops.Opts): _99.TraceID | nil
+--- @field open fun(): nil
+--- Opens a selection window for you to select the last interaction to open
+--- and display its contents in a way that makes sense for its type. For
+--- search and vibe, it will open the qfix window. For tutorial, it will open
+--- the tutorial window.
--- @field visual fun(opts: _99.ops.Opts): _99.TraceID
--- takes your current selection and sends that along with the prompt provided and replaces
--- your visual selection with the results
@@ -265,56 +271,59 @@ function _99.info()
Window.display_centered_message(info)
end
---- @param tutorials _99.Prompt.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
- --- @type _99.Prompt.Data.Tutorial[]
- local tutorials = _99_state:request_by_type("tutorial")
- if #tutorials == 0 then
- print("no tutorials available")
- return
- elseif #tutorials == 1 then
- local data = tutorials[1]
- assert(data, "tutorial is malformed")
- Window.create_split(data.tutorial, data.buffer, opts)
- return
- else
- --- TODO: Complete this task when i work through tutorials
- error([[not implemented. right now tutorials are not sccrollable.
-This is a later change required. I want a next/prev tutorial navigation
-much like qfix list. then i to have a capture input style window where you
-can press enter
-]])
- end
- return
- end
-
- --- @type _99.Prompt | nil
- local context = _99_state.__request_by_id[xid]
- assert(context, "could not find request")
- assert(context.state == "success", "tutorial found had a non success state")
+-- elseif #tutorials == 1 then
+-- local data = tutorials[1]
+-- assert(data, "tutorial is malformed")
+-- Window.create_split(data.tutorial, data.buffer, opts)
+-- return
+--- @param context _99.Prompt
+function _99.open_tutorial(context)
local tutorial = context:tutorial_data()
- Window.create_split(tutorial.tutorial, tutorial.buffer, opts)
+ Window.create_split(tutorial.tutorial, tutorial.buffer)
end
---- @param path string
-function _99:rule_from_path(path)
- _ = self
- path = expand(path) --[[ @as string]]
- return Agents.get_rule_by_path(_99_state.rules, path)
+function _99.open()
+ local requests = _99_state:requests()
+ local str_requests = {}
+ for _, r in ipairs(requests) do
+ table.insert(str_requests, r:summary())
+ end
+ for i = 1, #requests do
+ str_requests[i] = string.format("%d: %s", i, requests[i]:summary())
+ end
+ Window.capture_select_input("99", {
+ content = str_requests,
+ cb = function(success, result)
+ if not success or result == "" then
+ return
+ end
+
+ local idx = tonumber(vim.fn.matchstr(result, "^\\d\\+"))
+ local r = requests[idx]
+ if not r then
+ print(
+ "somehow we have had a successful callback, but no request context... i honestly have no idea how we got here"
+ )
+ return
+ end
+ assert(
+ r:valid(),
+ "request is not valid... not sure how we got here. please report bug and this word: "
+ .. vim.inspect(r.operation)
+ )
+ if r.operation == "visual" then
+ --- TODO: this is its own work item for being able to have a global mark
+ --- section in which i keep track of marks for the lifetime of the
+ --- editor and when you close the editor, then it should lose them
+ print("visual not supported: i will figure this out... at some point")
+ elseif r.operation == "search" or r.operation == "vibe" then
+ _99.open_qfix_for_request(r)
+ elseif r.operation == "tutorial" then
+ _99.open_tutorial(r)
+ end
+ end,
+ })
end
--- @param opts? _99.ops.Opts
@@ -345,55 +354,12 @@ function _99.search(opts)
return context.xid
end
---- @param opts? _99.ops.Opts
---- @return _99.TraceID | nil
-function _99.vibe_search(opts)
- local searches = _99_state:request_by_type("search")
- if #searches == 0 then
- error("no previous search results")
- return nil
- end
-
- local o = process_opts(opts)
- local lines = {}
- for i, context in ipairs(searches) do
- table.insert(lines, string.format("%d: %s", i, context:summary()))
- end
-
- Window.capture_select_input("Select Search", {
- content = lines,
- cb = function(ok, result)
- if not ok then
- return
- end
-
- local idx = tonumber(string.match(result, "^(%d+)%:"))
- local selected = idx and searches[idx] or nil
- if not selected then
- print("failed to select search result")
- return
- end
-
- local selected_data = selected:search_data()
- local context = Prompt.vibe(_99_state)
- capture_prompt(
- ops.vibe,
- "Vibe",
- context,
- o,
- vim.split(selected_data.response, "\n")
- )
- end,
- })
-
- return nil
-end
-
--- @param opts _99.ops.Opts
function _99.tutorial(opts)
opts = process_opts(opts)
local context = Prompt.tutorial(_99_state)
if opts.additional_prompt then
+ context.user_prompt = opts.additional_prompt
ops.tutorial(context, opts)
else
capture_prompt(ops.tutorial, "Tutorial", context, opts)
@@ -446,57 +412,8 @@ 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
-
---- @class _99.QFixOpts
---- @field operation? "search" | "vibe"
-
---- @param opts? _99.QFixOpts
---- @return "search" | "vibe"
-local function qfix_operation(opts)
- local operation = (opts and opts.operation) or "search"
- assert(
- operation == "search" or operation == "vibe",
- "opts.operation must be either 'search' or 'vibe'"
- )
- return operation
-end
-
---- @param operation "search" | "vibe"
---- @return _99.Prompt[]
-local function qfix_requests(operation)
- local out = {} --[[ @as _99.Prompt[] ]]
- for _, request in ipairs(_99_state.__request_history) do
- if request.operation == operation then
- local ok, items = pcall(request.qfix_data, request)
- if ok and #items > 0 then
- table.insert(out, request)
- end
- end
- end
- return out
-end
-
---- @param operation "search" | "vibe"
---- @param index number
---- @return _99.Prompt | nil
-local function qfix_request_at(operation, index)
- local requests = qfix_requests(operation)
- if #requests == 0 then
- return nil
- end
-
- local idx = math.max(1, math.min(index, #requests))
- _99_state.__qfix_history_idx[operation] = idx
- return requests[idx]
-end
-
--- @param request _99.Prompt
-local function open_qfix_request(request)
+function _99.open_qfix_for_request(request)
local items = request:qfix_data()
if #items == 0 then
print("there are no quickfix items to show")
@@ -522,58 +439,6 @@ function _99.clear_all_marks()
_99_state.__active_marks = {}
end
---- @param opts? _99.QFixOpts
-function _99.qfix_top(opts)
- local operation = qfix_operation(opts)
- local requests = qfix_requests(operation)
- if #requests == 0 then
- print("there are no quickfix items to show")
- return
- end
-
- local request = qfix_request_at(operation, #requests)
- assert(request, "failed to retrieve qfix request")
- open_qfix_request(request)
-end
-
---- @param opts? _99.QFixOpts
-function _99.qfix_older(opts)
- local operation = qfix_operation(opts)
- local requests = qfix_requests(operation)
- if #requests == 0 then
- print("there are no quickfix items to show")
- return
- end
-
- local current = _99_state.__qfix_history_idx[operation]
- if current == 0 then
- current = #requests
- end
-
- local request = qfix_request_at(operation, current - 1)
- assert(request, "failed to retrieve older qfix request")
- open_qfix_request(request)
-end
-
---- @param opts? _99.QFixOpts
-function _99.qfix_newer(opts)
- local operation = qfix_operation(opts)
- local requests = qfix_requests(operation)
- if #requests == 0 then
- print("there are no quickfix items to show")
- return
- end
-
- local current = _99_state.__qfix_history_idx[operation]
- if current == 0 then
- current = #requests
- end
-
- local request = qfix_request_at(operation, current + 1)
- assert(request, "failed to retrieve newer qfix request")
- open_qfix_request(request)
-end
-
function _99.clear_previous_requests()
_99_state:clear_history()
end
diff --git a/lua/99/ops/init.lua b/lua/99/ops/init.lua
index d45b1a5..5cb7a74 100644
--- a/lua/99/ops/init.lua
+++ b/lua/99/ops/init.lua
@@ -35,5 +35,5 @@ return {
search = require("99.ops.search"),
tutorial = require("99.ops.tutorial"),
over_range = require("99.ops.over-range"),
- vibe = require("99.ops.vibe")
+ vibe = require("99.ops.vibe"),
}
diff --git a/lua/99/ops/search.lua b/lua/99/ops/search.lua
index dc7520f..0b19bb4 100644
--- a/lua/99/ops/search.lua
+++ b/lua/99/ops/search.lua
@@ -17,9 +17,7 @@ local function create_search_locations(context, response)
}
if #qf_list > 0 then
- require("99").qfix_top({
- operation = "search",
- })
+ require("99").open_qfix_for_request(context)
else
vim.notify("No search results found", vim.log.levels.INFO)
end
diff --git a/lua/99/ops/tutorial.lua b/lua/99/ops/tutorial.lua
index 9889801..4b9a9b8 100644
--- a/lua/99/ops/tutorial.lua
+++ b/lua/99/ops/tutorial.lua
@@ -54,8 +54,7 @@ local function tutorial(context, opts)
response or "no response provided"
)
elseif status == "success" then
- local data = open_tutorial(context, response)
- context._99:open_tutorial(data)
+ open_tutorial(context, response)
end
end))
end
diff --git a/lua/99/ops/vibe.lua b/lua/99/ops/vibe.lua
index 3ba15c5..0e52307 100644
--- a/lua/99/ops/vibe.lua
+++ b/lua/99/ops/vibe.lua
@@ -17,9 +17,7 @@ local function finish_vibe(context, response)
}
if #qf_list > 0 then
- require("99").qfix_top({
- operation = "vibe",
- })
+ require("99").open_qfix_for_request(context)
else
vim.notify("No search results found", vim.log.levels.INFO)
end
diff --git a/lua/99/prompt-settings.lua b/lua/99/prompt-settings.lua
index c7e87dd..fb219db 100644
--- a/lua/99/prompt-settings.lua
+++ b/lua/99/prompt-settings.lua
@@ -174,10 +174,7 @@ local prompt_settings = {
--- @param tmp_file string
--- @return string
tmp_file_location = function(tmp_file)
- return string.format(
- "<TEMP_FILE>%s</TEMP_FILE>",
- tmp_file
- )
+ return string.format("<TEMP_FILE>%s</TEMP_FILE>", tmp_file)
end,
--- @return string
diff --git a/lua/99/prompt.lua b/lua/99/prompt.lua
index fbb8265..429ad7b 100644
--- a/lua/99/prompt.lua
+++ b/lua/99/prompt.lua
@@ -158,7 +158,8 @@ end
--- @return string
function Prompt:summary()
- return string.format("%s: %s", self.operation, self.user_prompt)
+ local prompt_str = utils.split_with_count(self.user_prompt, 8)
+ return string.format("%s: %s", self.operation, table.concat(prompt_str, " "))
end
--- @param _99 _99.State
diff --git a/lua/99/state.lua b/lua/99/state.lua
index 397e30f..180c1a9 100644
--- a/lua/99/state.lua
+++ b/lua/99/state.lua
@@ -38,7 +38,6 @@ end
--- @field __request_by_id table<number, _99.Prompt>
--- @field __active_marks _99.Mark[]
--- @field __tmp_dir string | nil
---- @field __qfix_history_idx table<"search" | "vibe", number>
local State = {}
State.__index = State
@@ -56,10 +55,6 @@ local function create()
__view_log_idx = 1,
__request_history = {},
__request_by_id = {},
- __qfix_history_idx = {
- search = 0,
- vibe = 0,
- },
tmp_dir = nil,
}
end
@@ -121,6 +116,11 @@ function State:completed_prompts()
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
diff --git a/lua/99/test/geo_spec.lua b/lua/99/test/geo_spec.lua
index ed67b6f..fbbfedc 100644
--- a/lua/99/test/geo_spec.lua
+++ b/lua/99/test/geo_spec.lua
@@ -5,6 +5,28 @@ local Range = geo.Range
local test_utils = require("99.test.test_utils")
local eq = assert.are.same
+describe("Point", function()
+ local buffer
+
+ before_each(function()
+ buffer = test_utils.create_file({
+ "first line",
+ "middle line",
+ "last line",
+ }, "lua", 1, 0)
+ end)
+
+ after_each(function()
+ test_utils.clean_files()
+ end)
+
+ it("line returns first, middle, and last line", function()
+ eq("first line", Point:from_1_based(1, 1):line(buffer))
+ eq("middle line", Point:from_1_based(2, 1):line(buffer))
+ eq("last line", Point:from_1_based(3, 1):line(buffer))
+ end)
+end)
+
describe("Range", function()
local buffer
diff --git a/lua/99/test/open_spec.lua b/lua/99/test/open_spec.lua
new file mode 100644
index 0000000..a65d8e8
--- /dev/null
+++ b/lua/99/test/open_spec.lua
@@ -0,0 +1,99 @@
+-- luacheck: globals describe it assert before_each after_each
+local _99 = require("99")
+local Window = require("99.window")
+local test_utils = require("99.test.test_utils")
+local QFixHelpers = require("99.ops.qfix-helpers")
+local eq = assert.are.same
+
+local function some_window_has(str)
+ local wins = vim.api.nvim_list_wins()
+
+ for _, winid in ipairs(wins) do
+ local bufnr = vim.api.nvim_win_get_buf(winid)
+ local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
+ local content = table.concat(lines, "\n")
+ if str == content then
+ return
+ end
+ end
+ assert(
+ false,
+ "unable to find buffer with the str contents from an active window"
+ )
+end
+
+local function qfix_items()
+ local items = vim.fn.getqflist()
+ local out = {}
+ for _, item in ipairs(items) do
+ table.insert(out, {
+ filename = vim.api.nvim_buf_get_name(item.bufnr),
+ col = item.col,
+ lnum = item.lnum,
+ text = item.text,
+ })
+ end
+ return out
+end
+
+describe("open", function()
+ local provider
+ local previous_capture_select_input
+
+ before_each(function()
+ provider = test_utils.TestProvider.new()
+ _99.setup(test_utils.get_test_setup_options({}, provider))
+
+ previous_capture_select_input = Window.capture_select_input
+ end)
+
+ after_each(function()
+ Window.capture_select_input = previous_capture_select_input
+ end)
+
+ --- @param term "search" | "tutorial" | "vibe"
+ ---@param result_str any
+ local function op(term, result_str)
+ _99[term]({ additional_prompt = result_str })
+ local out = result_str
+ provider:resolve("success", out)
+ test_utils.next_frame()
+ return out
+ end
+
+ local function search()
+ return op("search", "/tmp/foo.lua:1:1,search note")
+ end
+
+ local function vibe()
+ return op("vibe", "/tmp/bar.lua:2:2,search bar note")
+ end
+
+ local function tutorial()
+ return op("tutorial", "here is a large tutorial")
+ end
+
+ local function select_content(idx)
+ Window.capture_select_input = function(_, opts)
+ opts.cb(true, opts.content[idx])
+ end
+ end
+
+ it("selects a previous search and passes edited output to vibe", function()
+ local s = search()
+ local v = vibe()
+ local t = tutorial()
+
+ select_content(1)
+ _99.open()
+ eq(QFixHelpers.create_qfix_entries(s), qfix_items())
+
+ select_content(2)
+ _99.open()
+ eq(QFixHelpers.create_qfix_entries(v), qfix_items())
+
+ select_content(3)
+ _99.open()
+ some_window_has(t)
+ end)
+end)
diff --git a/lua/99/test/qfix_navigation_spec.lua b/lua/99/test/qfix_navigation_spec.lua
deleted file mode 100644
index f079a9e..0000000
--- a/lua/99/test/qfix_navigation_spec.lua
+++ /dev/null
@@ -1,70 +0,0 @@
--- luacheck: globals describe it assert before_each
-local _99 = require("99")
-local test_utils = require("99.test.test_utils")
-local eq = assert.are.same
-
-local content = {
- "local value = 1",
- "return value",
-}
-
-local function qfix_first_text()
- local items = vim.fn.getqflist()
- local first = items[1]
- assert(first, "expected a quickfix item")
- return first.text
-end
-
-describe("qfix navigation", function()
- local provider
- local results = {}
-
- before_each(function()
- provider = test_utils.test_setup(content, 1, 0)
- end)
-
- it("navigates older and newer search quickfix results", function()
- _99.search({ additional_prompt = "search one" })
- provider:resolve("success", "/tmp/one.lua:1:1,1,first search")
- test_utils.next_frame()
-
- _99.search({ additional_prompt = "search two" })
- provider:resolve("success", "/tmp/two.lua:1:1,1,second search")
- test_utils.next_frame()
-
- _99.search({ additional_prompt = "search three" })
- provider:resolve("success", "/tmp/three.lua:1:1,1,third search")
- test_utils.next_frame()
-
- _99.qfix_older({ operation = "search" })
- eq("second search", qfix_first_text())
-
- _99.qfix_older({ operation = "search" })
- eq("first search", qfix_first_text())
-
- _99.qfix_newer({ operation = "search" })
- eq("second search", qfix_first_text())
-
- _99.qfix_top({ operation = "search" })
- eq("third search", qfix_first_text())
- end)
-
- it("navigates vibe quickfix history through vibe results", function()
- _99.vibe({ additional_prompt = "vibe one" })
- provider:resolve("success", "/tmp/a.lua:1:1,1,first vibe")
- test_utils.next_frame()
-
- _99.vibe({ additional_prompt = "vibe two" })
- provider:resolve("success", "/tmp/b.lua:1:1,1,second vibe")
- test_utils.next_frame()
-
- _99.qfix_top({ operation = "vibe" })
- eq("second vibe", qfix_first_text())
-
- _99.qfix_older({ operation = "vibe" })
- eq("first vibe", qfix_first_text())
-
- _99.qfix_newer({ operation = "vibe" })
- eq("second vibe", qfix_first_text())
- end)
-end)
diff --git a/lua/99/test/utils_spec.lua b/lua/99/test/utils_spec.lua
new file mode 100644
index 0000000..516f902
--- /dev/null
+++ b/lua/99/test/utils_spec.lua
@@ -0,0 +1,19 @@
+-- luacheck: globals describe it assert
+local Utils = require("99.utils")
+local eq = assert.are.same
+
+describe("utils", function()
+ it("split_with_count handles 0, 1, 5, and N + 2 words", function()
+ local str = "alpha\tbeta gamma\ndelta epsilon zeta eta"
+ local words = vim.split(str, "%s+", { trimempty = true })
+ local n = #words
+
+ eq({}, Utils.split_with_count(str, 0))
+ eq({ "alpha" }, Utils.split_with_count(str, 1))
+ eq(
+ { "alpha", "beta", "gamma", "delta", "epsilon" },
+ Utils.split_with_count(str, 5)
+ )
+ eq(words, Utils.split_with_count(str, n + 2))
+ end)
+end)
diff --git a/lua/99/test/vibe_search_spec.lua b/lua/99/test/vibe_search_spec.lua
deleted file mode 100644
index f3f13ae..0000000
--- a/lua/99/test/vibe_search_spec.lua
+++ /dev/null
@@ -1,56 +0,0 @@
--- luacheck: globals describe it assert before_each after_each
-local _99 = require("99")
-local Window = require("99.window")
-local ops = require("99.ops")
-local test_utils = require("99.test.test_utils")
-local eq = assert.are.same
-
-describe("vibe_search", function()
- local provider
- local previous_capture_input
- local previous_capture_select_input
- local previous_vibe
-
- before_each(function()
- provider = test_utils.TestProvider.new()
- _99.setup(test_utils.get_test_setup_options({}, provider))
-
- previous_capture_input = Window.capture_input
- previous_capture_select_input = Window.capture_select_input
- previous_vibe = ops.vibe
- end)
-
- after_each(function()
- Window.capture_input = previous_capture_input
- Window.capture_select_input = previous_capture_select_input
- ops.vibe = previous_vibe
- end)
-
- it("selects a previous search and passes edited output to vibe", function()
- _99.search({
- additional_prompt = "find error handling",
- })
- provider:resolve("success", "/tmp/foo.lua:1:1,search note")
- test_utils.next_frame()
-
- local selected_content
- Window.capture_select_input = function(_, opts)
- opts.cb(true, opts.content[1])
- end
-
- Window.capture_input = function(_, opts)
- selected_content = opts.content
- opts.cb(true, "extra vibe context")
- end
-
- local vibe_prompt
- ops.vibe = function(_, opts)
- vibe_prompt = opts.additional_prompt
- end
-
- _99.vibe_search()
-
- eq({ "/tmp/foo.lua:1:1,search note" }, selected_content)
- eq("extra vibe context", vibe_prompt)
- end)
-end)
diff --git a/lua/99/utils.lua b/lua/99/utils.lua
index 56c49a5..e15e178 100644
--- a/lua/99/utils.lua
+++ b/lua/99/utils.lua
@@ -1,5 +1,20 @@
local M = {}
+--- @param str string
+---@param word_count number
+---@return string[]
+function M.split_with_count(str, word_count)
+ local out = {}
+ local words = vim.split(str, "%s+", { trimempty = true })
+
+ local count = math.min(word_count, #words)
+ for i = 1, count do
+ table.insert(out, words[i])
+ end
+
+ return out
+end
+
function M.copy(t)
assert(type(t) == "table", "passed in non table into table")
local out = {}
diff --git a/lua/99/window/init.lua b/lua/99/window/init.lua
index 47f6f1c..a3a02bb 100644
--- a/lua/99/window/init.lua
+++ b/lua/99/window/init.lua
@@ -1,15 +1,17 @@
--- TODO: I need to refactor a lot of this file
--- it really sucks
local Agents = require("99.extensions.agents")
+local Point = require("99.geo").Point
--- @class _99.window.Module
--- @field active_windows _99.window.Window[]
local M = {
active_windows = {},
}
+
local nsid = vim.api.nvim_create_namespace("99.window.error")
-local nvim_win_is_valid = vim.api.nvim_win_is_valid
-local nvim_buf_is_valid = vim.api.nvim_buf_is_valid
+local win_valid = vim.api.nvim_win_is_valid
+local buf_valid = vim.api.nvim_buf_is_valid
--- @class _99.window.Config
--- @field width number
@@ -199,10 +201,10 @@ end
--- @param window _99.window.Window
local function window_close(window)
- if nvim_win_is_valid(window.win_id) then
+ if win_valid(window.win_id) then
vim.api.nvim_win_close(window.win_id, true)
end
- if nvim_buf_is_valid(window.buf_id) then
+ if buf_valid(window.buf_id) then
vim.api.nvim_buf_delete(window.buf_id, { force = true })
end
end
@@ -210,7 +212,7 @@ end
--- @param window _99.window.Window
--- @return boolean
function M.valid(window)
- return nvim_win_is_valid(window.win_id) and nvim_buf_is_valid(window.buf_id)
+ return win_valid(window.win_id) and buf_valid(window.buf_id)
end
--- @param text string
@@ -228,7 +230,7 @@ function M.display_cancellation_message(text)
})
vim.defer_fn(function()
- if nvim_win_is_valid(window.win_id) then
+ if win_valid(window.win_id) then
M.clear_active_popups()
end
end, 5000)
@@ -293,7 +295,7 @@ local function highlight_rules_found(win, rules, group)
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
+ if not win_valid(win.win_id) then
return
end
@@ -382,7 +384,7 @@ function M.capture_input(name, opts)
group = group,
buffer = win.buf_id,
callback = function()
- if nvim_win_is_valid(win.win_id) then
+ if win_valid(win.win_id) then
vim.api.nvim_set_current_win(win.win_id)
else
M.clear_active_popups()
@@ -394,7 +396,7 @@ function M.capture_input(name, opts)
group = group,
buffer = win.buf_id,
callback = function()
- if not nvim_win_is_valid(win.win_id) then
+ if not win_valid(win.win_id) then
return
end
local lines = vim.api.nvim_buf_get_lines(win.buf_id, 0, -1, false)
@@ -408,7 +410,7 @@ function M.capture_input(name, opts)
group = group,
buffer = win.buf_id,
callback = function()
- if not nvim_win_is_valid(win.win_id) then
+ if not win_valid(win.win_id) then
return
end
vim.api.nvim_del_augroup_by_id(group)
@@ -419,7 +421,7 @@ function M.capture_input(name, opts)
group = group,
pattern = tostring(win.win_id),
callback = function()
- if not nvim_win_is_valid(win.win_id) then
+ if not win_valid(win.win_id) then
return
end
M.clear_active_popups()
@@ -471,19 +473,14 @@ function M.capture_select_input(name, opts)
})
vim.keymap.set("n", "<CR>", function()
- if not nvim_win_is_valid(win.win_id) then
+ if not win_valid(win.win_id) then
return
end
- local cursor = vim.api.nvim_win_get_cursor(win.win_id)
- local line = vim.api.nvim_buf_get_lines(
- win.buf_id,
- cursor[1] - 1,
- cursor[1],
- false
- )[1] or ""
+ local point = Point:from_cursor()
+ local line = point:line(win.buf_id)
M.clear_active_popups()
- opts.cb(true, line)
+ opts.cb(true, line or "")
end, { buffer = win.buf_id, nowait = true })
end
@@ -599,7 +596,7 @@ function M.create_split(content, buffer, opts)
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
+ if not buf_id or not buf_valid(buf_id) then
buf_id = vim.api.nvim_create_buf(false, false)
vim.api.nvim_buf_set_lines(
buf_id,