feat(nvim): add dedicated mcp tools for file reading and regex searching
This commit is contained in:
1 parent
b1fc381107
commit
24aacdfae1
1 file changed
+91
@@ -999,6 +999,31 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nvim_read_file",
|
||||
"description": "Read specific lines from a file buffer (like cat or sed -n). Reads unsaved changes if open.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": { "type": "string" },
|
||||
"start_line": { "type": "integer", "description": "1-indexed start line (optional, defaults to 1)" },
|
||||
"end_line": { "type": "integer", "description": "1-indexed end line (optional, defaults to end of file)" }
|
||||
},
|
||||
"required": ["file"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nvim_search_file",
|
||||
"description": "Search for a regex pattern within a file buffer (like grep). Searches unsaved changes if open.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": { "type": "string" },
|
||||
"pattern": { "type": "string", "description": "Lua-compatible regex pattern to search for" }
|
||||
},
|
||||
"required": ["file", "pattern"]
|
||||
}
|
||||
}
|
||||
]
|
||||
})),
|
||||
@@ -1329,6 +1354,72 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
Err(e) => send_error(id, -32603, &e).await,
|
||||
}
|
||||
}
|
||||
|
||||
"nvim_read_file" => {
|
||||
if let Some(file) = args.get("file").and_then(|v| v.as_str()) {
|
||||
let start_line = args.get("start_line").and_then(|v| v.as_i64()).unwrap_or(1);
|
||||
let end_line = args.get("end_line").and_then(|v| v.as_i64()).unwrap_or(-1);
|
||||
|
||||
let escaped_file = file.replace('\\', "\\\\").replace('"', "\\\"");
|
||||
let code = format!("
|
||||
local file = \"{escaped_file}\"
|
||||
local start_idx = {start_line} - 1
|
||||
local end_idx = {end_line}
|
||||
local bufnr = vim.fn.bufnr(file, true)
|
||||
if vim.fn.bufloaded(bufnr) == 0 then
|
||||
vim.fn.bufload(bufnr)
|
||||
end
|
||||
local lines = vim.api.nvim_buf_get_lines(bufnr, start_idx, end_idx, false)
|
||||
local res = {{}}
|
||||
for i, line in ipairs(lines) do
|
||||
local line_num = start_idx + i
|
||||
table.insert(res, tostring(line_num) .. ': ' .. line)
|
||||
end
|
||||
return table.concat(res, '\\n')
|
||||
");
|
||||
match execute_nvim_lua(&code).await {
|
||||
Ok(res) => send_text_result!(id.clone(), res),
|
||||
Err(e) => send_error(id, -32603, &e).await,
|
||||
}
|
||||
} else {
|
||||
send_error(id, -32602, "Missing 'file'").await;
|
||||
}
|
||||
}
|
||||
|
||||
"nvim_search_file" => {
|
||||
if let (Some(file), Some(pattern)) = (
|
||||
args.get("file").and_then(|v| v.as_str()),
|
||||
args.get("pattern").and_then(|v| v.as_str()),
|
||||
) {
|
||||
let escaped_file = file.replace('\\', "\\\\").replace('"', "\\\"");
|
||||
let escaped_pattern = pattern.replace('\\', "\\\\").replace('"', "\\\"");
|
||||
let code = format!("
|
||||
local file = \"{escaped_file}\"
|
||||
local pattern = \"{escaped_pattern}\"
|
||||
local bufnr = vim.fn.bufnr(file, true)
|
||||
if vim.fn.bufloaded(bufnr) == 0 then
|
||||
vim.fn.bufload(bufnr)
|
||||
end
|
||||
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
||||
local matches = {{}}
|
||||
for i, line in ipairs(lines) do
|
||||
if string.match(line, pattern) then
|
||||
table.insert(matches, tostring(i) .. ': ' .. line)
|
||||
end
|
||||
end
|
||||
if #matches == 0 then
|
||||
return 'No matches found.'
|
||||
end
|
||||
return table.concat(matches, '\\n')
|
||||
");
|
||||
match execute_nvim_lua(&code).await {
|
||||
Ok(res) => send_text_result!(id.clone(), res),
|
||||
Err(e) => send_error(id, -32603, &e).await,
|
||||
}
|
||||
} else {
|
||||
send_error(id, -32602, "Missing 'file' or 'pattern'").await;
|
||||
}
|
||||
}
|
||||
|
||||
"nvim_execute_lua" => {
|
||||
if let Some(code) = args.get("code").and_then(|v| v.as_str()) {
|
||||
|
||||
Reference in new issue
Block a user