Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed 2 issues and added 5 features #468

Merged
merged 7 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lua/chatgpt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ M.selectAwesomePrompt = function()
module.open_chat_with_awesome_prompt()
end

M.open_chat_with = function(opts)
module.open_chat_with(opts)
end

M.edit_with_instructions = function()
module.edit_with_instructions()
end
Expand Down
7 changes: 7 additions & 0 deletions lua/chatgpt/code_edits.lua
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,13 @@ M.edit_with_instructions = function(output_lines, bufnr, selection, ...)
end
end

-- close_n
if Config.options.edit_with_instructions.keymaps.close_n then
instructions_input:map("n", Config.options.edit_with_instructions.keymaps.close_n, function()
vim.cmd("q")
end, { noremap = true })
end

-- toggle settings
for _, popup in ipairs({ instructions_input, settings_panel, help_panel }) do
for _, mode in ipairs({ "n", "i" }) do
Expand Down
11 changes: 11 additions & 0 deletions lua/chatgpt/common/preview_window.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ function PreviewWindow:mount()
self:unmount()
end)
end

-- close_n
keys = Config.options.chat.keymaps.close_n or {}
if type(keys) ~= "table" then
keys = { keys }
end
for _, key in ipairs(keys) do
self:map("n", key, function()
self:unmount()
end)
end
end

return PreviewWindow
4 changes: 4 additions & 0 deletions lua/chatgpt/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function M.defaults()
diff = false,
keymaps = {
close = "<C-c>",
close_n = "<Esc>",
accept = "<C-y>",
yank = "<C-u>",
toggle_diff = "<C-d>",
Expand All @@ -27,6 +28,7 @@ function M.defaults()
},
chat = {
welcome_message = WELCOME_MESSAGE,
default_system_message = "",
loading_text = "Loading, please wait ...",
question_sign = "", -- 🙂
answer_sign = "ﮧ", -- 🤖
Expand All @@ -49,6 +51,7 @@ function M.defaults()
},
keymaps = {
close = "<C-c>",
close_n = "<Esc>",
yank_last = "<C-y>",
yank_last_code = "<C-k>",
scroll_up = "<C-u>",
Expand Down Expand Up @@ -175,6 +178,7 @@ function M.defaults()
n = 1,
},
use_openai_functions_for_edits = false,
ignore_default_actions_path = false,
actions_paths = {},
show_quickfixes_cmd = "Trouble quickfix",
predefined_chat_gpt_prompts = "https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv",
Expand Down
9 changes: 6 additions & 3 deletions lua/chatgpt/flows/actions/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ function M.read_actions()
local actions = {}
local paths = {}

-- add default actions
local default_actions_path = debug.getinfo(1, "S").source:sub(2):match("(.*/)") .. "actions.json"
table.insert(paths, default_actions_path)
if not Config.options.ignore_default_actions_path then
-- add default actions
local default_actions_path = debug.getinfo(1, "S").source:sub(2):match("(.*/)") .. "actions.json"
table.insert(paths, default_actions_path)
end

