
Bir süredir kodlamaya yardımcı olması için yapay zekayı kullanıyorum, ancak kodumla yapay zeka arasında ileri geri gitmek, son derece optimize edilmiş bir kurulumla bile sıkıcı olmaya başladı. Böylece Dijital Asistanım Kai’yi doğrudan Neovim’e entegre ettim.
Sorun
Kod düzenleme için yapay zeka ile çalışırken genellikle şu eylemlerden birini istersiniz:
- Yer değiştirmek geliştirilmiş bir sürüme sahip seçilen kod
- Sokmak bağlama dayalı yeni kod
- Görüntülemek hiçbir şeyi değiştirmeden bilgi
Çoğu yapay zeka entegrasyonu onlara tam olarak ne yapmaları gerektiğini söylemenizi sağlar. Kai bunu senin sorma şeklinden anlıyor.
Nasıl Çalışır?
Bütün bunlar Claude Kodundaki bir yeteneğe dayanıyor: kitlesel olarak az tartışıldı. Bunu sadece komut satırı modu olarak düşünüyorum.
- Bu şeyin içine girebilirsin
- Daha sonra ona bir dize verebilirsiniz ve o sadece gidip çalıştıracaktır.
- Hatta farklı bağlamları ve benzerlerini nasıl kullandığını bile kontrol edebilirsiniz.
claude -p "What's the weather like in San Francisco right now?"1
Her neyse, kaputun altında olup biten bu. Aslında bu eklentiyle çağırdığımız şey, Claude Code’un komut satırı sürümüdür.
Yapı
Eklentinin iki ana parçası var:
- Lua eklentisi (
kai-neovim.lua) – Neovim entegrasyonunu, görsel seçimleri ve arabellek yönetimini yönetir - Kabuk betiği (
kai-neovim.sh) – Bağlamı işler ve AI arka ucuyla iletişim kurar
Akıllı Bağlam İşleme

