Skip to content

Commit d87887f

Browse files
authored
Merge pull request #15 from bigcodegen/develop
bug fixes
2 parents 800d4de + 87c4da6 commit d87887f

File tree

4 files changed

+115
-50
lines changed

4 files changed

+115
-50
lines changed

package-lock.json

Lines changed: 29 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mcp-neovim-server",
3-
"version": "0.5.2",
3+
"version": "0.5.3",
44
"description": "An MCP server for neovim",
55
"type": "module",
66
"bin": {
@@ -26,13 +26,13 @@
2626
},
2727
"homepage": "https://github.com/bigcodegen/mcp-neovim-server#readme",
2828
"dependencies": {
29-
"@modelcontextprotocol/sdk": "^1.11.0",
29+
"@modelcontextprotocol/sdk": "^1.13.2",
3030
"neovim": "^5.3.0",
3131
"ts-node": "^10.9.2",
32-
"zod": "^3.25.64"
32+
"zod": "^3.25.67"
3333
},
3434
"devDependencies": {
35-
"@types/node": "^22.15.3",
35+
"@types/node": "^24.0.6",
3636
"typescript": "^5.8.3"
3737
}
3838
}

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { z } from "zod";
1212
const server = new McpServer(
1313
{
1414
name: "mcp-neovim-server",
15-
version: "0.5.2"
15+
version: "0.5.3"
1616
}
1717
);
1818

@@ -244,7 +244,7 @@ server.tool(
244244
"vim_register",
245245
"Manage Neovim register contents",
246246
{
247-
register: z.string().regex(/^[a-z\"]$/).describe("Register name - a lowercase letter [a-z] or double-quote [\"] for the unnamed register"),
247+
register: z.string().regex(/^[a-z"]$/).describe("Register name - a lowercase letter [a-z] or double-quote [\"] for the unnamed register"),
248248
content: z.string().describe("The text content to store in the specified register")
249249
},
250250
async ({ register, content }) => {

src/neovim.ts

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -213,25 +213,32 @@ export class NeovimManager {
213213
const tabpage = await nvim.tabpage;
214214
const currentTab = await tabpage.number;
215215

216-
// Get marks (a-z)
216+
// Get marks (a-z) - only include set marks
217217
const marks: { [key: string]: [number, number] } = {};
218218
for (const mark of 'abcdefghijklmnopqrstuvwxyz') {
219219
try {
220220
const pos = await nvim.eval(`getpos("'${mark}")`) as [number, number, number, number];
221-
marks[mark] = [pos[1], pos[2]];
221+
// Only include marks that are actually set (not at position 0,0)
222+
if (pos[1] > 0 && pos[2] > 0) {
223+
marks[mark] = [pos[1], pos[2]];
224+
}
222225
} catch (e) {
223226
// Mark not set
224227
}
225228
}
226229

227-
// Get registers (a-z, ", 0-9)
230+
// Get registers (a-z, ", 0-9) - only include non-empty registers
228231
const registers: { [key: string]: string } = {};
229232
const registerNames = [...'abcdefghijklmnopqrstuvwxyz', '"', ...Array(10).keys()];
230233
for (const reg of registerNames) {
231234
try {
232-
registers[reg] = String(await nvim.eval(`getreg('${reg}')`));
235+
const content = String(await nvim.eval(`getreg('${reg}')`));
236+
// Only include registers that have content
237+
if (content && content.trim().length > 0) {
238+
registers[String(reg)] = content;
239+
}
233240
} catch (e) {
234-
// Register empty
241+
// Register empty or error
235242
}
236243
}
237244

@@ -243,8 +250,8 @@ export class NeovimManager {
243250
let pluginInfo = '';
244251

245252
try {
246-
// Get LSP clients if available
247-
const lspClients = await nvim.eval('luaeval("vim.lsp.get_active_clients()")');
253+
// Get LSP clients if available (use new API for Neovim >=0.10)
254+
const lspClients = await nvim.eval('luaeval("vim.lsp.get_clients()")');
248255
if (Array.isArray(lspClients) && lspClients.length > 0) {
249256
const clientNames = lspClients.map((client: any) => client.name || 'unknown').join(', ');
250257
lspInfo = `Active LSP clients: ${clientNames}`;
@@ -288,14 +295,72 @@ export class NeovimManager {
288295
};
289296

290297
if (mode.mode.startsWith('v')) {
291-
const start = await nvim.eval(`getpos("'<")`) as [number, number, number, number];
292-
const end = await nvim.eval(`getpos("'>")`) as [number, number, number, number];
293-
const lines = await buffer.getLines({
294-
start: start[1] - 1,
295-
end: end[1],
296-
strictIndexing: true
297-
});
298-
neovimStatus.visualSelection = lines.join('\n');
298+
try {
299+
// Use a more reliable method to get the visual selection
300+
// This Lua code gets the actual selected text
301+
const visualText = await nvim.lua(`
302+
local mode = vim.fn.visualmode()
303+
if mode == '' then
304+
return ''
305+
end
306+
307+
-- Save current register content
308+
local save_reg = vim.fn.getreg('"')
309+
local save_regtype = vim.fn.getregtype('"')
310+
311+
-- Yank the visual selection to unnamed register
312+
vim.cmd('normal! "vy')
313+
314+
-- Get the yanked text
315+
local selected_text = vim.fn.getreg('"')
316+
317+
-- Restore the register
318+
vim.fn.setreg('"', save_reg, save_regtype)
319+
320+
return selected_text
321+
`);
322+
323+
neovimStatus.visualSelection = String(visualText || '');
324+
} catch (e) {
325+
// Fallback method using getpos and getline
326+
try {
327+
const start = await nvim.eval(`getpos("'<")`) as [number, number, number, number];
328+
const end = await nvim.eval(`getpos("'>")`) as [number, number, number, number];
329+
330+
if (start[1] === end[1]) {
331+
// Single line selection
332+
const line = await nvim.eval(`getline(${start[1]})`) as string;
333+
const startCol = start[2] - 1; // Convert to 0-based
334+
const endCol = end[2]; // Keep 1-based for substring end
335+
neovimStatus.visualSelection = line.substring(startCol, endCol);
336+
} else {
337+
// Multi-line selection
338+
const lines = await nvim.eval(`getline(${start[1]}, ${end[1]})`) as string[];
339+
if (lines && lines.length > 0) {
340+
const result = [];
341+
const startCol = start[2] - 1;
342+
const endCol = end[2];
343+
344+
// First line: from start column to end
345+
result.push(lines[0].substring(startCol));
346+
347+
// Middle lines: complete lines
348+
for (let i = 1; i < lines.length - 1; i++) {
349+
result.push(lines[i]);
350+
}
351+
352+
// Last line: from beginning to end column
353+
if (lines.length > 1) {
354+
result.push(lines[lines.length - 1].substring(0, endCol));
355+
}
356+
357+
neovimStatus.visualSelection = result.join('\n');
358+
}
359+
}
360+
} catch (e2) {
361+
neovimStatus.visualSelection = '';
362+
}
363+
}
299364
}
300365

301366
return neovimStatus;

0 commit comments

Comments
 (0)