for i = 1, #Config.options.actions_paths do
paths[#paths + 1] = Config.options.actions_paths[i]
end
Expand Down
64 changes: 48 additions & 16 deletions lua/chatgpt/flows/chat/base.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ function Chat:init()
self.system_role_open = false

self.is_streaming_response = false
self.is_streaming_response_lock = false

self.prompt_lines = 1

Expand All @@ -71,16 +72,25 @@ function Chat:welcome()
self:set_cursor({ 1, 0 })
self:set_system_message(nil, true)

local system_message_absent = true
if #self.session.conversation > 0 then
for idx, item in ipairs(self.session.conversation) do
if item.type == SYSTEM then
system_message_absent = false
self:set_system_message(item.text, true)
else
self:_add(item.type, item.text, item.usage, idx)
end
end
end

if system_message_absent then
local default_system_message = Config.options.chat.default_system_message
if default_system_message and #default_system_message > 0 then
self:set_system_message(default_system_message, true)
end
end

if #self.session.conversation == 0 or (#self.session.conversation == 1 and self.system_message ~= nil) then
local lines = Utils.split_string_by_line(Config.options.chat.welcome_message)
self:set_lines(0, 0, false, lines)
Expand Down Expand Up @@ -211,6 +221,8 @@ end

function Chat:addAnswerPartial(text, state)
if state == "ERROR" then
-- unlock first and then wirte answer
self.is_streaming_response_lock = false
return self:addAnswer(text, {})
end

Expand All @@ -221,6 +233,8 @@ function Chat:addAnswerPartial(text, state)
end

if state == "END" then
-- unlock first and then wirte answer
self.is_streaming_response_lock = false
local usage = {}
local idx = self.session:add_item({
type = ANSWER,
Expand Down Expand Up @@ -248,10 +262,8 @@ function Chat:addAnswerPartial(text, state)
})
self.selectedIndex = self.selectedIndex + 1

if self.chat_window.bufnr ~= nil then
vim.api.nvim_buf_set_lines(self.chat_window.bufnr, -1, -1, false, { "", "" })
Signs.set_for_lines(self.chat_window.bufnr, start_line, end_line, "chat")
end
-- redraw make sure signs correct
self:redraw()

self.is_streaming_response = false
end
Expand All @@ -261,12 +273,15 @@ function Chat:addAnswerPartial(text, state)

self:stopSpinner()
self:set_lines(-2, -1, false, { "" })
if self.chat_input.bufnr ~= nil then
vim.api.nvim_buf_set_option(self.chat_window.bufnr, "modifiable", true)
end

-- lock chat window buf
self.is_streaming_response_lock = true
end

if state == "START" or state == "CONTINUE" then
-- avoid unlocking caused by multi addAnswerPartial parallel
self.is_streaming_response_lock = true

local lines = vim.split(text, "\n", {})
local length = #lines
local buffer = self.chat_window.bufnr
Expand All @@ -278,12 +293,17 @@ function Chat:addAnswerPartial(text, state)

for i, line in ipairs(lines) do
local currentLine = vim.api.nvim_buf_get_lines(buffer, -2, -1, false)[1]
vim.api.nvim_buf_set_lines(buffer, -2, -1, false, { currentLine .. line })
Utils.modify_buf(self.chat_window.bufnr, function(bufnr)
vim.api.nvim_buf_set_lines(bufnr, -2, -1, false, { currentLine .. line })
end)

local last_line_num = vim.api.nvim_buf_line_count(buffer)
Signs.set_for_lines(self.chat_window.bufnr, start_line, last_line_num - 1, "chat")
-- busy call Signs.set_for_lines will cause neovim to freeze, and it will be redraw after completion
-- Signs.set_for_lines(self.chat_window.bufnr, start_line, last_line_num - 1, "chat")
if i == length and i > 1 then
vim.api.nvim_buf_set_lines(buffer, -1, -1, false, { "" })
Utils.modify_buf(self.chat_window.bufnr, function(bufnr)
vim.api.nvim_buf_set_lines(bufnr, -1, -1, false, { "" })
end)
end
if self:is_buf_visiable() then
vim.api.nvim_win_set_cursor(win, { last_line_num, 0 })
Expand Down Expand Up @@ -557,10 +577,10 @@ function Chat:is_buf_visiable()
end

function Chat:set_lines(start_idx, end_idx, strict_indexing, lines)
if self:is_buf_exists() then
vim.api.nvim_buf_set_option(self.chat_window.bufnr, "modifiable", true)
vim.api.nvim_buf_set_lines(self.chat_window.bufnr, start_idx, end_idx, strict_indexing, lines)
vim.api.nvim_buf_set_option(self.chat_window.bufnr, "modifiable", false)
if not self.is_streaming_response_lock then
Utils.modify_buf(self.chat_window.bufnr, function(bufnr)
vim.api.nvim_buf_set_lines(bufnr, start_idx, end_idx, strict_indexing, lines)
end)
end
end

Expand Down Expand Up @@ -752,6 +772,7 @@ function Chat:open()
self:set_session(session)
end)
self.chat_window = Popup(Config.options.popup_window)
vim.api.nvim_buf_set_option(self.chat_window.bufnr, "modifiable", false)
self.system_role_panel = SystemWindow({
on_change = function(text)
self:set_system_message(text)
Expand Down Expand Up @@ -779,7 +800,9 @@ function Chat:open()
end),
on_submit = function(value)
-- clear input
vim.api.nvim_buf_set_lines(self.chat_input.bufnr, 0, -1, false, { "" })
Utils.modify_buf(self.chat_input.bufnr, function(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { "" })
end)

if self:isBusy() then
vim.notify("I'm busy, please wait a moment...", vim.log.levels.WARN)
Expand Down Expand Up @@ -851,6 +874,13 @@ function Chat:open()
end
end)

