summaryrefslogtreecommitdiff
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
parent9be01a1a50a61635ea7169e01c85fab41638ad66 (diff)
downloada4-cbc24f940f49b28da62642bca10206f3933bec77.tar.xz
a4-cbc24f940f49b28da62642bca10206f3933bec77.zip
tutorial
-rw-r--r--.agents/skills/vim.diagnostics/SKILL.md83
-rw-r--r--.agents/skills/vim.lsp/SKILL.md114
-rw-r--r--.agents/skills/vim.treesitter/SKILL.md90
-rw-r--r--.agents/skills/vim/SKILL.md734
-rw-r--r--README.md13
-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
21 files changed, 1283 insertions, 363 deletions
diff --git a/.agents/skills/vim.diagnostics/SKILL.md b/.agents/skills/vim.diagnostics/SKILL.md
new file mode 100644
index 0000000..463f7e2
--- /dev/null
+++ b/.agents/skills/vim.diagnostics/SKILL.md
@@ -0,0 +1,83 @@
+# Neovim Diagnostics API Reference
+
+This document contains function definitions for Neovim's diagnostics Lua API.
+Use this as a reference when working with diagnostics in Neovim Lua.
+
+---
+
+## diagnostic
+
+vim.diagnostic APIs, types, and helpers.
+
+```lua
+function get_qf_id_for_title(title)
+function __newindex(t, name, handler)
+function __index(t, bufnr)
+function callback()
+function to_severity(severity)
+function severity_predicate(severity)
+function filter_by_severity(severity, diagnostics)
+function count_sources(bufnr)
+function prefix_source(diagnostics)
+function reformat_diagnostics(format, diagnostics)
+function enabled_value(option, namespace)
+function resolve_optional_value(option, value, namespace, bufnr)
+function get_resolved_options(opts, namespace, bufnr)
+function make_highlight_map(base_name)
+function diagnostic_lines(diagnostics)
+function diagnostics_at_cursor(diagnostics)
+function set_diagnostic_cache(namespace, bufnr, diagnostics)
+function restore_extmarks(bufnr, last)
+function save_extmarks(namespace, bufnr)
+function on_lines(_, _, _, _, _, last)
+function on_detach()
+function severity_to_extmark_priority(priority, opts)
+function make_augroup_key(namespace, bufnr)
+function execute_scheduled_display(namespace, bufnr)
+function schedule_display(namespace, bufnr, args)
+function clear_scheduled_display(namespace, bufnr)
+function get_diagnostics(bufnr, opts, clamp)
+function __index(t, k)
+function add(b, d)
+function add_all_diags(buf, diags)
+function set_list(loclist, opts)
+function filter_highest(diagnostics)
+function next_diagnostic(search_forward, opts)
+function sort_diagnostics(a, b)
+function is_next(d)
+function goto_diagnostic(diagnostic, opts)
+function M.config(opts, namespace)
+function M.set(namespace, bufnr, diagnostics, opts)
+function M.get_namespace(namespace)
+function M.get_namespaces()
+function M.get(bufnr, opts)
+function M.count(bufnr, opts)
+function M.get_prev(opts)
+function M.get_prev_pos(opts)
+function M.goto_prev(opts)
+function M.get_next(opts)
+function M.get_next_pos(opts)
+function M.jump(opts)
+function M.goto_next(opts)
+function show(namespace, bufnr, diagnostics, opts)
+function hide(namespace, bufnr)
+function render_virtual_text(namespace, bufnr, diagnostics, opts)
+function distance_between_cols(bufnr, lnum, start_col, end_col)
+function render_virtual_lines(namespace, bufnr, diagnostics)
+function format_virtual_lines(diagnostic)
+function M._get_virt_text_chunks(line_diags, opts)
+function M.hide(namespace, bufnr)
+function M.is_enabled(filter)
+function M.is_disabled(bufnr, namespace)
+function M.show(namespace, bufnr, diagnostics, opts)
+function M.open_float(opts, ...)
+function M.reset(namespace, bufnr)
+function M.setqflist(opts)
+function M.setloclist(opts)
+function M.disable(bufnr, namespace)
+function M.enable(enable, filter)
+function __index()
+function M.match(str, pat, groups, severity_map, defaults)
+function M.toqflist(diagnostics)
+function M.fromqflist(list)
+```
diff --git a/.agents/skills/vim.lsp/SKILL.md b/.agents/skills/vim.lsp/SKILL.md
new file mode 100644
index 0000000..17aae57
--- /dev/null
+++ b/.agents/skills/vim.lsp/SKILL.md
@@ -0,0 +1,114 @@
+# Neovim LSP API Reference
+
+This document contains function definitions from Neovim's LSP help docs.
+Use this as a reference when working with LSP in Neovim Lua.
+
+---
+
+## lsp
+
+Functions extracted from `lsp.txt`.
+
+```lua
+vim.lsp.buf_attach_client({bufnr}, {client_id})
+vim.lsp.buf_detach_client({bufnr}, {client_id})
+vim.lsp.buf_is_attached({bufnr}, {client_id})
+vim.lsp.buf_notify({bufnr}, {method}, {params})
+vim.lsp.buf_request_all({bufnr}, {method}, {params}, {handler})
+vim.lsp.buf_request_sync({bufnr}, {method}, {params}, {timeout_ms})
+vim.lsp.client_is_stopped({client_id})
+vim.lsp.config({name}, {cfg})
+vim.lsp.enable({name}, {enable})
+vim.lsp.foldclose({kind}, {winid})
+vim.lsp.foldexpr({lnum})
+vim.lsp.foldtext()
+vim.lsp.formatexpr({opts})
+vim.lsp.get_buffers_by_client_id({client_id})
+vim.lsp.get_client_by_id({client_id})
+vim.lsp.get_clients({filter})
+vim.lsp.get_log_path()
+vim.lsp.is_enabled({name})
+vim.lsp.omnifunc({findstart}, {base})
+vim.lsp.set_log_level({level})
+vim.lsp.start({config}, {opts})
+vim.lsp.status()
+vim.lsp.stop_client({client_id}, {force})
+vim.lsp.tagfunc({pattern}, {flags})
+vim.lsp.buf.add_workspace_folder({workspace_folder})
+vim.lsp.buf.clear_references()
+vim.lsp.buf.code_action({opts})
+vim.lsp.buf.declaration({opts})
+vim.lsp.buf.definition({opts})
+vim.lsp.buf.document_highlight()
+vim.lsp.buf.document_symbol({opts})
+vim.lsp.buf.format({opts})
+vim.lsp.buf.hover({config})
+vim.lsp.buf.implementation({opts})
+vim.lsp.buf.incoming_calls()
+vim.lsp.buf.list_workspace_folders()
+vim.lsp.buf.outgoing_calls()
+vim.lsp.buf.references({context}, {opts})
+vim.lsp.buf.remove_workspace_folder({workspace_folder})
+vim.lsp.buf.rename({new_name}, {opts})
+vim.lsp.buf.signature_help({config})
+vim.lsp.buf.type_definition({opts})
+vim.lsp.buf.typehierarchy({kind})
+vim.lsp.buf.workspace_symbol({query}, {opts})
+vim.lsp.diagnostic.from({diagnostics})
+vim.lsp.diagnostic.get_namespace({client_id}, {is_pull})
+vim.lsp.diagnostic.on_diagnostic({error}, {result}, {ctx})
+vim.lsp.diagnostic.on_publish_diagnostics({_}, {params}, {ctx})
+vim.lsp.codelens.clear({client_id}, {bufnr})
+vim.lsp.codelens.display({lenses}, {bufnr}, {client_id})
+vim.lsp.codelens.get({bufnr})
+vim.lsp.codelens.on_codelens({err}, {result}, {ctx})
+vim.lsp.codelens.refresh({opts})
+vim.lsp.codelens.run()
+vim.lsp.codelens.save({lenses}, {bufnr}, {client_id})
+vim.lsp.completion.enable({enable}, {client_id}, {bufnr}, {opts})
+vim.lsp.completion.get({opts})
+vim.lsp.inlay_hint.enable({enable}, {filter})
+vim.lsp.inlay_hint.get({filter})
+vim.lsp.inlay_hint.is_enabled({filter})
+vim.lsp.semantic_tokens.force_refresh({bufnr})
+vim.lsp.semantic_tokens.get_at_pos({bufnr}, {row}, {col})
+vim.lsp.semantic_tokens.highlight_token({token}, {bufnr}, {client_id}, {hl_group}, {opts})
+vim.lsp.semantic_tokens.start({bufnr}, {client_id}, {opts})
+vim.lsp.semantic_tokens.stop({bufnr}, {client_id})
+vim.lsp.util.apply_text_document_edit({text_document_edit}, {index}, {position_encoding})
+vim.lsp.util.apply_text_edits({text_edits}, {bufnr}, {position_encoding})
+vim.lsp.util.apply_workspace_edit({workspace_edit}, {position_encoding})
+vim.lsp.util.buf_clear_references({bufnr})
+vim.lsp.util.buf_highlight_references({bufnr}, {references}, {position_encoding})
+vim.lsp.util.character_offset({buf}, {row}, {col}, {offset_encoding})
+vim.lsp.util.convert_input_to_markdown_lines({input}, {contents})
+vim.lsp.util.convert_signature_help_to_markdown_lines({signature_help}, {ft}, {triggers})
+vim.lsp.util.get_effective_tabstop({bufnr})
+vim.lsp.util.locations_to_items({locations}, {position_encoding})
+vim.lsp.util.make_floating_popup_options({width}, {height}, {opts})
+vim.lsp.util.make_formatting_params({options})
+vim.lsp.util.make_given_range_params({start_pos}, {end_pos}, {bufnr}, {position_encoding})
+vim.lsp.util.make_position_params({window}, {position_encoding})
+vim.lsp.util.make_range_params({window}, {position_encoding})
+vim.lsp.util.make_text_document_params({bufnr})
+vim.lsp.util.make_workspace_params({added}, {removed})
+vim.lsp.util.open_floating_preview({contents}, {syntax}, {opts})
+vim.lsp.util.preview_location({location}, {opts})
+vim.lsp.util.rename({old_fname}, {new_fname}, {opts})
+vim.lsp.util.show_document({location}, {position_encoding}, {opts})
+vim.lsp.util.stylize_markdown({bufnr}, {contents}, {opts})
+vim.lsp.util.symbols_to_items({symbols}, {bufnr}, {position_encoding})
+vim.lsp.log.get_filename()
+vim.lsp.log.get_level()
+vim.lsp.log.set_format_func({handle})
+vim.lsp.log.set_level({level})
+vim.lsp.log.should_log({level})
+vim.lsp.rpc.connect({host_or_path}, {port})
+vim.lsp.rpc.format_rpc_error({err})
+vim.lsp.rpc.notify({method}, {params})
+vim.lsp.rpc.request({method}, {params}, {callback}, {notify_reply_callback})
+vim.lsp.rpc.rpc_response_error({code}, {message}, {data})
+vim.lsp.rpc.start({cmd}, {dispatchers}, {extra_spawn_params})
+vim.lsp.protocol.make_client_capabilities()
+vim.lsp.protocol.resolve_capabilities({server_capabilities})
+```
diff --git a/.agents/skills/vim.treesitter/SKILL.md b/.agents/skills/vim.treesitter/SKILL.md
new file mode 100644
index 0000000..6a3da81
--- /dev/null
+++ b/.agents/skills/vim.treesitter/SKILL.md
@@ -0,0 +1,90 @@
+# Neovim Treesitter API Reference
+
+This document contains type stubs and API references for Neovim's treesitter Lua API.
+Use this as a reference when working with treesitter in Neovim Lua.
+
+---
+
+## tsnode
+
+TSNode methods - represents a specific element in a parsed syntax tree. Use these methods to navigate and inspect nodes.
+
+```lua
+function TSNode:parent() end
+function TSNode:next_sibling() end
+function TSNode:prev_sibling() end
+function TSNode:next_named_sibling() end
+function TSNode:prev_named_sibling() end
+function TSNode:iter_children() end
+function TSNode:field(name) end
+function TSNode:child_count() end
+function TSNode:child(index) end
+function TSNode:named_child_count() end
+function TSNode:named_children() end
+function TSNode:__has_ancestor(node_types) end
+function TSNode:named_child(index) end
+function TSNode:child_with_descendant(descendant) end
+function TSNode:start() end
+function TSNode:end_() end
+function TSNode:range(include_bytes) end
+function TSNode:type() end
+function TSNode:symbol() end
+function TSNode:named() end
+function TSNode:missing() end
+function TSNode:extra() end
+function TSNode:has_changes() end
+function TSNode:has_error() end
+function TSNode:sexpr() end
+function TSNode:id() end
+function TSNode:tree() end
+function TSNode:descendant_for_range(start_row, start_col, end_row, end_col) end
+function TSNode:named_descendant_for_range(start_row, start_col, end_row, end_col) end
+function TSNode:equal(node) end
+function TSNode:byte_length() end
+```
+
+---
+
+## tstree
+
+TSTree methods - represents the parsed contents of a buffer.
+
+```lua
+function TSTree:root() end
+function TSTree:edit(start_byte, end_byte_old, end_byte_new, start_row, start_col, end_row_old, end_col_old, end_row_new, end_col_new) end
+function TSTree:copy() end
+function TSTree:included_ranges(include_bytes) end
+function TSTree:included_ranges(include_bytes) end
+```
+
+---
+
+## tsquery
+
+TSQuery methods - for working with treesitter queries.
+
+```lua
+function TSQuery:inspect() end
+function TSQuery:disable_capture(capture_name) end
+function TSQuery:disable_pattern(pattern_index) end
+```
+
+---
+
+## misc
+
+Various treesitter types including TSParser, TSQueryMatch, TSQueryCursor, and TSLangInfo.
+
+```lua
+vim._ts_inspect_language = function(lang) end
+vim._ts_get_language_version = function() end
+vim._ts_add_language_from_object = function(path, lang, symbol_name) end
+vim._ts_add_language_from_wasm = function(path, lang) end
+vim._ts_get_minimum_language_version = function() end
+vim._ts_parse_query = function(lang, query) end
+vim._create_ts_parser = function(lang) end
+function TSQueryMatch:info() end
+function TSQueryCursor:next_capture() end
+function TSQueryCursor:next_match() end
+function vim._create_ts_querycursor(node, query, start, stop, opts) end
+```
diff --git a/.agents/skills/vim/SKILL.md b/.agents/skills/vim/SKILL.md
new file mode 100644
index 0000000..9bef4fb
--- /dev/null
+++ b/.agents/skills/vim/SKILL.md
@@ -0,0 +1,734 @@
+# Neovim Lua API Reference
+
+This document contains type stubs and API references for Neovim's Lua API.
+Use this as a reference when writing Neovim plugins or configurations in Lua.
+
+---
+
+## api
+
+The following are type stubs for all the functions available on `vim.api.*`. Prefer these functions where possible.
+
+```lua
+vim.api = {}
+vim.api.nvim__buf_debug_extmarks(buffer, keys, dot)
+vim.api.nvim__buf_stats(buffer)
+vim.api.nvim__complete_set(index, opts)
+vim.api.nvim__get_lib_dir()
+vim.api.nvim__get_runtime(pat, all, opts)
+vim.api.nvim__id(obj)
+vim.api.nvim__id_array(arr)
+vim.api.nvim__id_dict(dct)
+vim.api.nvim__id_float(flt)
+vim.api.nvim__inspect_cell(grid, row, col)
+vim.api.nvim__invalidate_glyph_cache()
+vim.api.nvim__ns_get(ns_id)
+vim.api.nvim__ns_set(ns_id, opts)
+vim.api.nvim__redraw(opts)
+vim.api.nvim__runtime_inspect()
+vim.api.nvim__screenshot(path)
+vim.api.nvim__stats()
+vim.api.nvim__unpack(str)
+vim.api.nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start, col_end)
+vim.api.nvim_buf_attach(buffer, send_buffer, opts)
+vim.api.nvim_buf_call(buffer, fun)
+vim.api.nvim_buf_clear_highlight(buffer, ns_id, line_start, line_end)
+vim.api.nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end)
+vim.api.nvim_buf_create_user_command(buffer, name, command, opts)
+vim.api.nvim_buf_del_extmark(buffer, ns_id, id)
+vim.api.nvim_buf_del_keymap(buffer, mode, lhs)
+vim.api.nvim_buf_del_mark(buffer, name)
+vim.api.nvim_buf_del_user_command(buffer, name)
+vim.api.nvim_buf_del_var(buffer, name)
+vim.api.nvim_buf_delete(buffer, opts)
+vim.api.nvim_buf_get_changedtick(buffer)
+vim.api.nvim_buf_get_commands(buffer, opts)
+vim.api.nvim_buf_get_extmark_by_id(buffer, ns_id, id, opts)
+vim.api.nvim_buf_get_extmarks(buffer, ns_id, start, end_, opts)
+vim.api.nvim_buf_get_keymap(buffer, mode)
+vim.api.nvim_buf_get_lines(buffer, start, end_, strict_indexing)
+vim.api.nvim_buf_get_mark(buffer, name)
+vim.api.nvim_buf_get_name(buffer)
+vim.api.nvim_buf_get_number(buffer)
+vim.api.nvim_buf_get_offset(buffer, index)
+vim.api.nvim_buf_get_option(buffer, name)
+vim.api.nvim_buf_get_text(buffer, start_row, start_col, end_row, end_col, opts)
+vim.api.nvim_buf_get_var(buffer, name)
+vim.api.nvim_buf_is_loaded(buffer)
+vim.api.nvim_buf_is_valid(buffer)
+vim.api.nvim_buf_line_count(buffer)
+vim.api.nvim_buf_set_extmark(buffer, ns_id, line, col, opts)
+vim.api.nvim_buf_set_keymap(buffer, mode, lhs, rhs, opts)
+vim.api.nvim_buf_set_lines(buffer, start, end_, strict_indexing, replacement)
+vim.api.nvim_buf_set_mark(buffer, name, line, col, opts)
+vim.api.nvim_buf_set_name(buffer, name)
+vim.api.nvim_buf_set_option(buffer, name, value)
+vim.api.nvim_buf_set_text(buffer, start_row, start_col, end_row, end_col, replacement)
+vim.api.nvim_buf_set_var(buffer, name, value)
+vim.api.nvim_buf_set_virtual_text(buffer, src_id, line, chunks, opts)
+vim.api.nvim_call_dict_function(dict, fn, args)
+vim.api.nvim_call_function(fn, args)
+vim.api.nvim_chan_send(chan, data)
+vim.api.nvim_clear_autocmds(opts)
+vim.api.nvim_cmd(cmd, opts)
+vim.api.nvim_command(command)
+vim.api.nvim_command_output(command)
+vim.api.nvim_create_augroup(name, opts)
+vim.api.nvim_create_autocmd(event, opts)
+vim.api.nvim_create_buf(listed, scratch)
+vim.api.nvim_create_namespace(name)
+vim.api.nvim_create_user_command(name, command, opts)
+vim.api.nvim_del_augroup_by_id(id)
+vim.api.nvim_del_augroup_by_name(name)
+vim.api.nvim_del_autocmd(id)
+vim.api.nvim_del_current_line()
+vim.api.nvim_del_keymap(mode, lhs)
+vim.api.nvim_del_mark(name)
+vim.api.nvim_del_user_command(name)
+vim.api.nvim_del_var(name)
+vim.api.nvim_echo(chunks, history, opts)
+vim.api.nvim_err_write(str)
+vim.api.nvim_err_writeln(str)
+vim.api.nvim_eval(expr)
+vim.api.nvim_eval_statusline(str, opts)
+vim.api.nvim_exec(src, output)
+vim.api.nvim_exec2(src, opts)
+vim.api.nvim_exec_autocmds(event, opts)
+vim.api.nvim_feedkeys(keys, mode, escape_ks)
+vim.api.nvim_get_all_options_info()
+vim.api.nvim_get_autocmds(opts)
+vim.api.nvim_get_chan_info(chan)
+vim.api.nvim_get_color_by_name(name)
+vim.api.nvim_get_color_map()
+vim.api.nvim_get_commands(opts)
+vim.api.nvim_get_context(opts)
+vim.api.nvim_get_current_buf()
+vim.api.nvim_get_current_line()
+vim.api.nvim_get_current_tabpage()
+vim.api.nvim_get_current_win()
+vim.api.nvim_get_hl(ns_id, opts)
+vim.api.nvim_get_hl_by_id(hl_id, rgb)
+vim.api.nvim_get_hl_by_name(name, rgb)
+vim.api.nvim_get_hl_id_by_name(name)
+vim.api.nvim_get_hl_ns(opts)
+vim.api.nvim_get_keymap(mode)
+vim.api.nvim_get_mark(name, opts)
+vim.api.nvim_get_mode()
+vim.api.nvim_get_namespaces()
+vim.api.nvim_get_option(name)
+vim.api.nvim_get_option_info(name)
+vim.api.nvim_get_option_info2(name, opts)
+vim.api.nvim_get_option_value(name, opts)
+vim.api.nvim_get_proc(pid)
+vim.api.nvim_get_proc_children(pid)
+vim.api.nvim_get_runtime_file(name, all)
+vim.api.nvim_get_var(name)
+vim.api.nvim_get_vvar(name)
+vim.api.nvim_input(keys)
+vim.api.nvim_input_mouse(button, action, modifier, grid, row, col)
+vim.api.nvim_list_bufs()
+vim.api.nvim_list_chans()
+vim.api.nvim_list_runtime_paths()
+vim.api.nvim_list_tabpages()
+vim.api.nvim_list_uis()
+vim.api.nvim_list_wins()
+vim.api.nvim_load_context(dict)
+vim.api.nvim_notify(msg, log_level, opts)
+vim.api.nvim_open_term(buffer, opts)
+vim.api.nvim_open_win(buffer, enter, config)
+vim.api.nvim_out_write(str)
+vim.api.nvim_parse_cmd(str, opts)
+vim.api.nvim_parse_expression(expr, flags, highlight)
+vim.api.nvim_paste(data, crlf, phase)
+vim.api.nvim_put(lines, type, after, follow)
+vim.api.nvim_replace_termcodes(str, from_part, do_lt, special)
+vim.api.nvim_select_popupmenu_item(item, insert, finish, opts)
+vim.api.nvim_set_current_buf(buffer)
+vim.api.nvim_set_current_dir(dir)
+vim.api.nvim_set_current_line(line)
+vim.api.nvim_set_current_tabpage(tabpage)
+vim.api.nvim_set_current_win(window)
+vim.api.nvim_set_decoration_provider(ns_id, opts)
+vim.api.nvim_set_hl(ns_id, name, val)
+vim.api.nvim_set_hl_ns(ns_id)
+vim.api.nvim_set_hl_ns_fast(ns_id)
+vim.api.nvim_set_keymap(mode, lhs, rhs, opts)
+vim.api.nvim_set_option(name, value)
+vim.api.nvim_set_option_value(name, value, opts)
+vim.api.nvim_set_var(name, value)
+vim.api.nvim_set_vvar(name, value)
+vim.api.nvim_strwidth(text)
+vim.api.nvim_tabpage_del_var(tabpage, name)
+vim.api.nvim_tabpage_get_number(tabpage)
+vim.api.nvim_tabpage_get_var(tabpage, name)
+vim.api.nvim_tabpage_get_win(tabpage)
+vim.api.nvim_tabpage_is_valid(tabpage)
+vim.api.nvim_tabpage_list_wins(tabpage)
+vim.api.nvim_tabpage_set_var(tabpage, name, value)
+vim.api.nvim_tabpage_set_win(tabpage, win)
+vim.api.nvim_win_call(window, fun)
+vim.api.nvim_win_close(window, force)
+vim.api.nvim_win_del_var(window, name)
+vim.api.nvim_win_get_buf(window)
+vim.api.nvim_win_get_config(window)
+vim.api.nvim_win_get_cursor(window)
+vim.api.nvim_win_get_height(window)
+vim.api.nvim_win_get_number(window)
+vim.api.nvim_win_get_option(window, name)
+vim.api.nvim_win_get_position(window)
+vim.api.nvim_win_get_tabpage(window)
+vim.api.nvim_win_get_var(window, name)
+vim.api.nvim_win_get_width(window)
+vim.api.nvim_win_hide(window)
+vim.api.nvim_win_is_valid(window)
+vim.api.nvim_win_set_buf(window, buffer)
+vim.api.nvim_win_set_config(window, config)
+vim.api.nvim_win_set_cursor(window, pos)
+vim.api.nvim_win_set_height(window, height)
+vim.api.nvim_win_set_hl_ns(window, ns_id)
+vim.api.nvim_win_set_option(window, name, value)
+vim.api.nvim_win_set_var(window, name, value)
+vim.api.nvim_win_set_width(window, width)
+vim.api.nvim_win_text_height(window, opts)
+```
+
+---
+
+## builtin
+
+Various APIs that are provided by Neovim, that are unique to the Lua API.
+
+```lua
+vim.NIL = ...
+function vim.in_fast_event() end
+function vim.empty_dict() end
+function vim.rpcnotify(channel, method, ...) end
+function vim.rpcrequest(channel, method, ...) end
+function vim.stricmp(a, b) end
+function vim.str_utf_pos(str) end
+function vim.str_utf_start(str, index) end
+function vim.str_utf_end(str, index) end
+function vim.iconv(str, from, to, opts) end
+function vim.schedule(fn) end
+function vim.wait(time, callback, interval, fast_only) end
+function vim.ui_attach(ns, options, callback) end
+function vim.ui_detach(ns) end
+```
+
+---
+
+## api_keysets
+
+The following describe various types that are used in Neovim's API.
+
+```lua
+
+```
+
+---
+
+## api_keysets_extra
+
+Additional types that are used in Neovim's API.
+
+```lua
+
+```
+
+---
+
+## builtin_types
+
+Various types used by Neovim's builtin APIs.
+
+```lua
+
+```
+
+---
+
+## vimfn
+
+Functions available from Neovim's vimscript APIs. They are available via `vim.fn.*`.
+
+```lua
+vim.fn.abs(expr)
+vim.fn.acos(expr)
+vim.fn.add(object, expr)
+vim.fn['and'] = function(expr, expr1)
+vim.fn.api_info()
+vim.fn.append(lnum, text)
+vim.fn.appendbufline(buf, lnum, text)
+vim.fn.argc(winid)
+vim.fn.argidx()
+vim.fn.arglistid(winnr, tabnr)
+vim.fn.argv(nr, winid)
+vim.fn.asin(expr)
+vim.fn.assert_beeps(cmd)
+vim.fn.assert_equal(expected, actual, msg)
+vim.fn.assert_equalfile(fname_one, fname_two)
+vim.fn.assert_exception(error, msg)
+vim.fn.assert_fails(cmd, error, msg, lnum, context)
+vim.fn.assert_false(actual, msg)
+vim.fn.assert_inrange(lower, upper, actual, msg)
+vim.fn.assert_match(pattern, actual, msg)
+vim.fn.assert_nobeep(cmd)
+vim.fn.assert_notequal(expected, actual, msg)
+vim.fn.assert_notmatch(pattern, actual, msg)
+vim.fn.assert_report(msg)
+vim.fn.assert_true(actual, msg)
+vim.fn.atan(expr)
+vim.fn.atan2(expr1, expr2)
+vim.fn.blob2list(blob)
+vim.fn.browse(save, title, initdir, default)
+vim.fn.browsedir(title, initdir)
+vim.fn.bufadd(name)
+vim.fn.bufexists(buf)
+vim.fn.buffer_exists(...)
+vim.fn.buffer_name(...)
+vim.fn.buffer_number(...)
+vim.fn.buflisted(buf)
+vim.fn.bufload(buf)
+vim.fn.bufloaded(buf)
+vim.fn.bufname(buf)
+vim.fn.bufnr(buf, create)
+vim.fn.bufwinid(buf)
+vim.fn.bufwinnr(buf)
+vim.fn.byte2line(byte)
+vim.fn.byteidx(expr, nr, utf16)
+vim.fn.byteidxcomp(expr, nr, utf16)
+vim.fn.call(func, arglist, dict)
+vim.fn.ceil(expr)
+vim.fn.chanclose(id, stream)
+vim.fn.changenr()
+vim.fn.chansend(id, data)
+vim.fn.char2nr(string, utf8)
+vim.fn.charclass(string)
+vim.fn.charcol(expr, winid)
+vim.fn.charidx(string, idx, countcc, utf16)
+vim.fn.chdir(dir)
+vim.fn.cindent(lnum)
+vim.fn.clearmatches(win)
+vim.fn.col(expr, winid)
+vim.fn.complete(startcol, matches)
+vim.fn.complete_add(expr)
+vim.fn.complete_check()
+vim.fn.complete_info(what)
+vim.fn.confirm(msg, choices, default, type)
+vim.fn.copy(expr)
+vim.fn.cos(expr)
+vim.fn.cosh(expr)
+vim.fn.count(comp, expr, ic, start)
+vim.fn.ctxget(index)
+vim.fn.ctxpop()
+vim.fn.ctxpush(types)
+vim.fn.ctxset(context, index)
+vim.fn.ctxsize()
+vim.fn.cursor(lnum, col, off)
+vim.fn.cursor(list)
+vim.fn.debugbreak(pid)
+vim.fn.deepcopy(expr, noref)
+vim.fn.delete(fname, flags)
+vim.fn.deletebufline(buf, first, last)
+vim.fn.dictwatcheradd(dict, pattern, callback)
+vim.fn.dictwatcherdel(dict, pattern, callback)
+vim.fn.did_filetype()
+vim.fn.diff_filler(lnum)
+vim.fn.diff_hlID(lnum, col)
+vim.fn.digraph_get(chars)
+vim.fn.digraph_getlist(listall)
+vim.fn.digraph_set(chars, digraph)
+vim.fn.digraph_setlist(digraphlist)
+vim.fn.empty(expr)
+vim.fn.environ()
+vim.fn.escape(string, chars)
+vim.fn.eval(string)
+vim.fn.eventhandler()
+vim.fn.executable(expr)
+vim.fn.execute(command, silent)
+vim.fn.exepath(expr)
+vim.fn.exists(expr)
+vim.fn.exp(expr)
+vim.fn.expand(string, nosuf, list)
+vim.fn.expand(string, nosuf, list)
+vim.fn.expandcmd(string, options)
+vim.fn.extend(expr1, expr2, expr3)
+vim.fn.extendnew(expr1, expr2, expr3)
+vim.fn.feedkeys(string, mode)
+vim.fn.file_readable(file)
+vim.fn.filecopy(from, to)
+vim.fn.filereadable(file)
+vim.fn.filewritable(file)
+vim.fn.filter(expr1, expr2)
+vim.fn.finddir(name, path, count)
+vim.fn.findfile(name, path, count)
+vim.fn.flatten(list, maxdepth)
+vim.fn.flattennew(list, maxdepth)
+vim.fn.float2nr(expr)
+vim.fn.floor(expr)
+vim.fn.fmod(expr1, expr2)
+vim.fn.fnameescape(string)
+vim.fn.fnamemodify(fname, mods)
+vim.fn.foldclosed(lnum)
+vim.fn.foldclosedend(lnum)
+vim.fn.foldlevel(lnum)
+vim.fn.foldtext()
+vim.fn.foldtextresult(lnum)
+vim.fn.foreach(expr1, expr2)
+vim.fn.fullcommand(name)
+vim.fn.funcref(name, arglist, dict)
+vim.fn['function'] = function(name, arglist, dict)
+vim.fn.garbagecollect(atexit)
+vim.fn.get(list, idx, default)
+vim.fn.get(blob, idx, default)
+vim.fn.get(dict, key, default)
+vim.fn.get(func, what)
+vim.fn.getbufinfo(buf)
+vim.fn.getbufinfo(dict)
+vim.fn.getbufline(buf, lnum, end_)
+vim.fn.getbufoneline(buf, lnum)
+vim.fn.getbufvar(buf, varname, def)
+vim.fn.getcellwidths()
+vim.fn.getchangelist(buf)
+vim.fn.getchar(expr, opts)
+vim.fn.getcharmod()
+vim.fn.getcharpos(expr)
+vim.fn.getcharsearch()
+vim.fn.getcharstr(expr, opts)
+vim.fn.getcmdcomplpat()
+vim.fn.getcmdcompltype()
+vim.fn.getcmdline()
+vim.fn.getcmdpos()
+vim.fn.getcmdprompt()
+vim.fn.getcmdscreenpos()
+vim.fn.getcmdtype()
+vim.fn.getcmdwintype()
+vim.fn.getcompletion(pat, type, filtered)
+vim.fn.getcurpos(winid)
+vim.fn.getcursorcharpos(winid)
+vim.fn.getcwd(winnr, tabnr)
+vim.fn.getenv(name)
+vim.fn.getfontname(name)
+vim.fn.getfperm(fname)
+vim.fn.getfsize(fname)
+vim.fn.getftime(fname)
+vim.fn.getftype(fname)
+vim.fn.getjumplist(winnr, tabnr)
+vim.fn.getline(lnum, end_)
+vim.fn.getline(lnum, end_)
+vim.fn.getloclist(nr, what)
+vim.fn.getmarklist(buf)
+vim.fn.getmatches(win)
+vim.fn.getmousepos()
+vim.fn.getpid()
+vim.fn.getpos(expr)
+vim.fn.getqflist(what)
+vim.fn.getreg(regname, list)
+vim.fn.getreg(regname, list)
+vim.fn.getreginfo(regname)
+vim.fn.getregion(pos1, pos2, opts)
+vim.fn.getregionpos(pos1, pos2, opts)
+vim.fn.getregtype(regname)
+vim.fn.getscriptinfo(opts)
+vim.fn.getstacktrace()
+vim.fn.gettabinfo(tabnr)
+vim.fn.gettabvar(tabnr, varname, def)
+vim.fn.gettabwinvar(tabnr, winnr, varname, def)
+vim.fn.gettagstack(winnr)
+vim.fn.gettext(text)
+vim.fn.getwininfo(winid)
+vim.fn.getwinpos(timeout)
+vim.fn.getwinposx()
+vim.fn.getwinposy()
+vim.fn.getwinvar(winnr, varname, def)
+vim.fn.glob(expr, nosuf, list, alllinks)
+vim.fn.glob2regpat(string)
+vim.fn.globpath(path, expr, nosuf, list, allinks)
+vim.fn.has(feature)
+vim.fn.has_key(dict, key)
+vim.fn.haslocaldir(winnr, tabnr)
+vim.fn.hasmapto(what, mode, abbr)
+vim.fn.highlightID(name)
+vim.fn.highlight_exists(name)
+vim.fn.histadd(history, item)
+vim.fn.histdel(history, item)
+vim.fn.histget(history, index)
+vim.fn.histnr(history)
+vim.fn.hlID(name)
+vim.fn.hlexists(name)
+vim.fn.hostname()
+vim.fn.iconv(string, from, to)
+vim.fn.id(expr)
+vim.fn.indent(lnum)
+vim.fn.index(object, expr, start, ic)
+vim.fn.indexof(object, expr, opts)
+vim.fn.input(prompt, text, completion)
+vim.fn.input(opts)
+vim.fn.inputdialog(...)
+vim.fn.inputlist(textlist)
+vim.fn.inputrestore()
+vim.fn.inputsave()
+vim.fn.inputsecret(prompt, text)
+vim.fn.insert(object, item, idx)
+vim.fn.interrupt()
+vim.fn.invert(expr)
+vim.fn.isabsolutepath(path)
+vim.fn.isdirectory(directory)
+vim.fn.isinf(expr)
+vim.fn.islocked(expr)
+vim.fn.isnan(expr)
+vim.fn.items(dict)
+vim.fn.jobclose(...)
+vim.fn.jobpid(job)
+vim.fn.jobresize(job, width, height)
+vim.fn.jobsend(...)
+vim.fn.jobstart(cmd, opts)
+vim.fn.jobstop(id)
+vim.fn.jobwait(jobs, timeout)
+vim.fn.join(list, sep)
+vim.fn.json_decode(expr)
+vim.fn.json_encode(expr)
+vim.fn.keys(dict)
+vim.fn.keytrans(string)
+vim.fn.last_buffer_nr()
+vim.fn.len(expr)
+vim.fn.libcall(libname, funcname, argument)
+vim.fn.libcallnr(libname, funcname, argument)
+vim.fn.line(expr, winid)
+vim.fn.line2byte(lnum)
+vim.fn.lispindent(lnum)
+vim.fn.list2blob(list)
+vim.fn.list2str(list, utf8)
+vim.fn.localtime()
+vim.fn.log(expr)
+vim.fn.log10(expr)
+vim.fn.map(expr1, expr2)
+vim.fn.maparg(name, mode, abbr, dict)
+vim.fn.maparg(name, mode, abbr, dict)
+vim.fn.mapcheck(name, mode, abbr)
+vim.fn.maplist(abbr)
+vim.fn.mapnew(expr1, expr2)
+vim.fn.mapset(mode, abbr, dict)
+vim.fn.mapset(dict)
+vim.fn.match(expr, pat, start, count)
+vim.fn.matchadd(group, pattern, priority, id, dict)
+vim.fn.matchaddpos(group, pos, priority, id, dict)
+vim.fn.matcharg(nr)
+vim.fn.matchbufline(buf, pat, lnum, end_, dict)
+vim.fn.matchdelete(id, win)
+vim.fn.matchend(expr, pat, start, count)
+vim.fn.matchfuzzy(list, str, dict)
+vim.fn.matchfuzzypos(list, str, dict)
+vim.fn.matchlist(expr, pat, start, count)
+vim.fn.matchstr(expr, pat, start, count)
+vim.fn.matchstrlist(list, pat, dict)
+vim.fn.matchstrpos(expr, pat, start, count)
+vim.fn.max(expr)
+vim.fn.menu_get(path, modes)
+vim.fn.menu_info(name, mode)
+vim.fn.min(expr)
+vim.fn.mkdir(name, flags, prot)
+vim.fn.mode(expr)
+vim.fn.msgpackdump(list, type)
+vim.fn.msgpackparse(data)
+vim.fn.nextnonblank(lnum)
+vim.fn.nr2char(expr, utf8)
+vim.fn['or'] = function(expr, expr1)
+vim.fn.pathshorten(path, len)
+vim.fn.perleval(expr)
+vim.fn.pow(x, y)
+vim.fn.prevnonblank(lnum)
+vim.fn.printf(fmt, expr1)
+vim.fn.prompt_getprompt(buf)
+vim.fn.prompt_setcallback(buf, expr)
+vim.fn.prompt_setinterrupt(buf, expr)
+vim.fn.prompt_setprompt(buf, text)
+vim.fn.pum_getpos()
+vim.fn.pumvisible()
+vim.fn.py3eval(expr)
+vim.fn.pyeval(expr)
+vim.fn.pyxeval(expr)
+vim.fn.rand(expr)
+vim.fn.range(expr, max, stride)
+vim.fn.readblob(fname, offset, size)
+vim.fn.readdir(directory, expr)
+vim.fn.readfile(fname, type, max)
+vim.fn.reduce(object, func, initial)
+vim.fn.reg_executing()
+vim.fn.reg_recorded()
+vim.fn.reg_recording()
+vim.fn.reltime()
+vim.fn.reltime(start)
+vim.fn.reltime(start, end_)
+vim.fn.reltimefloat(time)
+vim.fn.reltimestr(time)
+vim.fn.remove(list, idx)
+vim.fn.remove(list, idx, end_)
+vim.fn.remove(blob, idx)
+vim.fn.remove(blob, idx, end_)
+vim.fn.remove(dict, key)
+vim.fn.rename(from, to)
+vim.fn['repeat'] = function(expr, count)
+vim.fn.resolve(filename)
+vim.fn.reverse(object)
+vim.fn.round(expr)
+vim.fn.rpcnotify(channel, event, ...)
+vim.fn.rpcrequest(channel, method, ...)
+vim.fn.rpcstart(prog, argv)
+vim.fn.rpcstop(...)
+vim.fn.rubyeval(expr)
+vim.fn.screenattr(row, col)
+vim.fn.screenchar(row, col)
+vim.fn.screenchars(row, col)
+vim.fn.screencol()
+vim.fn.screenpos(winid, lnum, col)
+vim.fn.screenrow()
+vim.fn.screenstring(row, col)
+vim.fn.search(pattern, flags, stopline, timeout, skip)
+vim.fn.searchcount(options)
+vim.fn.searchdecl(name, global, thisblock)
+vim.fn.searchpair(start, middle, end_, flags, skip, stopline, timeout)
+vim.fn.searchpairpos(start, middle, end_, flags, skip, stopline, timeout)
+vim.fn.searchpos(pattern, flags, stopline, timeout, skip)
+vim.fn.serverlist()
+vim.fn.serverstart(address)
+vim.fn.serverstop(address)
+vim.fn.setbufline(buf, lnum, text)
+vim.fn.setbufvar(buf, varname, val)
+vim.fn.setcellwidths(list)
+vim.fn.setcharpos(expr, list)
+vim.fn.setcharsearch(dict)
+vim.fn.setcmdline(str, pos)
+vim.fn.setcmdpos(pos)
+vim.fn.setcursorcharpos(lnum, col, off)
+vim.fn.setcursorcharpos(list)
+vim.fn.setenv(name, val)
+vim.fn.setfperm(fname, mode)
+vim.fn.setline(lnum, text)
+vim.fn.setloclist(nr, list, action, what)
+vim.fn.setmatches(list, win)
+vim.fn.setpos(expr, list)
+vim.fn.setqflist(list, action, what)
+vim.fn.setreg(regname, value, options)
+vim.fn.settabvar(tabnr, varname, val)
+vim.fn.settabwinvar(tabnr, winnr, varname, val)
+vim.fn.settagstack(nr, dict, action)
+vim.fn.setwinvar(nr, varname, val)
+vim.fn.sha256(string)
+vim.fn.shellescape(string, special)
+vim.fn.shiftwidth(col)
+vim.fn.sign_define(name, dict)
+vim.fn.sign_define(list)
+vim.fn.sign_getdefined(name)
+vim.fn.sign_getplaced(buf, dict)
+vim.fn.sign_jump(id, group, buf)
+vim.fn.sign_place(id, group, name, buf, dict)
+vim.fn.sign_placelist(list)
+vim.fn.sign_undefine(name)
+vim.fn.sign_undefine(list)
+vim.fn.sign_unplace(group, dict)
+vim.fn.sign_unplacelist(list)
+vim.fn.simplify(filename)
+vim.fn.sin(expr)
+vim.fn.sinh(expr)
+vim.fn.slice(expr, start, end_)
+vim.fn.sockconnect(mode, address, opts)
+vim.fn.sort(list, how, dict)
+vim.fn.soundfold(word)
+vim.fn.spellbadword(sentence)
+vim.fn.spellsuggest(word, max, capital)
+vim.fn.split(string, pattern, keepempty)
+vim.fn.sqrt(expr)
+vim.fn.srand(expr)
+vim.fn.state(what)
+vim.fn.stdioopen(opts)
+vim.fn.stdpath(what)
+vim.fn.stdpath(what)
+vim.fn.stdpath(what)
+vim.fn.str2float(string, quoted)
+vim.fn.str2list(string, utf8)
+vim.fn.str2nr(string, base)
+vim.fn.strcharlen(string)
+vim.fn.strcharpart(src, start, len, skipcc)
+vim.fn.strchars(string, skipcc)
+vim.fn.strdisplaywidth(string, col)
+vim.fn.strftime(format, time)
+vim.fn.strgetchar(str, index)
+vim.fn.stridx(haystack, needle, start)
+vim.fn.string(expr)
+vim.fn.strlen(string)
+vim.fn.strpart(src, start, len, chars)
+vim.fn.strptime(format, timestring)
+vim.fn.strridx(haystack, needle, start)
+vim.fn.strtrans(string)
+vim.fn.strutf16len(string, countcc)
+vim.fn.strwidth(string)
+vim.fn.submatch(nr, list)
+vim.fn.submatch(nr, list)
+vim.fn.substitute(string, pat, sub, flags)
+vim.fn.swapfilelist()
+vim.fn.swapinfo(fname)
+vim.fn.swapname(buf)
+vim.fn.synID(lnum, col, trans)
+vim.fn.synIDattr(synID, what, mode)
+vim.fn.synIDtrans(synID)
+vim.fn.synconcealed(lnum, col)
+vim.fn.synstack(lnum, col)
+vim.fn.system(cmd, input)
+vim.fn.systemlist(cmd, input, keepempty)
+vim.fn.tabpagebuflist(arg)
+vim.fn.tabpagenr(arg)
+vim.fn.tabpagewinnr(tabarg, arg)
+vim.fn.tagfiles()
+vim.fn.taglist(expr, filename)
+vim.fn.tan(expr)
+vim.fn.tanh(expr)
+vim.fn.tempname()
+vim.fn.termopen(cmd, opts)
+vim.fn.timer_info(id)
+vim.fn.timer_pause(timer, paused)
+vim.fn.timer_start(time, callback, options)
+vim.fn.timer_stop(timer)
+vim.fn.timer_stopall()
+vim.fn.tolower(expr)
+vim.fn.toupper(expr)
+vim.fn.tr(src, fromstr, tostr)
+vim.fn.trim(text, mask, dir)
+vim.fn.trunc(expr)
+vim.fn.type(expr)
+vim.fn.undofile(name)
+vim.fn.undotree(buf)
+vim.fn.uniq(list, func, dict)
+vim.fn.utf16idx(string, idx, countcc, charidx)
+vim.fn.values(dict)
+vim.fn.virtcol(expr, list, winid)
+vim.fn.virtcol2col(winid, lnum, col)
+vim.fn.visualmode(expr)
+vim.fn.wait(timeout, condition, interval)
+vim.fn.wildmenumode()
+vim.fn.win_execute(id, command, silent)
+vim.fn.win_findbuf(bufnr)
+vim.fn.win_getid(win, tab)
+vim.fn.win_gettype(nr)
+vim.fn.win_gotoid(expr)
+vim.fn.win_id2tabwin(expr)
+vim.fn.win_id2win(expr)
+vim.fn.win_move_separator(nr, offset)
+vim.fn.win_move_statusline(nr, offset)
+vim.fn.win_screenpos(nr)
+vim.fn.win_splitmove(nr, target, options)
+vim.fn.winbufnr(nr)
+vim.fn.wincol()
+vim.fn.windowsversion()
+vim.fn.winheight(nr)
+vim.fn.winlayout(tabnr)
+vim.fn.winline()
+vim.fn.winnr(arg)
+vim.fn.winrestcmd()
+vim.fn.winrestview(dict)
+vim.fn.winsaveview()
+vim.fn.winwidth(nr)
+vim.fn.wordcount()
+vim.fn.writefile(object, fname, flags)
+vim.fn.xor(expr, expr1)
+```
diff --git a/README.md b/README.md
index bda81c8..98181c5 100644
--- a/README.md
+++ b/README.md
@@ -143,7 +143,8 @@ See search for more details
| --- | --- | --- |
| `setup` | `fun(opts?: _99.Options): nil` | - |
| `search` | `fun(opts: _99.ops.SearchOpts): _99.TraceID` | - |
-| `vibe_search` | `fun(opts?: _99.ops.Opts): _99.TraceID \| nil` | - |
+| `vibe` | `fun(opts?: _99.ops.Opts): _99.TraceID \| nil` | - |
+| `open` | `fun(): nil` | - |
| `visual` | `fun(opts: _99.ops.Opts): _99.TraceID` | - |
| `view_logs` | `fun(): nil` | - |
| `stop_all_requests` | `fun(): nil` | - |
@@ -161,8 +162,14 @@ way you want it to.
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.
-#### vibe_search
-Select a previous search, edit it, then pass it to vibe.
+#### vibe
+No description.
+
+#### open
+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.
#### visual
takes your current selection and sends that along with the prompt provided and replaces
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,