A Neovim plugin to chat with LLM in buffer. Tune
tune.mp4
- Install the plugin with your preferred package manager
- Install
npm install -g tune-sdk - Initialize tune-sdk
tune-sdk init - edit
~/.tune/.envaddOPENAI_KEYand other keys - Run
:TuneNewto create a new chat buffer - Type your message and press
<CR>to send - Use
:TuneSaveto save your conversation with an AI-generated filename
- Native Editor Experience: Chat with LLMs using your familiar text editor environment and keybindings
- File-Based Chat: Store and organize your conversations in
.chatfiles - Variable Expansion: Easily include content from files, environment variables, and even images in your prompts
- Tool Integration: Create and use custom tools (Python, JavaScript, PHP, or even chat-based) for extended functionality
- Flexible LLM Configuration: Support for different LLM providers through simple configuration files
- Structured Chat Format: Clear syntax for different message types (system, user, assistant, etc.)
- Smart Text Objects: Navigate and edit chat conversations with purpose-built text objects
- Autocomplete: Auto-complete models tools and filenames
- AI-Generated Filenames: Automatically generate meaningful filenames for your chat sessions
Use .chat files with a clear syntax for different message types:
system: system prompt
user: user message
assistant: assistant reply
comment: comment
tool_call: tool call
tool_result: result of a tool call
err: error that occurred
Include external content in your chats:
system:
@system # Expand from system.txt
user:
describe @image # Include images
:TuneNew [system_prompt]- Create a new chat buffer (optionally with a system prompt):TuneChat [stop]- Execute chat completion (stops at 'step' by default, or 'assistant' if specified):TuneSave- Save buffer with an AI-generated filename:TuneKill- Cancel ongoing generation
<CR>in normal mode: Execute TuneChat<C-CR>in normal mode: Execute TuneChat until assistant answer<S-CR>in insert mode: Execute TuneChat<S-C-CR>in insert mode: Execute TuneChat until assistant answer<Esc>or<C-c>in any mode: Cancel generation
You can customize the keymaps in your configuration:
require("tune").setup({
keymaps = {
n = {
["<CR>"] = { ":TuneChat<CR>", "Execute TuneChat" },
["<C-CR>"] = { ":TuneChat assistant<CR>", "Execute TuneChat until assistant answer" },
["<Esc>"] = { ":TuneKill<CR>", "Execute TuneKill" },
["<C-c>"] = { ":TuneKill<CR>", "Execute TuneKill" },
},
i = {
["<S-CR>"] = { "<Esc>:TuneChat<CR>", "Execute TuneChat in Insert Mode" },
["<S-C-CR>"] = { "<Esc>:TuneChat assistant<CR>", "Execute TuneChat in Insert Mode until assistant answer" },
["<C-c>"] = { "<Esc>:TuneKill<CR>", "Execute TuneKill in Insert Mode" },
},
}
})The plugin provides custom text objects for easier navigation and editing in chat files:
ar/ir- Around/inner role content (select entire role block or just content)ac/ic- Around/inner chat conversation (select entire chat or just content between separators)at/it- Around/inner tail (select from cursor to end of current chat)
Examples:
var- Select around current role (including the role header)vir- Select just the content of current roledac- Delete entire current chat conversationcit- Change content from cursor to end of chat
The plugin integrates with nvim-cmp to provide:
- Snippet completion: Type
u,s, orcand press your completion key to expand to role headers - Variable completion: Type
@followed by partial variable names to see available expansions
Built-in variables include:
@editor/filename- Current file path@editor/buffer- Current buffer content@editor/buffers- List of all open buffers@editor/selection- Currently selected text
Before installing, ensure you have:
- Neovim >= 0.8.0
- nvim-treesitter installed
- tune-sdk installed globally
npm install -g tune-sdk
Using lazy.nvim (recommended)
Add this to your Neovim configuration:
{
"iovdin/tune.nvim",
dependencies = {
'iovdin/tree-sitter-chat',
'nvim-treesitter/nvim-treesitter'
},
config = function()
require("tune").setup({})
end,
},Using packer.nvim
use {
'iovdin/tune.nvim',
config = function()
require("tune").setup({})
end,
requires = {
'nvim-treesitter/nvim-treesitter',
'iovdin/tree-sitter-chat'
},
}Using vim-plug
Add this to your init.vim:
call plug#begin('~/.config/nvim/plugged')
" Install nvim-treesitter and run :TSUpdate after installation
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
" Install tree-sitter-chat parser
Plug 'iovdin/tree-sitter-chat'
" Install tune.nvim and lazy-load it for 'chat' filetype
Plug 'iovdin/tune.nvim', { 'for': 'chat' }
call plug#end()
" Initialize tune.nvim for 'chat' filetype
augroup TuneSetup
autocmd!
autocmd FileType chat lua require("tune").setup({})
augroup ENDAfter installation, make sure to:
- Add "chat" to your nvim-treesitter configuration:
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function ()
local configs = require("nvim-treesitter.configs")
configs.setup({
ensure_installed = { "c", "lua", "vim", "vimdoc", "javascript", "html", "css", "python", "typescript", "chat"},
sync_install = false,
highlight = { enable = true },
indent = { enable = true },
})
end
},Alternatively, you can install the chat parser manually after installation:
:TSInstall chat
- (Optional) For completion support, ensure you have nvim-cmp installed and add the tune source:
{
"hrsh7th/nvim-cmp",
config = function()
local cmp = require('cmp')
cmp.setup({
sources = cmp.config.sources({
{ name = 'tune' }, -- Add tune completion source
-- your other sources...
})
})
end
}