🤏SimpleGPT is a Vim plugin designed to provide a simple (high transparency based on Jinja) yet flexible way (context-aware based on buffer, visual selection, LSP info, etc.) to customize your LLM/ChatGPT prompts for your tasks (finishing tasks by replacing with diff comparison, appending, etc.).
🤏SimpleGPT's efforts can be categorized into the following parts:
This allows you to easily build a LLM-based toolbox with 🤏SimpleGPT.
We provide a tools gallery for basic usage, which also serves as examples for further customization.
Tool | Config | Demo |
---|---|---|
Grammar fixing | conf.lua | |
Text Rewriting | conf.lua | |
Code completing | conf.lua | Demo |
Code Explanation | conf.lua | |
Bug Fixing | conf.lua | |
Translation with great formatting | conf.lua | Demo |
Dictionary with customized explanation | conf.lua | Demo |
Reading | My Config |
More tools are coming soon.
⚠️Please follow the installation guide of ChatGPT.nvim to make sure your ChatGPT works.
You can use :ChatGPT
to start a chat and verify if it is working.
-- Lazy.nvim
{
"you-n-g/simplegpt.nvim",
dependencies = {
{
"jackMort/ChatGPT.nvim", -- You should configure your ChatGPT make sure it works.
event = "VeryLazy",
config = true,
dependencies = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim",
"folke/trouble.nvim",
"nvim-telescope/telescope.nvim",
},
},
"you-n-g/jinja-engine.nvim",
"ibhagwan/fzf-lua",
},
config = true,
},
-- or packer.nvim
use({
"you-n-g/simplegpt.nvim",
config = function()
require("simplegpt").setup()
end,
requires = {
{
"jackMort/ChatGPT.nvim", -- You should configure your ChatGPT make sure it works.
event = "VimEnter",
config = function()
require("chatgpt").setup()
end,
requires = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim",
"folke/trouble.nvim",
"nvim-telescope/telescope.nvim",
},
},
"you-n-g/jinja-engine.nvim",
"ibhagwan/fzf-lua",
},
})
If you want to customize you <LocalLeader>
, please use following code:
vim.g.maplocalleader = "\\" -- change the localleader key to \
More detailed configuration are listed here. You can find my latest and preferred configuration here as an example.
I have attempted to summarize the key concepts and manual in one image.
The question is constructed by rendering a template. The 't' register serves as the template, encompassing:
{{content}}
, {{filetype}}
, and {{visual}}
.{{a}}
, {{b}}
, and {{c}}
.Here is a gif demo that quickly showcases the customization process.
You can specify a custom template path for loading and dumping files by setting the custom_template_path
option in your configuration. If the specified path does not exist, it will be created automatically.
Example configuration:
require("simplegpt").setup({
custom_template_path = "~/my_custom_templates/"
})
When you set a custom_template_path:
Create a Template File: Navigate to your custom template path and create a .json
file.
Define Template Structure: Add your template with placeholders:
{
"t": "I am working on a {{filetype}} file. The content is: {{content}}. Selected lines: {{visual}}. Question: {{q}}."
}
Save: Save the file in custom_template_path
.
Set the 't' Register: In Vim, set the 't' register:
" setting it with command
:let @t = "I am working on a {{filetype}} file. The content is: {{content}}. Selected lines: {{visual}}. Question: {{q}}."
" or use `"ty` to copy the content to the 't' register
Dump the Register: Use the shortcut to dump the 't' register:
:<LocalLeader>gD
You can register custom shortcuts to use templates from the custom template path. Here is an example of how to configure custom shortcuts:
require("simplegpt").setup({
custom_template_path = "~/my_custom_templates/",
keymaps = {
custom_shortcuts = {
["<LocalLeader>sQ"] = {
mode = { "n", "v" },
tpl = "my_custom_template.json",
target = "popup",
opts = { noremap = true, silent = true, desc = "Use custom template" },
},
},
},
})
In this example, pressing <LocalLeader>sQ
in normal or visual mode will load the my_custom_template.json
from the custom template path and send it to the popup target.
The primary concepts that govern the functionality of this plugin are:
Register-based, template-driven question construction: This approach allows for the dynamic creation of questions by leveraging the power of Vim registers. The registers serve as placeholders within the template, which are then replaced with the appropriate content during the question construction process.
Dumping and loading of registers: This feature enables the preservation of register content across different sessions. It's important to note that temporary registers, denoted by {{p-}}
, are exempt from this process and their content is not saved to disk.
Response display targets: This refers to the destination where the response from ChatGPT is displayed. The plugin offers flexibility in choosing the target, allowing for a more tailored user experience.
To illustrate the core template rendering mechanism of SimpleGPT, consider the following example. We have a template in the 't' register:
"I am currently working on a {{filetype}} file. The content of the file is: {{content}}. I have selected the following lines: {{visual}}. My question is: {{q}}."
The register values are:
{{filetype}}
is 'markdown'{{content}}
is 'This is a sample markdown file.'{{visual}}
is 'This is a selected.'{{q}}
is 'How can I improve this line?'The constructed question becomes:
"I am currently working on a markdown file. The content of the file is: This is a sample markdown file. I have selected the following lines: This is a selected line. My question is: How can I improve this line?"
Registers are of two types:
{{content}}
, {{filetype}}
, {{visual}}
, and {{q}}
. They store special values used in the template process. The {{q}}
register allows for an editable question when rendering the whole content.Register | meaning |
---|---|
t | The register for the template. |
others | the variables to render the template |
You can use these variables in your jinja template.
key | meaning |
---|---|
content | Content around the cursor, limited by a configurable length |
full_content | Entire content of the current file |
filetype | Filetype of the current buffer |
visual | Lines selected in visual mode |
context | Context around the cursor, configurable lines up/down |
all_buf | Content from all loaded buffers with files on disk |
lsp_diag | LSP diagnostics information for the selected lines |
SimpleGPT uses a Jinja-like template engine (jinja-engine.nvim) to power its template system:
Variable Interpolation: Access registers using {{register_name}}
syntax
{
"t": "I am working on a {{filetype}} file. The content is: {{content}}. Selected lines: {{visual}}. Question: {{q}}."
}
Control Structures: Use Jinja-style control flow
{% if visual %}Selected: {{visual}}{% else %}No selection{% endif %}
The template engine provides familiar Jinja-style syntax while being fully integrated with Neovim.
{"q", "<C-c>", "<esc>"}
: Exit the dialog{"<C-k>"}
: Extract code block closest to cursor{"<C-j>"}
: Cycle to next window{"<C-h>"}
: Cycle to previous window{"<C-s>"}
: Save registers (for template editing only)K
: Show special value for placeholder under cursor (for template editing only)ChatDialog
(The dialog that can get responses){"<C-a>"}
: Append response to original buffer after selection/current line{"<C-y>"}
: Copy full response to clipboard{"<C-r>"}
: Replace selected text/current line with response{"<m-c>"}
: Instruction Editing:<LocalLeader>g
(You can change it by setting keymaps.prefix
when you setup the plugin)<LocalLeader>gl
: load registers<LocalLeader>gD
: dump registers<LocalLeader>ge
: edit registers<LocalLeader>gs
: send question to clipboard<LocalLeader>gc
: send question to ChatGPT<LocalLeader>gr
: send to get direct response<LocalLeader>gd
: send to get response with diff<LocalLeader>gR
: resume last popup<LocalLeader>gp
: load current file to reg<LocalLeader>gP
: append current file to reg<LocalLeader>s
(You can change it by setting keymaps.shortcuts.prefix
when you setup the plugin)<LocalLeader>sr
: (R)ewrite Text<LocalLeader>sc
: (C)omplete Code<LocalLeader>sg
: Fix (g)rammar<LocalLeader>sd
: Con(d)ense<LocalLeader>st
: Con(t)inueAn example to change the shortcuts prefix in lazy.nvim:
{
"you-n-g/simplegpt.nvim",
--- ... other configurations
opts = {
keymaps = {
shortcuts = {
prefix = "<m-g>",
},
prefix = "<m-g><m-g>",
},
},
--- ... other configurations
}
Flag explanation:
🌟: high priority
TODOs
b:vimtex_main
in my config solve this problem.?
to see the help menu for shortcuts.---- Example focused part ----
def plus(a, b):
# TODO: plus them and return
---- Example output part ----
def plus(a, b):
return a + b
show
an hide
to ctrl the conversation dialogBugs
<c-r>
in popup target.More features that may be added in the long future
Welcome to contribute to this project.
You can test the plugin with minimal config with
vim -u tests/init_configs/lazy.lua -U NONE -N -i NONE
for lazy.nvimvim -u tests/init_configs/packer.lua -U NONE -N -i NONE
ChatCompletion
API (which is the most powerful and frequently used in the future trend).