2024.04.08
ChatGPT Inside Neovim
こんにちは、次世代システム研究室のN.M.です。
TLDR
Neovim is a fork of Vim. It uses Lua for configuration, although it still supports Vim Script. There are many plugins and even many pre-configured distributions available.
ChatGPT.nvim is a Neovim plugin that allows you to interact with the OpenAI Chat GPT API from within Neovim. It provides a simple chat interface that allows you to prompt, ask questions, and perform other tasks.
The plugin is designed to be extensible, so you can add custom prompts and responses.
If you are interested only in code generation, I would recommend looking at Aider, which is a CLI tool that is specifically designed for code generation, and handling integration with git. See my previous blog on Aider.
If you are looking for a general, seamless UX with the OpenAI API, from inside your Neovim editor, ChatGPT.nvim is a good option.
The plugin: https://github.com/jackMort/ChatGPT.nvim
Introduction
The plugin is designed to be simple to use and easy to install. It is also extensible, you can add custom prompts.
In this blog, we will cover how to use it, how to upgrade the model, how to write tests, as well as looking at a failing of the plugin.
We will also look at how to extend the plugin with custom prompts.
Help
As with most plugins, ChatGPT.nvim comes with a help file that explains how to use the plugin. You can view the help by running
:h chat-gpt-nvim
in Neovim.While using the plugin, Typing
ctrl-h
, will show a list of ChatGPT.nvim key shortcut commands, useable from inside ChatGPT.nvim.Upgrading the model
By default, the plugin uses the gpt-3.5 Turbo model.
The plugin allows you to upgrade the model as shown below:
return { "jackMort/ChatGPT.nvim", enabled = true, event = "VeryLazy", config = function() require("chatgpt").setup({ api_key_cmd = "pass show work/openai_api_key", openai_params = { model = "gpt-4", }, openai_edit_params = { model = "gpt-4", }, predefined_chat_gpt_prompts = "file:///" .. vim.loop.os_homedir() .. "/awesome-chatgpt-prompts/prompts.csv", }) end, dependencies = { "MunifTanjim/nui.nvim", "nvim-lua/plenary.nvim", "folke/trouble.nvim", "nvim-telescope/telescope.nvim", }, lazy = false, }
Note that the above configuration uses the Lazy Plugin Manager, which is a plugin manager for Neovim that allows you to load plugins on demand. If you are using a different plugin manager, you will need to adjust the configuration accordingly.
After changing the configuration, reload the plugin, with the following vim command (if you’re not using the Lazy plugin manager, substitute your plugin manager’s specific reloading method):
:Lazy reload ChatGPT.nvim
The ChatGPT command
The
:ChatGPT
command is used to interact with the OpenAI API. Use this command to ask questions, as you would normally do in the ChatGPT web interface.Editing Code
- I used the
:ChatGPTEditWithInstructions
command to edit code. - The prompt:
The screen-shot below shows the diff between the original and proposed code, the model used, and the available ChatGPT.nvim commands:
- the diff is obtained by typing
ctl-d
- the model used is obtained by typing
ctl-o
- the available ChatGPT.nvim pop-up commands are obtained by typing
ctl-h
- Type
ctl-y
to accept the suggestion, which causes the ChatGPT.nvim popup to close, and the original buffer to be updated with the new code
From the command line, the new code builds, and runs, showing the ordered insert was successful:
➜ cargo run Compiling linked-list v0.1.0 (/Users/me/project/linked-list-chat-gpt-nvim) Finished dev [unoptimized + debuginfo] target(s) in 0.08s Running `target/debug/linked-list` ll = LinkedList(Some((1, LinkedList(Some((2, LinkedList(Some((3, LinkedList(Some((4, LinkedList(None)))))))))))))
Add a method to reverse the linked list
The prompt:
A screenshot showing the diff between the original and proposed code
ctl-d
- It builds, and runs, but shows the `reverse` logic is incorrect:
❯ cargo run Compiling linked-list v0.1.0 (/Users/me/project/linked-list-chat-gpt-nvim) Finished dev [unoptimized + debuginfo] target(s) in 0.33s Running `target/debug/linked-list` ll = LinkedList(Some((1, LinkedList(None))))
Aider was able to successfully add the reverse method, also using the OpenAI 4.0 model.
I suspect that the difference may be due to higher quality prompting used in Aider.
Writing tests
Tests can be created with the
:ChatGPTRun add_tests
command.#[derive(Debug, PartialEq)] pub struct LinkedList<T>(Option<(T, Box<LinkedList<T>>)>); impl<T: PartialOrd> LinkedList<T> { pub fn new() -> Self { LinkedList(None) } pub fn push_front(&mut self, data: T) { let t = self.0.take(); self.0 = Some((data, Box::new(LinkedList(t)))); } pub fn push_back(&mut self, data: T) { match self.0 { Some((_, ref mut child)) => child.push_back(data), None => self.push_front(data), } } pub fn ordered_insert(&mut self, data: T) { match self.0 { Some((ref mut head, ref mut child)) if *head < data => child.ordered_insert(data), _ => self.push_front(data), } } pub fn reverse(&mut self) { let mut prev = LinkedList(None); while let Some((data, mut next)) = self.0.take() { next.0 = prev.0.take(); prev = LinkedList(Some((data, next))); } *self = prev; } } fn main() { let mut ll = LinkedList::new(); ll.push_front(1); ll.push_back(2); ll.push_back(4); ll.ordered_insert(3); ll.reverse(); println!("ll = {:?}", ll); } #[cfg(test)] mod tests { use super::*; #[test] fn test_push_front() { let mut ll = LinkedList::new(); ll.push_front(1); assert_eq!(ll, LinkedList(Some((1, Box::new(LinkedList(None)))))); } #[test] fn test_push_back() { let mut ll = LinkedList::new(); ll.push_back(1); assert_eq!(ll, LinkedList(Some((1, Box::new(LinkedList(None)))))); } #[test] fn test_ordered_insert() { let mut ll = LinkedList::new(); ll.push_front(1); ll.push_back(3); ll.ordered_insert(2); assert_eq!(ll, LinkedList(Some((1, Box::new(LinkedList(Some((2, Box::new(LinkedList(Some((3, Box::new(LinkedList(None)))))))))))))); } #[test] fn test_reverse() { let mut ll = LinkedList::new(); ll.push_front(1); ll.push_back(2); ll.push_back(3); ll.reverse(); assert_eq!(ll, LinkedList(Some((3, Box::new(LinkedList(Some((2, Box::new(LinkedList(Some((1, Box::new(LinkedList(None)))))))))))))) } }
These tests work as expected and correctly expose the bug in the
reverse
method.Handling Errors
My hope was, that, since there was already a test for the reverse method, the plugin would be able to generate a fix for the method and pass the test.
The plugin provides a
ChatGPTRun fix_code
command, which I tried using to fix the reverse method. Unfortunately, the plugin was unable to provide a fix for the reverse method.I could probably fix the reverse method by providing a more detailed prompt, using the
ChatGPT
command, but I did not try this, because this would be functionally the same as just using the ChatGPT web interface, and I don’t need to prove that GPT 4.0 can solve this, because I have already confirmed it can, in previous tests.Awesome Chat GPT Prompts
The ChatGPT.nvim plugin uses Awesome Chat GPT Prompts to provide persona description prompts.
The prompts are stored in a CSV file, and loaded into the plugin using the
predefined_chat_gpt_prompts
configuration option in the plugin configuration.I customized my prompts by cloning the repository and editing the CSV file. I then updated the
predefined_chat_gpt_prompts
configuration option to point to the file on my local machine.predefined_chat_gpt_prompts = "file:///" .. vim.loop.os_homedir() .. "/awesome-chatgpt-prompts/prompts.csv",
This allowed me to use my custom prompts.
ChatGPT.nvim uses these prompts in the
:ChatGPTActAs
command, which allows you to choose a persona that the AI should imitate when generating responses.If you wish to customize the way ChatGPT.nvim generates responses, you can edit the CSV file changing existing prompts or adding your own.
Summary
- While providing a slightly better UX than Aider due to integration with Neovim, the ChatGPT.nvim plugin was unable to provide a fix for the reverse method, which Aider was able to do. This inferior code generation ability, may be due to differences in the prompts used by the two tools, since I tested both using the same OpenAI 4.0 model.
- While behind Aider in code generation, ChatGPT.nvim provides broader integration with the OpenAI API, allowing for a ChatGPT-like experience within Neovim.
- Using the
ChatGPT
command, along withChatGPTActAs
and many others, makes it easy and fun to interact with the OpenAI API from within Neovim. - Not having to context switch between browser and editor is a plus point, possibly allowing for more focus on development.
Perhaps ChatGPT.nvim can replace the ChatGPT web interface, during day-to-day code editing. This should allow, for easier switching between ChatGPT, code, and notes, for Neovim users.
ChatGPT code generation may be useful for simple tasks, falling back to Aider or other AI tools for more complex code generation tasks.
Other Recommended AI Tools
References
次世代システム研究室では、グループ全体のインテグレーションを支援してくれるアーキテクトを募集しています。インフラ設計、構築経験者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ募集職種一覧からご応募をお願いします。
グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。
Follow @GMO_RD