Skip to content

Commit 3462cb0

Browse files
authored
feat(recipes): start working on an AI recipes section (#171)
* feat(recipes): start working on an AI recipes section * feat(ai): add basic configuration code for various AI plugins * feat(ai): add link to AstroCommunity AI entry
1 parent ff21038 commit 3462cb0

File tree

1 file changed

+232
-0
lines changed
  • src/content/docs/recipes

1 file changed

+232
-0
lines changed

src/content/docs/recipes/ai.mdx

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
---
2+
id: ai
3+
title: AI Completion
4+
---
5+
6+
There are many AI plugins out there which provide completion through various mechanisms. This page goes over how to build onto an AstroNvim configuration in order to easily hook up and configure different AI completion plugins.
7+
8+
:::tip
9+
10+
This is available in the [AstroCommunity](https://github.com/AstroNvim/astrocommunity/tree/main/lua/astrocommunity/recipes/ai) and the AI completion plugins within AstroCommunity utilize the configuration it sets up.
11+
12+
```lua title="lua/community.lua" ins={3}
13+
return {
14+
"AstroNvim/astrocommunity",
15+
{ import = "astrocommunity.recipes.ai" },
16+
}
17+
```
18+
19+
:::
20+
21+
### Completion Engine Integration
22+
23+
In order to make AI plugins play nicely with AstroNvim it's important to set up an integration point with completion engines in Neovim in order to accept AI recommended code. Depending on which completion plugin you are using, you may need to modify the configuration of the mappings to account for interacting with normal completion as well as AI recommended code. By default AstroNvim utilizes a "super-tab" like configuration where the `<Tab>` key is used for triggering completion, navigating through snippets, and navigating through completion items. These code snippets change this configuration so that the `<Tab>` key is only used for snippet navigation and AI completion. To navigate through the completion lists, it would then be recommended to use `<C-n>` and `<C-p>`.
24+
25+
These configurations set up the completion engines to look for a function stored in `vim.g.ai_accept` which can be later configured by an AI completion plugin to choose what action should be taken when attempting to accept an AI suggestion if available.
26+
27+
#### [nvim-cmp](https://github.com/hrsh7th/nvim-cmp) Integration
28+
29+
By default AstroNvim comes with [`nvim-cmp`](https://github.com/hrsh7th/nvim-cmp) for completion. This modifies the default configuration to set up the `<Tab>` key as described above:
30+
31+
```lua title="lua/plugins/cmp_ai.lua"
32+
return {
33+
"hrsh7th/nvim-cmp",
34+
optional = true,
35+
opts = function(_, opts)
36+
local cmp = require("cmp")
37+
if not opts.mapping then
38+
opts.mapping = {}
39+
end
40+
opts.mapping["<Tab>"] = cmp.mapping(function(fallback)
41+
-- Snippet jump next (with support for several popular snippet plugins)
42+
local mini_snippets_avail, mini_snippets = pcall(require, "mini.snippets")
43+
local luasnip_avail, luasnip = pcall(require, "luasnip")
44+
if mini_snippets_avail then
45+
if mini_snippets.session.get(false) then
46+
mini_snippets.session.jump("next")
47+
return
48+
end
49+
elseif luasnip_avail then
50+
if luasnip.locally_jumpable(1) then
51+
luasnip.jump(1)
52+
return
53+
end
54+
elseif vim.snippet and vim.snippet.active({ direction = 1 }) then
55+
vim.schedule(function()
56+
vim.snippet.jump(1)
57+
end)
58+
return
59+
end
60+
-- AI accept
61+
if vim.g.ai_accept and vim.g.ai_accept() then
62+
return
63+
end
64+
-- Fallback
65+
fallback()
66+
end, { "i", "s" })
67+
opts.mapping["<S-Tab>"] = cmp.mapping(function(fallback)
68+
-- Snippet jump previous
69+
local mini_snippets_avail, mini_snippets = pcall(require, "mini.snippets")
70+
local luasnip_avail, luasnip = pcall(require, "luasnip")
71+
if mini_snippets_avail then
72+
if mini_snippets.session.get(false) then
73+
mini_snippets.session.jump("prev")
74+
return
75+
end
76+
elseif luasnip_avail then
77+
if luasnip.locally_jumpable(-1) then
78+
luasnip.jump(-1)
79+
return
80+
end
81+
elseif vim.snippet and vim.snippet.active({ direction = -1 }) then
82+
vim.schedule(function()
83+
vim.snippet.jump(-1)
84+
end)
85+
return
86+
end
87+
-- Fallback
88+
fallback()
89+
end, { "i", "s" })
90+
end,
91+
}
92+
```
93+
94+
#### [blink.cmp](https://github.com/Saghen/blink.cmp) Integration
95+
96+
[blink.cmp](https://github.com/Saghen/blink.cmp) is another popular completion plugin. This configures the `<Tab>` key as described above:
97+
98+
```lua title="lua/plugins/cmp_ai.lua"
99+
return {
100+
"Saghen/blink.cmp",
101+
optional = true,
102+
opts = function(_, opts)
103+
if not opts.keymap then
104+
opts.keymap = {}
105+
end
106+
opts.keymap["<Tab>"] = {
107+
"snippet_forward",
108+
function()
109+
if vim.g.ai_accept then
110+
return vim.g.ai_accept()
111+
end
112+
end,
113+
"fallback",
114+
}
115+
opts.keymap["<S-Tab>"] = { "snippet_backward", "fallback" }
116+
end,
117+
}
118+
```
119+
120+
### AI Plugin Integration
121+
122+
Once our completion engine is configured, we can start choosing and adding in an AI plugin from the Neovim plugin ecosystem, and setting up the `vim.g.ai_accept` function appropriately to hook into the completion engine mappings that we previously set up. Please note that further configuration may be necessary if you want to use completion sources rather than inline suggestions or change other behavior of the AI plugins. For that setup, please refer to the documentation of the plugins themselves.
123+
124+
#### [copilot.lua](https://github.com/zbirenbaum/copilot.lua)
125+
126+
```lua title="lua/plugins/copilot.lua"
127+
return {
128+
"zbirenbaum/copilot.lua",
129+
cmd = "Copilot",
130+
build = ":Copilot auth",
131+
event = "BufReadPost",
132+
opts = {
133+
suggestion = {
134+
keymap = {
135+
accept = false, -- handled by completion engine
136+
},
137+
},
138+
},
139+
specs = {
140+
{
141+
"AstroNvim/astrocore",
142+
opts = {
143+
options = {
144+
g = {
145+
-- set the ai_accept function
146+
ai_accept = function()
147+
if require("copilot.suggestion").is_visible() then
148+
require("copilot.suggestion").accept()
149+
return true
150+
end
151+
end,
152+
},
153+
},
154+
},
155+
},
156+
},
157+
}
158+
```
159+
160+
#### [codeium.nvim](https://github.com/Exafunction/codeium.nvim)
161+
162+
```lua title="lua/plugins/codeium.lua"
163+
return {
164+
"Exafunction/codeium.nvim",
165+
cmd = "Codeium",
166+
event = "InsertEnter",
167+
build = ":Codeium Auth",
168+
opts = {
169+
virtual_text = {
170+
key_bindings = {
171+
accept = false, -- handled by completion engine
172+
},
173+
},
174+
},
175+
specs = {
176+
{
177+
"AstroNvim/astrocore",
178+
opts = {
179+
options = {
180+
g = {
181+
-- set the ai_accept function
182+
ai_accept = function()
183+
if
184+
require("codeium.virtual_text").get_current_completion_item()
185+
then
186+
vim.api.nvim_input(require("codeium.virtual_text").accept())
187+
return true
188+
end
189+
end,
190+
},
191+
},
192+
},
193+
},
194+
},
195+
}
196+
```
197+
198+
#### [supermaven-nvim](https://github.com/supermaven-inc/supermaven-nvim)
199+
200+
```lua title="lua/plugins/supermaven.lua"
201+
return {
202+
"supermaven-inc/supermaven-nvim",
203+
event = "InsertEnter",
204+
cmd = { "SupermavenUseFree", "SupermavenUsePro" },
205+
opts = {
206+
keymaps = {
207+
accept_suggestion = nil, -- handled by completion engine
208+
},
209+
},
210+
specs = {
211+
{
212+
"AstroNvim/astrocore",
213+
opts = {
214+
options = {
215+
g = {
216+
-- set the ai_accept function
217+
ai_accept = function()
218+
local suggestion = require("supermaven-nvim.completion_preview")
219+
if suggestion.has_suggestion() then
220+
vim.schedule(function()
221+
suggestion.on_accept_suggestion()
222+
end)
223+
return true
224+
end
225+
end,
226+
},
227+
},
228+
},
229+
},
230+
},
231+
}
232+
```

0 commit comments

Comments
 (0)