feat(nvim-core): implement nvim_set_extmark for rich virtual text UI feedback
- Added nvim_set_extmark tool schema and handler - Implemented lua bridge using vim.api.nvim_buf_set_extmark to dynamically overlay ghost text and highlight groups onto active buffers
This commit is contained in:
1 parent
ea735003e2
commit
6a89f50cf2
1 file changed
+60
@@ -510,6 +510,31 @@ async fn set_nvim_diagnostics(line: i64, message: &str) -> Result<(), String> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn set_nvim_extmark(line: i64, text: &str, hl_group: &str) -> Result<(), String> {
|
||||||
|
let escaped_text = text.replace('\\', "\\\\").replace('"', "\\\"");
|
||||||
|
let lua_script = format!(
|
||||||
|
r#"
|
||||||
|
local ns = vim.api.nvim_create_namespace("gemini_extmarks")
|
||||||
|
local opts = {{
|
||||||
|
virt_text = {{{{"{escaped_text}", "{hl_group}"}}}},
|
||||||
|
virt_text_pos = "eol",
|
||||||
|
}}
|
||||||
|
vim.api.nvim_buf_set_extmark(0, ns, {line} - 1, 0, opts)
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
call_nvim_method(
|
||||||
|
"nvim_exec_lua",
|
||||||
|
vec![
|
||||||
|
rmpv::Value::String(lua_script.into()),
|
||||||
|
rmpv::Value::Array(vec![]),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn rmpv_to_json(val: &rmpv::Value) -> serde_json::Value {
|
fn rmpv_to_json(val: &rmpv::Value) -> serde_json::Value {
|
||||||
match val {
|
match val {
|
||||||
rmpv::Value::Nil => serde_json::Value::Null,
|
rmpv::Value::Nil => serde_json::Value::Null,
|
||||||
@@ -731,6 +756,19 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
|||||||
"required": ["line", "message"]
|
"required": ["line", "message"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "nvim_set_extmark",
|
||||||
|
"description": "Add virtual text (ghost text) to a specific line in the buffer to give the user rich UI feedback",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"line": { "type": "integer" },
|
||||||
|
"text": { "type": "string" },
|
||||||
|
"highlight_group": { "type": "string", "description": "Optional. E.g., 'DiagnosticVirtualTextInfo', 'Comment'" }
|
||||||
|
},
|
||||||
|
"required": ["line", "text"]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "nvim_list_buffers",
|
"name": "nvim_list_buffers",
|
||||||
"description": "List all open buffers in Neovim",
|
"description": "List all open buffers in Neovim",
|
||||||
@@ -952,6 +990,28 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
|||||||
send_error(id, -32602, "Missing 'line' or 'message'").await;
|
send_error(id, -32602, "Missing 'line' or 'message'").await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"nvim_set_extmark" => {
|
||||||
|
if let (Some(line), Some(text)) = (
|
||||||
|
args.get("line").and_then(serde_json::Value::as_i64),
|
||||||
|
args.get("text").and_then(|v| v.as_str()),
|
||||||
|
) {
|
||||||
|
let hl_group = args
|
||||||
|
.get("highlight_group")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.unwrap_or("Comment");
|
||||||
|
match set_nvim_extmark(line, text, hl_group).await {
|
||||||
|
Ok(()) => {
|
||||||
|
send_text_result!(
|
||||||
|
id.clone(),
|
||||||
|
format!("Successfully set extmark on line {}", line)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(e) => send_error(id, -32603, &e).await,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
send_error(id, -32602, "Missing 'line' or 'text'").await;
|
||||||
|
}
|
||||||
|
}
|
||||||
"nvim_list_buffers" => {
|
"nvim_list_buffers" => {
|
||||||
let lua_code = r"
|
let lua_code = r"
|
||||||
local bufs = vim.api.nvim_list_bufs()
|
local bufs = vim.api.nvim_list_bufs()
|
||||||
|
|||||||
Reference in new issue
Block a user