-- close_n
if Config.options.chat.keymaps.close_n then
self:map(Config.options.chat.keymaps.close_n, function()
self:hide()
end, nil, { "n" })
end

local function inTable(tbl, item)
for key, value in pairs(tbl) do
if value == item then
Expand Down Expand Up @@ -990,7 +1020,9 @@ function Chat:open()
local lines = vim.api.nvim_buf_get_lines(self.chat_input.bufnr, 0, -1, false)
local text = table.concat(lines, "\n")
if #text > 0 then
vim.api.nvim_buf_set_lines(self.chat_input.bufnr, 0, -1, false, { "" })
Utils.modify_buf(self.chat_input.bufnr, function(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { "" })
end)
self:add(self.role == ROLE_USER and QUESTION or ANSWER, text)
if self.role ~= ROLE_USER then
self.role = ROLE_USER
Expand Down
46 changes: 46 additions & 0 deletions lua/chatgpt/flows/chat/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ local Session = require("chatgpt.flows.chat.session")
local Prompts = require("chatgpt.prompts")
local Chat = require("chatgpt.flows.chat.base")

local ROLE_TO_CODE = {
["user"] = 1,
["assistant"] = 2,
["system"] = 3,
}

local M = {
chat = nil,
}
Expand Down Expand Up @@ -32,4 +38,44 @@ M.open_with_awesome_prompt = function()
})
end

-- @param opts.new_session default false
-- @param opts.messages optinal (effect when new session), prompt content list, like [{"role": "system", "content": "You are a helpful assistant."},{"role": "user", "content": "Hello!"}]
-- @param opts.open_system_panel "open" or "active"
M.open_with = function(opts)
local new_session = false
if M.chat ~= nil and M.chat.active then
M.chat:toggle()
else
M.chat = Chat:new()
M.chat:open()
new_session = true
end
if opts and M.chat.layout.winid ~= nil then
if opts.new_session then
M.chat:new_session()
end

-- 仅在new_session时才支持prompt设置
if new_session or opts.new_session then
if opts.messages then
for _, item in pairs(opts.messages) do
if item and item.role == "system" then
M.chat:set_system_message(item.content)
elseif item and item.role and ROLE_TO_CODE[item.role] then
M.chat:add(ROLE_TO_CODE[item.role], item.content)
end
end
end
end

if opts.open_system_panel == "open" or opts.open_system_panel == "active" then
M.chat.system_role_open = true
M.chat:redraw()
if opts.open_system_panel == "active" then
M.chat:set_active_panel(M.chat.system_role_panel)
end
end
end
end

return M
1 change: 1 addition & 0 deletions lua/chatgpt/module.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ local CodeCompletions = require("chatgpt.flows.code_completions")

M.open_chat = Chat.open
M.open_chat_with_awesome_prompt = Chat.open_with_awesome_prompt
M.open_chat_with = Chat.open_with
M.edit_with_instructions = Edits.edit_with_instructions
M.run_action = Actions.run_action
M.complete_code = CodeCompletions.complete
Expand Down
13 changes: 13 additions & 0 deletions lua/chatgpt/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,17 @@ function M.match_indentation(input, output)
return table.concat(lines)
end

M.modify_buf = function(bufnr, modify_func)
if bufnr and vim.fn.bufexists(bufnr) == 1 then
local modifiable = vim.api.nvim_buf_get_option(bufnr, "modifiable")
if not modifiable then
vim.api.nvim_buf_set_option(bufnr, "modifiable", true)
end
modify_func(bufnr)
if not modifiable then
vim.api.nvim_buf_set_option(bufnr, "modifiable", false)
end
end
end

return M
Loading