Eklenti her zaman arabelleğin tamamını bağlam olarak gönderir, ancak akıllıca şunlara odaklanır:
- Seçilen metin görsel modda olduğunuzda
- İmleç konumu normal moddayken
Bu yaklaşım, mevcut seçiminize veya imleç konumunuza göre hassas, hedeflenen değişiklikleri mümkün kılarken kapsamlı bir bağlam sağlar.
Akıllı Eylem Tespiti
Eklenti temel olarak ona her şeyi anlatmanıza olanak tanır ve bunu çözmeye çalışır. İşte bazı örnekler.
- “X ile değiştir” → Seçimi değiştirir
- “Açıklayan bir yorum ekle” → Seçimden sonra ekler
- “Bu ne işe yarıyor?” → Analizi açılır pencerede gösterir
- “Buraya uygun bir resim ekleyin.” → Özel bir görüntü oluşturur ve onu o konuma ekler
- “Hatayı düzelt” → Düzeltilmiş kodla değiştirir
Bu tamamen delilik. Rastgele şeyler gönderebiliriz ve onun bunu çözmesini sağlayabiliriz. Temel olarak yapay zeka ile komut satırı etkileşimi. Ve metin düzenleyicinizin içinde.
Kod
Bu bunun için temel koddur, ancak bunun devam eden bir çalışma olduğunu unutmayın. Tamamen çöp olabilir. Ve evet, kesinlikle Kai’den bunu yapmama yardım etmesini istedim.
Ana Eklenti Kodu
Bunu farklı kaydet ~/.config/nvim/lua/kai-neovim.lua:
local M = {}
-- Function to get visual selection
local function get_visual_selection()
-- Get the visual selection marks
local _, start_row, start_col, _ = unpack(vim.fn.getpos("'<"))
local _, end_row, end_col, _ = unpack(vim.fn.getpos("'>"))
-- Get the lines
local lines = vim.api.nvim_buf_get_lines(0, start_row - 1, end_row, false)
if #lines == 0 then
return ""
end
-- Handle single line selection
if #lines == 1 then
lines[1] = string.sub(lines[1], start_col, end_col)
else
-- Multi-line selection
lines[1] = string.sub(lines[1], start_col)
if end_col > 0 then
lines[#lines] = string.sub(lines[#lines], 1, end_col)
end
end
return table.concat(lines, "\n")
end
-- Function to escape special characters for shell
local function shell_escape(str)
return "'" .. str:gsub("'", "'\"'\"'") .. "'"
end
-- Main function to handle Kai Neovim integration
function M.kai_enhance()
-- Set up subtle blue highlight for the input prompt
vim.cmd('highlight KaiPrompt guifg=#e0e0e0 guibg=#1a1a2e')
-- Get the prompt from user with custom highlighting
vim.cmd('echohl KaiPrompt')
local prompt = vim.fn.input("🤖 Kai: ")
vim.cmd('echohl None')
if prompt == "" then
print("No instruction provided.")
return
end
-- Check if we're in visual mode
local mode = vim.fn.mode()
local is_visual = mode == 'v' or mode == 'V' or mode == ''
-- Get selection if in visual mode, empty string otherwise
local selection = ""
if is_visual then
selection = get_visual_selection()
end
-- Get current file path
local filepath = vim.fn.expand('%:p')
-- Get cursor position
local cursor_row, cursor_col = unpack(vim.api.nvim_win_get_cursor(0))
-- Get entire buffer content
local buffer_content = table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), "\n")
-- Create a temporary file for the context
local context_file = os.tmpname()
local f = io.open(context_file, "w")
f:write("CURRENT FILE: " .. filepath .. "\n\n")
-- Always send the entire buffer
f:write("FULL BUFFER CONTENT:\n" .. buffer_content .. "\n\n")
-- Add cursor position
f:write("CURSOR POSITION: Line " .. cursor_row .. ", Column " .. cursor_col .. "\n\n")
if is_visual then
-- Include selection information when text is selected
local _, start_row, start_col, _ = unpack(vim.fn.getpos("'<"))
local _, end_row, end_col, _ = unpack(vim.fn.getpos("'>"))
f:write("SELECTED TEXT (Lines " .. start_row .. "-" .. end_row .. "):\n" .. selection .. "\n\n")
f:write("MODE: User has selected specific text. Focus on this selection within the context of the entire buffer.\n\n")
else
-- When no selection, note cursor position
f:write("MODE: No selection. User's cursor is at line " .. cursor_row .. ". Make targeted changes based on cursor location unless instructed otherwise.\n\n")
end
f:write("INSTRUCTION: " .. prompt .. "\n")
f:close()
-- Call Kai script
local cmd = string.format(
"~/.config/nvim/scripts/kai-neovim.sh %s %s",
shell_escape(context_file),
shell_escape(prompt)
)
-- Create progress notification (simplified for blog post)
print("🤖 Processing with Kai...")
-- Execute command
local output = vim.fn.system(cmd)
-- Clean up temp file
os.remove(context_file)
-- Parse the action and content from the response
local lines = vim.split(output, '\n', { plain = true })
local action = lines[1]
local content_lines = {}
for i = 2, #lines do
if lines[i] ~= "" or i < #lines then
table.insert(content_lines, lines[i])
end
end
local content = table.concat(content_lines, '\n')
-- Remove any trailing newline
content = content:gsub('\n$', '')
-- Handle different actions
if action == "[ACTION:DISPLAY]" then
-- Create a floating window to display the analysis
local display_buf = vim.api.nvim_create_buf(false, true)
local display_lines = vim.split(content, '\n', { plain = true })
-- Calculate window dimensions
local width = math.min(80, vim.o.columns - 10)
local height = math.min(#display_lines + 2, vim.o.lines - 10)
-- Set buffer content
vim.api.nvim_buf_set_lines(display_buf, 0, -1, false, display_lines)
-- Create floating window
local display_win = vim.api.nvim_open_win(display_buf, true, {
relative = 'editor',
width = width,
height = height,
col = math.floor((vim.o.columns - width) / 2),
row = math.floor((vim.o.lines - height) / 2),
style = 'minimal',
border = 'rounded',
title = ' Kai Analysis ',
title_pos = 'center',
})
-- Set up keymaps to close the window
local close_keys = {'' , 'q', '' }
for _, key in ipairs(close_keys) do
vim.api.nvim_buf_set_keymap(display_buf, 'n', key,
':lua vim.api.nvim_win_close(' .. display_win .. ', true)' ,
{ noremap = true, silent = true })
end
print("Kai analysis complete! Press , q, or to close." )
return
end
-- Perform the appropriate action based on the marker
if is_visual then
if action == "[ACTION:REPLACE]" then
-- Replace the selection
local save_reg = vim.fn.getreg('"')
local save_regtype = vim.fn.getregtype('"')
vim.fn.setreg('"', content, mode == 'V' and 'V' or 'v')
vim.cmd('normal! gv"_d') -- Delete selection without affecting registers
vim.cmd('normal! P') -- Paste before cursor
vim.fn.setreg('"', save_reg, save_regtype)
elseif action == "[ACTION:INSERT_AFTER]" then
-- Insert after the selection
vim.cmd('normal! gv') -- Reselect
vim.cmd('normal! o') -- Go to end of selection
vim.cmd('normal! ') -- Exit visual mode
-- Insert a newline and the content
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
local content_lines_new = vim.split(content, '\n', { plain = true })
-- Insert empty line first, then content
vim.api.nvim_buf_set_lines(0, row, row, false, {""})
vim.api.nvim_buf_set_lines(0, row + 1, row + 1, false, content_lines_new)
end
else
-- Normal mode - insert at cursor position
local content_lines_new = vim.split(content, '\n', { plain = true })
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
-- Insert the lines at cursor position
vim.api.nvim_buf_set_text(0, row - 1, col, row - 1, col, content_lines_new)
end
print("Kai enhancement complete!")
end
-- Set up the keymap
function M.setup()
-- Visual mode mapping
vim.keymap.set('v', 'ai' , M.kai_enhance,
{ noremap = true, silent = true, desc = "Enhance with Kai (intelligent action)" })
-- Normal mode mapping (insert at cursor)
vim.keymap.set('n', 'ai' , M.kai_enhance,
{ noremap = true, silent = true, desc = "Insert Kai text at cursor" })
end
return M1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
Kabuk Komut Dosyası
Yaratmak ~/.config/nvim/scripts/kai-neovim.sh:
#!/bin/bash
# Kai Neovim Enhancement Script with Intelligent Action Detection
# Usage: kai-neovim.sh
CONTEXT_FILE="$1"
PROMPT="$2"
# Check if claude CLI is available (we use it to communicate with Kai)
if ! command -v claude &> /dev/null; then
echo "Error: Claude CLI not found. Please install it first."
exit 1
fi
# Read the CLAUDE.md files for additional context (project-specific rules for Kai)
GLOBAL_CLAUDE_MD=""
LOCAL_CLAUDE_MD=""
if [ -f "$HOME/.claude/CLAUDE.md" ]; then
GLOBAL_CLAUDE_MD=$(cat "$HOME/.claude/CLAUDE.md")
fi
# Find the nearest CLAUDE.md in the project
CURRENT_DIR=$(pwd)
while [ "$CURRENT_DIR" != "/" ]; do
if [ -f "$CURRENT_DIR/CLAUDE.md" ]; then
LOCAL_CLAUDE_MD=$(cat "$CURRENT_DIR/CLAUDE.md")
break
fi
CURRENT_DIR=$(dirname "$CURRENT_DIR")
done
# Regular text enhancement request - let Kai determine the action
FULL_PROMPT="You are Kai, an AI assistant integrated into Neovim.
CRITICAL CONTEXT FROM CLAUDE.md FILES (FOLLOW THESE RULES EXACTLY):
==================================================
GLOBAL CLAUDE.md:
$GLOBAL_CLAUDE_MD
PROJECT CLAUDE.md:
$LOCAL_CLAUDE_MD
==================================================
CURRENT EDITING CONTEXT:
$(cat "$CONTEXT_FILE")
CRITICAL: INTELLIGENT ACTION DETECTION
You must analyze the user's instruction to determine what they want:
1. If they say things like \"replace with\", \"change to\", \"rewrite as\", \"make this\", \"convert to\" → REPLACE the selected text
2. If they say things like \"write something like this\", \"create a note about\", \"add after\", \"insert\" → INSERT new content (don't replace)
3. If they say things like \"improve\", \"enhance\", \"fix\", \"correct\" → REPLACE with improved version
4. If they say things like \"explain this\", \"what is this\", \"analyze\", \"tell me about\", \"show me\", \"list\", \"count\", \"find\" → DISPLAY information (don't modify file)
IMPORTANT: When working with selected text, focus on that specific text within the context of the entire buffer. When working without selection, make targeted changes at the cursor location.
RESPONSE FORMAT:
You must start your response with ONE of these action markers on its own line:
[ACTION:REPLACE]
[ACTION:INSERT_AFTER]
[ACTION:INSERT_BEFORE]
[ACTION:DISPLAY]
Then on the next line, provide the content:
- For REPLACE/INSERT actions: provide ONLY the text to insert (no explanations)
- For DISPLAY actions: provide the analysis/information to show the user
IMPORTANT INSTRUCTIONS:
- First line must be the action marker
- Follow ALL formatting rules from CLAUDE.md
- Maintain the code style and conventions of the file
- Consider the context when generating content
- You are Kai, the AI assistant integrated into Neovim
User instruction: $PROMPT"
# Get the response with action marker
RESPONSE=$(echo "$FULL_PROMPT" | claude -p) # Using claude CLI to communicate with Kai
# Output the response
echo "$RESPONSE"
# Exit with the command's exit code
exit $?1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
Komut dosyasını çalıştırılabilir yapmayı unutmayın:
chmod +x ~/.config/nvim/scripts/kai-neovim.sh1
Özet
Tamam, bu kendi uygulamanızın yapısına başlamanıza yardımcı olacaktır.
Artık Neovim’in içinden yapay zekanızla doğrudan konuşabilirsiniz!