Skip to content

Commit

Permalink
feat: chat macro support
Browse files Browse the repository at this point in the history
- starting with @context_file (issue: #206)
  • Loading branch information
Robitx committed Sep 19, 2024
1 parent 449052b commit bcc93df
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 2 deletions.
28 changes: 28 additions & 0 deletions after/ftplugin/gpchat.lua
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,31 @@ vim.api.nvim_create_autocmd({ "User" }, {
M.helpers.save_buffer(buf, "gpchat User GpRefresh autocmd")
end,
})

local has_cmp, cmp = pcall(require, "cmp")
if not has_cmp then
M.logger.debug("gpchat: cmp not found, skipping cmp setup")
return
end

M.macro.build_cmp_source("gpchat", {
require("gp.macros.context_file"),
})

local sources = {
{ name = "gpchat" },
}
for _, source in pairs(cmp.get_config().sources) do
if source.name ~= "gpchat" and source.name ~= "buffer" then
table.insert(sources, source)
end
end

M.logger.debug("gpchat: cmp sources " .. vim.inspect(sources))

cmp.setup.buffer({
-- keyword_length = 1,
max_item_count = 100,
completion = { autocomplete = { require("cmp.types").cmp.TriggerEvent.TextChanged } },
sources = sources,
})
11 changes: 9 additions & 2 deletions lua/gp/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,9 @@ M.setup = function(opts)
require("gp.macros.context_file"),
})

M.logger.debug("command_parser done")
M.chat_parser = M.macro.build_parser({
require("gp.macros.context_file"),
})

local completions = {
ChatNew = { "popup", "split", "vsplit", "tabnew" },
Expand Down Expand Up @@ -1035,8 +1037,13 @@ M.chat_respond = function(params)
table.insert(messages, 1, { role = "system", content = content })
end

-- strip whitespace from ends of content
local state = M.buffer_state.get(buf)
for _, message in ipairs(messages) do
local response = M.chat_parser(message.content, {}, state)
if response then
message.content = M.render.template(response.template, response.artifacts)
state = response.state
end
message.content = message.content:gsub("^%s*(.-)%s*$", "%1")
end

Expand Down
91 changes: 91 additions & 0 deletions lua/gp/macro.lua
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,95 @@ M.build_completion = function(macros, raw)
return completion
end

local registered_cmp_sources = {}
M.build_cmp_source = function(name, macros)
if registered_cmp_sources[name] then
logger.debug("cmp source " .. name .. " already registered")
return nil
end
local source = {}

source.new = function()
return setmetatable({}, { __index = source })
end

source.get_trigger_characters = function()
return { "@", " " }
end

local completion = M.build_completion(macros, true)

source.complete = function(self, params, callback)
local ctx = params.context
local suggestions, triggered = completion(ctx.cursor_before_line:match("%S*$"), ctx.cursor_line, ctx.cursor.col)

if not triggered and not ctx.cursor_before_line:match("%s*@%S*$") then
suggestions = {}
end

logger.debug("macro completion suggestions: " .. vim.inspect(suggestions))

local items = {}
for _, suggestion in ipairs(suggestions) do
table.insert(items, {
label = suggestion,
kind = require("cmp").lsp.CompletionItemKind.Keyword,
documentation = name,
})
end
logger.debug("macro cmp complete output: " .. vim.inspect(items))

callback(items)
end

local has_cmp, cmp = pcall(require, "cmp")
if not has_cmp then
logger.warning("cmp not found, skipping cmp source registration")
return source
end

cmp.register_source(name, source)
registered_cmp_sources[name] = true

if true then
return source
end

cmp.event:on("complete_done", function(event)
if not event or not event.entry or event.entry.source.name ~= name then
return
end
local ctx = event.entry.source.context
local suggestions, triggered = completion(ctx.cursor_before_line:match("%S*$"), ctx.cursor_line, ctx.cursor.col)
logger.debug(
"macro cmp complete_done suggestions: " .. vim.inspect(suggestions) .. " triggered: " .. vim.inspect(triggered)
)
if not suggestions or not triggered then
return
end

vim.schedule(function()
-- insert a space if not already present at the cursor
local cursor_col = vim.api.nvim_win_get_cursor(0)[2]
local line = vim.api.nvim_get_current_line()
logger.debug(
"macro cmp complete_done cursor_col: "
.. cursor_col
.. " line: "
.. line
.. " char: "
.. line:sub(cursor_col, cursor_col)
)
if line:sub(cursor_col, cursor_col) ~= " " then
vim.api.nvim_put({ " " }, "c", false, true)
end
vim.schedule(function()
cmp.complete(suggestions)
end)
end)
end)

return source
end

return M

0 comments on commit bcc93df

Please sign in to comment.