Skip to content

Commit aa0dd8c

Browse files
committed
feat: GpChatHelp to toggle help comments
1 parent 140d514 commit aa0dd8c

File tree

5 files changed

+120
-11
lines changed

5 files changed

+120
-11
lines changed

after/ftplugin/gpchat.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ local commands = {
3737
shortcut = M.config.chat_shortcut_new.shortcut,
3838
comment = "GPT prompt Chat New",
3939
},
40+
{
41+
command = "ChatHelp",
42+
modes = M.config.chat_shortcut_help.modes,
43+
shortcut = M.config.chat_shortcut_help.shortcut,
44+
comment = "GPT prompt Chat Help",
45+
},
4046
}
4147
for _, rc in ipairs(commands) do
4248
local cmd = M.config.cmd_prefix .. rc.command .. "<cr>"
@@ -124,6 +130,8 @@ vim.api.nvim_create_autocmd({ "User" }, {
124130

125131
M.logger.debug("gpchat: refreshing buffer " .. buf .. " " .. vim.json.encode(event))
126132

133+
M.chat_help(buf)
134+
127135
vim.api.nvim_buf_clear_namespace(buf, ns_id, 0, -1)
128136

129137
vim.api.nvim_buf_set_extmark(buf, ns_id, 0, 0, {

lua/gp/config.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ local config = {
310310
chat_shortcut_delete = { modes = { "n", "i", "v", "x" }, shortcut = "<C-g>d" },
311311
chat_shortcut_stop = { modes = { "n", "i", "v", "x" }, shortcut = "<C-g>s" },
312312
chat_shortcut_new = { modes = { "n", "i", "v", "x" }, shortcut = "<C-g>c" },
313+
chat_shortcut_help = { modes = { "n", "i", "v", "x" }, shortcut = "<C-g>h" },
313314
-- default search term when using :GpChatFinder
314315
chat_finder_pattern = "topic ",
315316
-- if true, finished ChatResponder won't move the cursor to the end of the buffer

lua/gp/defaults.lua

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,19 @@ M.code_system_prompt = "You are an AI working as a code editor.\n\n"
1313
.. "Please AVOID COMMENTARY OUTSIDE OF THE SNIPPET RESPONSE.\n"
1414
.. "START AND END YOUR ANSWER WITH:\n\n```"
1515

16-
M.chat_template = [[
17-
---
18-
topic: ?
19-
{{optional_headers}}
16+
M.chat_help = [[
2017
# Write your queries after {{user_prefix}}. Use `{{respond_shortcut}}` or :{{cmd_prefix}}ChatRespond to generate a response.
2118
# Response generation can be terminated by using `{{stop_shortcut}}` or :{{cmd_prefix}}ChatStop command.
2219
# Chats are saved automatically. To delete this chat, use `{{delete_shortcut}}` or :{{cmd_prefix}}ChatDelete.
2320
# Be cautious of very long chats. Start a fresh chat by using `{{new_shortcut}}` or :{{cmd_prefix}}ChatNew.
21+
# See available macros by typing @ in the chat. Toggle this help by using `{{help_shortcut}}` or :{{cmd_prefix}}ChatHelp.]]
22+
23+
M.chat_template = [[
24+
---
25+
topic: ?
26+
{{optional_headers}}
27+
]] .. M.chat_help .. [[
28+
2429
---
2530
2631
{{user_prefix}}

lua/gp/helper.lua

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ _H.autocmd = function(events, buffers, callback, gid)
6363
end
6464
end
6565

66+
---@param callback function # callback to schedule
67+
---@param depth number # depth of nested scheduling
68+
_H.schedule = function(callback, depth)
69+
logger.debug("scheduling callback with depth: " .. depth)
70+
if depth <= 0 then
71+
return callback()
72+
end
73+
return vim.schedule(function()
74+
_H.schedule(callback, depth - 1)
75+
end)
76+
end
77+
6678
---@param file_name string # name of the file for which to delete buffers
6779
_H.delete_buffer = function(file_name)
6880
-- iterate over buffer list and close all buffers with the same name
@@ -294,24 +306,27 @@ _H.create_user_command = function(cmd_name, cmd_func, completion, desc)
294306
end
295307

296308
---@param lines string[] # array of lines
297-
---@return table<string, any>, table<string, number>, number | nil # headers, indices, last header line
309+
---@return table<string, any>, table<string, number>, number | nil, table<string, number> # headers, indices, last header line, comments
298310
_H.parse_headers = function(lines)
299311
local headers = {}
300312
local indices = {}
313+
local comments = {}
301314

302315
for i, line in ipairs(lines) do
303316
if i > 1 and line:sub(1, 3) == "---" then
304-
return headers, indices, i - 1
317+
return headers, indices, i - 1, comments
305318
end
306319

307320
local key, value = line:match("^[-#%s]*(%w+):%s*(.*)%s*")
308321
if key ~= nil then
309322
headers[key] = value
310323
indices[key] = i - 1
324+
elseif line:match("^# ") then
325+
comments[line] = i - 1
311326
end
312327
end
313328

314-
return headers, indices, nil
329+
return headers, indices, nil, comments
315330
end
316331

317332
---@param buf number # buffer number

lua/gp/init.lua

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,17 +242,34 @@ M.setup = function(opts)
242242
if M.hooks[cmd] == nil then
243243
M.helpers.create_user_command(M.config.cmd_prefix .. cmd, function(params)
244244
M.logger.debug("running command: " .. cmd)
245-
M.refresh_state()
245+
if cmd ~= "ChatHelp" then
246+
M.refresh_state()
247+
end
246248
M.cmd[cmd](params)
247249
end, completions[cmd])
248250
end
249251
end
250252

253+
vim.filetype.add({
254+
extension = {
255+
md = function(path, buf)
256+
M.logger.debug("filetype markdown: " .. path .. " buf: " .. buf)
257+
if not M.not_chat(buf, path) then
258+
return "markdown.gpchat"
259+
end
260+
261+
if M.helpers.ends_with(path, ".gp.md") then
262+
return "markdown.gpmd"
263+
end
264+
return "markdown"
265+
end,
266+
},
267+
})
268+
251269
vim.api.nvim_create_autocmd("BufEnter", {
252270
pattern = "*.md",
253271
callback = function(ev)
254-
vim.defer_fn(function()
255-
M.logger.debug("Markdown BufEnter: " .. ev.file)
272+
M.helpers.schedule(function()
256273
local path = ev.file
257274
local buf = ev.buf
258275
local current_ft = vim.bo[buf].filetype
@@ -262,7 +279,7 @@ M.setup = function(opts)
262279
vim.bo[buf].filetype = "markdown.gpmd"
263280
end
264281
vim.cmd("doautocmd User GpRefresh")
265-
end, 100)
282+
end, 3)
266283
end,
267284
})
268285

@@ -313,6 +330,10 @@ M.refresh_state = function(update)
313330
M._state.last_chat = nil
314331
end
315332

333+
if M._state.show_chat_help == nil then
334+
M._state.show_chat_help = true
335+
end
336+
316337
for k, _ in pairs(M._state) do
317338
if M._state[k] ~= old_state[k] or M._state[k] ~= disk_state[k] then
318339
M.logger.debug(
@@ -699,6 +720,7 @@ M.new_chat = function(params, toggle, system_prompt, agent)
699720
["{{stop_shortcut}}"] = M.config.chat_shortcut_stop.shortcut,
700721
["{{delete_shortcut}}"] = M.config.chat_shortcut_delete.shortcut,
701722
["{{new_shortcut}}"] = M.config.chat_shortcut_new.shortcut,
723+
["{{help_shortcut}}"] = M.config.chat_shortcut_help.shortcut,
702724
})
703725

704726
-- escape underscores (for markdown)
@@ -1041,6 +1063,64 @@ M.chat_respond = function(params)
10411063
)
10421064
end
10431065

1066+
---@param buf number
1067+
M.chat_help = function(buf)
1068+
local file_name = vim.api.nvim_buf_get_name(buf)
1069+
M.logger.debug("ChatHelp: buffer: " .. buf .. " file: " .. file_name)
1070+
local reason = M.not_chat(buf, file_name)
1071+
if reason then
1072+
M.logger.debug("File " .. vim.inspect(file_name) .. " does not look like a chat file: " .. vim.inspect(reason))
1073+
return
1074+
end
1075+
1076+
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
1077+
local _, _, header_end, comments = M.helpers.parse_headers(lines)
1078+
if header_end == nil then
1079+
M.logger.error("Error while parsing headers: --- not found. Check your chat template.")
1080+
return
1081+
end
1082+
1083+
local help_template = M.render.template(M.defaults.chat_help, {
1084+
["{{user_prefix}}"] = M.config.chat_user_prefix,
1085+
["{{respond_shortcut}}"] = M.config.chat_shortcut_respond.shortcut,
1086+
["{{cmd_prefix}}"] = M.config.cmd_prefix,
1087+
["{{stop_shortcut}}"] = M.config.chat_shortcut_stop.shortcut,
1088+
["{{delete_shortcut}}"] = M.config.chat_shortcut_delete.shortcut,
1089+
["{{new_shortcut}}"] = M.config.chat_shortcut_new.shortcut,
1090+
["{{help_shortcut}}"] = M.config.chat_shortcut_help.shortcut,
1091+
})
1092+
1093+
local help_lines = vim.split(help_template, "\n")
1094+
local help_map = {}
1095+
for _, line in ipairs(help_lines) do
1096+
help_map[line] = true
1097+
end
1098+
1099+
local insert_help = true
1100+
local drop_lines = {}
1101+
for comment, index in pairs(comments) do
1102+
if help_map[comment] then
1103+
insert_help = false
1104+
table.insert(drop_lines, index)
1105+
end
1106+
end
1107+
1108+
if M._state.show_chat_help and insert_help then
1109+
vim.api.nvim_buf_set_lines(buf, header_end, header_end, false, help_lines)
1110+
elseif not M._state.show_chat_help and not insert_help then
1111+
table.sort(drop_lines, function(a, b)
1112+
return a > b
1113+
end)
1114+
for _, index in ipairs(drop_lines) do
1115+
vim.api.nvim_buf_set_lines(buf, index, index + 1, false, {})
1116+
end
1117+
end
1118+
end
1119+
1120+
M.cmd.ChatHelp = function()
1121+
M.refresh_state({ show_chat_help = not M._state.show_chat_help })
1122+
end
1123+
10441124
M.cmd.ChatRespond = function(params)
10451125
if params.args == "" and vim.v.count == 0 then
10461126
M.chat_respond(params)

0 commit comments

Comments
 (0)