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",
|
"type": "object",
|
||||||
"properties": {}
|
"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"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})),
|
})),
|
||||||
@@ -1330,6 +1355,72 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"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" => {
|
"nvim_execute_lua" => {
|
||||||
if let Some(code) = args.get("code").and_then(|v| v.as_str()) {
|
if let Some(code) = args.get("code").and_then(|v| v.as_str()) {
|
||||||
// BAKE IN: Block interactive prompts that cause server deadlocks
|
// BAKE IN: Block interactive prompts that cause server deadlocks
|
||||||
|
|||||||
Reference in new issue
Block a user