fix: apply automatic clippy fixes across workspace

This commit is contained in:
Riz Ashraf committed 2026-09-21 11:41:55 +01:00
1 parent 73ab5037d8
commit 5da422d23a
12 files changed
+97 -113

No files matched your search

+1 -1
View File
@@ -16,5 +16,5 @@ fn main() {
.unwrap_or_else(|| "unknown".to_string()); .unwrap_or_else(|| "unknown".to_string());
let version = format!("{} ({})", git_date.trim(), git_hash.trim()); let version = format!("{} ({})", git_date.trim(), git_hash.trim());
println!("cargo:rustc-env=APP_VERSION={}", version); println!("cargo:rustc-env=APP_VERSION={version}");
} }
+54 -59
View File
@@ -55,7 +55,7 @@ pub async fn send_error(id: Value, code: i32, message: &str) {
async fn get_socket_path() -> Result<String, String> { async fn get_socket_path() -> Result<String, String> {
let profile = let profile =
std::env::var("USERPROFILE").unwrap_or_else(|_| "C:\\Users\\reazul.ashraf".into()); std::env::var("USERPROFILE").unwrap_or_else(|_| "C:\\Users\\reazul.ashraf".into());
let path = format!("{}\\.gemini\\active_nvim.txt", profile); let path = format!("{profile}\\.gemini\\active_nvim.txt");
if let Ok(content) = tokio::fs::read_to_string(&path).await { if let Ok(content) = tokio::fs::read_to_string(&path).await {
let p = content.trim().to_string(); let p = content.trim().to_string();
@@ -63,10 +63,9 @@ async fn get_socket_path() -> Result<String, String> {
if p.starts_with(r"\\.\pipe\") { if p.starts_with(r"\\.\pipe\") {
return Ok(p); return Ok(p);
} else if p.starts_with("nvim.") { } else if p.starts_with("nvim.") {
return Ok(format!(r"\\.\pipe\{}", p)); return Ok(format!(r"\\.\pipe\{p}"));
} else {
return Ok(p);
} }
return Ok(p);
} }
} }
@@ -76,7 +75,7 @@ async fn get_socket_path() -> Result<String, String> {
let name = entry.file_name(); let name = entry.file_name();
let name_str = name.to_string_lossy(); let name_str = name.to_string_lossy();
if name_str.starts_with("nvim.") { if name_str.starts_with("nvim.") {
return Ok(format!(r"\\.\pipe\{}", name_str)); return Ok(format!(r"\\.\pipe\{name_str}"));
} }
} }
} }
@@ -196,7 +195,7 @@ async fn get_nvim_connection() -> Result<mpsc::Sender<NvimRequest>, String> {
if let rmpv::Value::Array(ref arr) = val { if let rmpv::Value::Array(ref arr) = val {
if arr.len() >= 4 && arr[0] == rmpv::Value::Integer(1.into()) { if arr.len() >= 4 && arr[0] == rmpv::Value::Integer(1.into()) {
let msgid = &arr[1]; let msgid = &arr[1];
let msgid_str = format!("{:?}", msgid); let msgid_str = format!("{msgid:?}");
if let Some(reply_sender) = if let Some(reply_sender) =
pending_clone2.lock().unwrap().remove(&msgid_str) pending_clone2.lock().unwrap().remove(&msgid_str)
@@ -283,7 +282,7 @@ async fn call_nvim(req: rmpv::Value) -> Result<rmpv::Value, String> {
rmpv::Value::Nil rmpv::Value::Nil
}; };
let msgid_str = format!("{:?}", msgid); let msgid_str = format!("{msgid:?}");
let tx = get_nvim_connection().await?; let tx = get_nvim_connection().await?;
let (reply_tx, reply_rx) = oneshot::channel(); let (reply_tx, reply_rx) = oneshot::channel();
@@ -373,7 +372,7 @@ async fn get_nvim_cursor() -> Result<String, String> {
if let RmpValue::Array(pos) = &arr[3] { if let RmpValue::Array(pos) = &arr[3] {
if pos.len() == 2 { if pos.len() == 2 {
if let (RmpValue::Integer(row), RmpValue::Integer(col)) = (&pos[0], &pos[1]) { if let (RmpValue::Integer(row), RmpValue::Integer(col)) = (&pos[0], &pos[1]) {
return Ok(format!("Line: {}, Column: {}", row, col)); return Ok(format!("Line: {row}, Column: {col}"));
} }
} }
} }
@@ -419,19 +418,18 @@ async fn get_nvim_visual_selection() -> Result<String, String> {
} }
async fn set_nvim_diagnostics(line: i64, message: &str) -> Result<(), String> { async fn set_nvim_diagnostics(line: i64, message: &str) -> Result<(), String> {
let escaped_message = message.replace("\\", "\\\\").replace("\"", "\\\""); let escaped_message = message.replace('\\', "\\\\").replace('"', "\\\"");
let lua_script = format!( let lua_script = format!(
r#" r#"
local ns = vim.api.nvim_create_namespace("gemini_diagnostics") local ns = vim.api.nvim_create_namespace("gemini_diagnostics")
local diagnostics = {{{{ local diagnostics = {{{{
lnum = {} - 1, lnum = {line} - 1,
col = 0, col = 0,
severity = vim.diagnostic.severity.WARN, severity = vim.diagnostic.severity.WARN,
message = "{}", message = "{escaped_message}",
}}}} }}}}
vim.diagnostic.set(ns, 0, diagnostics, {{}}) vim.diagnostic.set(ns, 0, diagnostics, {{}})
"#, "#
line, escaped_message
); );
use rmpv::Value as RmpValue; use rmpv::Value as RmpValue;
@@ -487,7 +485,7 @@ fn rmpv_to_json(val: &rmpv::Value) -> serde_json::Value {
let key_str = if let rmpv::Value::String(s) = k { let key_str = if let rmpv::Value::String(s) = k {
s.as_str().unwrap_or("").to_string() s.as_str().unwrap_or("").to_string()
} else { } else {
format!("{:?}", k) format!("{k:?}")
}; };
obj.insert(key_str, rmpv_to_json(v)); obj.insert(key_str, rmpv_to_json(v));
} }
@@ -514,7 +512,7 @@ async fn execute_nvim_lua(code: &str) -> Result<String, String> {
if arr.len() > 3 { if arr.len() > 3 {
return Ok(serde_json::to_string_pretty(&rmpv_to_json(&arr[3])).unwrap_or_default()); return Ok(serde_json::to_string_pretty(&rmpv_to_json(&arr[3])).unwrap_or_default());
} }
return Ok("".to_string()); return Ok(String::new());
} }
Err("Invalid response".to_string()) Err("Invalid response".to_string())
} }
@@ -549,12 +547,9 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
tracing::info!("{} MCP server started", app_name); tracing::info!("{} MCP server started", app_name);
let mut stdin = tokio::io::BufReader::new(tokio::io::stdin()); let mut stdin = tokio::io::BufReader::new(tokio::io::stdin());
loop { loop {
let raw_msg = match mcp_stdio::read_mcp_message(&mut stdin).await { let raw_msg = if let Some(m) = mcp_stdio::read_mcp_message(&mut stdin).await { m } else {
Some(m) => m,
None => {
tracing::info!("Stdin closed, exiting loop"); tracing::info!("Stdin closed, exiting loop");
break; break;
}
}; };
let msg = match serde_json::from_str::<JsonRpcRequest>(&raw_msg) { let msg = match serde_json::from_str::<JsonRpcRequest>(&raw_msg) {
@@ -586,7 +581,7 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
.and_then(|p| p.get("name")) .and_then(|p| p.get("name"))
.and_then(|n| n.as_str()) .and_then(|n| n.as_str())
.unwrap_or("unknown"); .unwrap_or("unknown");
format!("ToolCall[{}]", tool_name) format!("ToolCall[{tool_name}]")
} else { } else {
msg.method.clone() msg.method.clone()
}; };
@@ -698,7 +693,7 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
] ]
})), })),
error: None, error: None,
}).await }).await;
} }
"tools/call" => { "tools/call" => {
let params = msg.params.unwrap_or(json!({})); let params = msg.params.unwrap_or(json!({}));
@@ -710,12 +705,12 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
"nvim_goto_line" => { "nvim_goto_line" => {
if let (Some(file), Some(line)) = ( if let (Some(file), Some(line)) = (
args.get("file").and_then(|v| v.as_str()), args.get("file").and_then(|v| v.as_str()),
args.get("line").and_then(|v| v.as_i64()), args.get("line").and_then(serde_json::Value::as_i64),
) { ) {
let escaped_file = file.replace("\\", "\\\\"); let escaped_file = file.replace('\\', "\\\\");
let cmd = format!("e {} | {} | normal! zz", escaped_file, line); let cmd = format!("e {escaped_file} | {line} | normal! zz");
match send_nvim_command(&cmd).await { match send_nvim_command(&cmd).await {
Ok(_) => { Ok(()) => {
send_text_result!(id.clone(), format!("Successfully jumped to {} line {}", file, line)); send_text_result!(id.clone(), format!("Successfully jumped to {} line {}", file, line));
} }
Err(e) => send_error(id, -32603, &e).await, Err(e) => send_error(id, -32603, &e).await,
@@ -744,11 +739,11 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
}, },
"nvim_set_diagnostics" => { "nvim_set_diagnostics" => {
if let (Some(line), Some(message)) = ( if let (Some(line), Some(message)) = (
args.get("line").and_then(|v| v.as_i64()), args.get("line").and_then(serde_json::Value::as_i64),
args.get("message").and_then(|v| v.as_str()), args.get("message").and_then(|v| v.as_str()),
) { ) {
match set_nvim_diagnostics(line, message).await { match set_nvim_diagnostics(line, message).await {
Ok(_) => { Ok(()) => {
send_text_result!(id.clone(), format!("Successfully set diagnostic on line {}", line)); send_text_result!(id.clone(), format!("Successfully set diagnostic on line {}", line));
} }
Err(e) => send_error(id, -32603, &e).await, Err(e) => send_error(id, -32603, &e).await,
@@ -758,7 +753,7 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
} }
} }
"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()
local result = {} local result = {}
for _, buf in ipairs(bufs) do for _, buf in ipairs(bufs) do
@@ -768,7 +763,7 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
end end
end end
return vim.fn.json_encode(result) return vim.fn.json_encode(result)
"#; ";
match execute_nvim_lua(lua_code).await { match execute_nvim_lua(lua_code).await {
Ok(result) => { Ok(result) => {
send_text_result!(id.clone(), result); send_text_result!(id.clone(), result);
@@ -777,7 +772,7 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
} }
} }
"nvim_get_diagnostics" => { "nvim_get_diagnostics" => {
let lua_code = r#" let lua_code = r"
local bufnr = vim.api.nvim_get_current_buf() local bufnr = vim.api.nvim_get_current_buf()
local diagnostics = vim.diagnostic.get(bufnr) local diagnostics = vim.diagnostic.get(bufnr)
local result = {} local result = {}
@@ -791,7 +786,7 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
}) })
end end
return vim.fn.json_encode(result) return vim.fn.json_encode(result)
"#; ";
match execute_nvim_lua(lua_code).await { match execute_nvim_lua(lua_code).await {
Ok(result) => { Ok(result) => {
send_text_result!(id.clone(), result); send_text_result!(id.clone(), result);
@@ -801,24 +796,24 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
} }
"nvim_open_file" => { "nvim_open_file" => {
let json_str = serde_json::to_string(args).unwrap().replace("\\", "\\\\").replace("'", "\\'"); let json_str = serde_json::to_string(args).unwrap().replace('\\', "\\\\").replace('\'', "\\'");
let code = format!(" let code = format!("
local args = vim.json.decode('{}') local args = vim.json.decode('{json_str}')
vim.cmd('edit ' .. vim.fn.fnameescape(args.file)) vim.cmd('edit ' .. vim.fn.fnameescape(args.file))
if args.filetype and args.filetype ~= '' then if args.filetype and args.filetype ~= '' then
vim.bo.filetype = args.filetype vim.bo.filetype = args.filetype
end end
return 'Opened file ' .. args.file return 'Opened file ' .. args.file
", json_str); ");
match execute_nvim_lua(&code).await { match execute_nvim_lua(&code).await {
Ok(res) => send_text_result!(id.clone(), res), Ok(res) => send_text_result!(id.clone(), res),
Err(e) => send_error(id, -32603, &e).await, Err(e) => send_error(id, -32603, &e).await,
} }
} }
"nvim_open_buffer" => { "nvim_open_buffer" => {
let json_str = serde_json::to_string(args).unwrap().replace("\\", "\\\\").replace("'", "\\'"); let json_str = serde_json::to_string(args).unwrap().replace('\\', "\\\\").replace('\'', "\\'");
let code = format!(" let code = format!("
local args = vim.json.decode('{}') local args = vim.json.decode('{json_str}')
local buf = vim.api.nvim_create_buf(true, true) local buf = vim.api.nvim_create_buf(true, true)
if args.name and args.name ~= '' then if args.name and args.name ~= '' then
pcall(vim.api.nvim_buf_set_name, buf, args.name) pcall(vim.api.nvim_buf_set_name, buf, args.name)
@@ -832,30 +827,30 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
end end
vim.api.nvim_win_set_buf(0, buf) vim.api.nvim_win_set_buf(0, buf)
return 'Opened buffer ' .. tostring(buf) return 'Opened buffer ' .. tostring(buf)
", json_str); ");
match execute_nvim_lua(&code).await { match execute_nvim_lua(&code).await {
Ok(res) => send_text_result!(id.clone(), res), Ok(res) => send_text_result!(id.clone(), res),
Err(e) => send_error(id, -32603, &e).await, Err(e) => send_error(id, -32603, &e).await,
} }
} }
"nvim_close_buffer" => { "nvim_close_buffer" => {
let json_str = serde_json::to_string(args).unwrap().replace("\\", "\\\\").replace("'", "\\'"); let json_str = serde_json::to_string(args).unwrap().replace('\\', "\\\\").replace('\'', "\\'");
let code = format!(" let code = format!("
local args = vim.json.decode('{}') local args = vim.json.decode('{json_str}')
local buf = args.buf_id or vim.api.nvim_get_current_buf() local buf = args.buf_id or vim.api.nvim_get_current_buf()
local force = args.force or false local force = args.force or false
vim.api.nvim_buf_delete(buf, {{ force = force }}) vim.api.nvim_buf_delete(buf, {{ force = force }})
return 'Closed buffer ' .. tostring(buf) return 'Closed buffer ' .. tostring(buf)
", json_str); ");
match execute_nvim_lua(&code).await { match execute_nvim_lua(&code).await {
Ok(res) => send_text_result!(id.clone(), res), Ok(res) => send_text_result!(id.clone(), res),
Err(e) => send_error(id, -32603, &e).await, Err(e) => send_error(id, -32603, &e).await,
} }
} }
"nvim_split_window" => { "nvim_split_window" => {
let json_str = serde_json::to_string(args).unwrap().replace("\\", "\\\\").replace("'", "\\'"); let json_str = serde_json::to_string(args).unwrap().replace('\\', "\\\\").replace('\'', "\\'");
let code = format!(" let code = format!("
local args = vim.json.decode('{}') local args = vim.json.decode('{json_str}')
local cmd = args.direction == 'horizontal' and 'split' or 'vsplit' local cmd = args.direction == 'horizontal' and 'split' or 'vsplit'
vim.cmd(cmd) vim.cmd(cmd)
if args.file and args.file ~= '' then if args.file and args.file ~= '' then
@@ -864,16 +859,16 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
vim.api.nvim_win_set_buf(0, args.buf_id) vim.api.nvim_win_set_buf(0, args.buf_id)
end end
return 'Split window created' return 'Split window created'
", json_str); ");
match execute_nvim_lua(&code).await { match execute_nvim_lua(&code).await {
Ok(res) => send_text_result!(id.clone(), res), Ok(res) => send_text_result!(id.clone(), res),
Err(e) => send_error(id, -32603, &e).await, Err(e) => send_error(id, -32603, &e).await,
} }
} }
"nvim_reload_buffer" => { "nvim_reload_buffer" => {
let json_str = serde_json::to_string(args).unwrap().replace("\\", "\\\\").replace("'", "\\'"); let json_str = serde_json::to_string(args).unwrap().replace('\\', "\\\\").replace('\'', "\\'");
let code = format!(" let code = format!("
local args = vim.json.decode('{}') local args = vim.json.decode('{json_str}')
local buf = args.buf_id or vim.api.nvim_get_current_buf() local buf = args.buf_id or vim.api.nvim_get_current_buf()
vim.api.nvim_buf_call(buf, function() vim.api.nvim_buf_call(buf, function()
if args.force then if args.force then
@@ -883,7 +878,7 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
end end
end) end)
return 'Reloaded buffer ' .. tostring(buf) return 'Reloaded buffer ' .. tostring(buf)
", json_str); ");
match execute_nvim_lua(&code).await { match execute_nvim_lua(&code).await {
Ok(res) => send_text_result!(id.clone(), res), Ok(res) => send_text_result!(id.clone(), res),
Err(e) => send_error(id, -32603, &e).await, Err(e) => send_error(id, -32603, &e).await,
@@ -900,9 +895,9 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
} }
} }
"nvim_set_quickfix" => { "nvim_set_quickfix" => {
let json_str = serde_json::to_string(args).unwrap().replace("\\", "\\\\").replace("'", "\\'"); let json_str = serde_json::to_string(args).unwrap().replace('\\', "\\\\").replace('\'', "\\'");
let code = format!(" let code = format!("
local args = vim.json.decode('{}') local args = vim.json.decode('{json_str}')
local items = args.items or {{}} local items = args.items or {{}}
local action = ' ' local action = ' '
if args.action == 'append' then action = 'a' end if args.action == 'append' then action = 'a' end
@@ -911,16 +906,16 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
vim.fn.setqflist(items, action) vim.fn.setqflist(items, action)
vim.cmd('copen') vim.cmd('copen')
return 'Populated quickfix with ' .. tostring(#items) .. ' items' return 'Populated quickfix with ' .. tostring(#items) .. ' items'
", json_str); ");
match execute_nvim_lua(&code).await { match execute_nvim_lua(&code).await {
Ok(res) => send_text_result!(id.clone(), res), Ok(res) => send_text_result!(id.clone(), res),
Err(e) => send_error(id, -32603, &e).await, Err(e) => send_error(id, -32603, &e).await,
} }
} }
"nvim_highlight_lines" => { "nvim_highlight_lines" => {
let json_str = serde_json::to_string(args).unwrap().replace("\\", "\\\\").replace("'", "\\'"); let json_str = serde_json::to_string(args).unwrap().replace('\\', "\\\\").replace('\'', "\\'");
let code = format!(" let code = format!("
local args = vim.json.decode('{}') local args = vim.json.decode('{json_str}')
local buf = args.buf_id or vim.api.nvim_get_current_buf() local buf = args.buf_id or vim.api.nvim_get_current_buf()
local group = args.group or 'IncSearch' local group = args.group or 'IncSearch'
local ns = vim.api.nvim_create_namespace('antigravity_highlight') local ns = vim.api.nvim_create_namespace('antigravity_highlight')
@@ -942,16 +937,16 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
end, duration) end, duration)
end end
return 'Highlighted lines ' .. tostring(args.start_line) .. ' to ' .. tostring(args.end_line) return 'Highlighted lines ' .. tostring(args.start_line) .. ' to ' .. tostring(args.end_line)
", json_str); ");
match execute_nvim_lua(&code).await { match execute_nvim_lua(&code).await {
Ok(res) => send_text_result!(id.clone(), res), Ok(res) => send_text_result!(id.clone(), res),
Err(e) => send_error(id, -32603, &e).await, Err(e) => send_error(id, -32603, &e).await,
} }
} }
"nvim_get_messages" => { "nvim_get_messages" => {
let json_str = serde_json::to_string(args).unwrap().replace("\\", "\\\\").replace("'", "\\'"); let json_str = serde_json::to_string(args).unwrap().replace('\\', "\\\\").replace('\'', "\\'");
let code = format!(" let code = format!("
local args = vim.json.decode('{}') local args = vim.json.decode('{json_str}')
local msg = vim.fn.execute('messages') local msg = vim.fn.execute('messages')
local lines = vim.split(msg, '\\n') local lines = vim.split(msg, '\\n')
if args.tail and args.tail > 0 and #lines > args.tail then if args.tail and args.tail > 0 and #lines > args.tail then
@@ -962,7 +957,7 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
return table.concat(tail_lines, '\\n') return table.concat(tail_lines, '\\n')
end end
return msg return msg
", json_str); ");
match execute_nvim_lua(&code).await { match execute_nvim_lua(&code).await {
Ok(res) => send_text_result!(id.clone(), res), Ok(res) => send_text_result!(id.clone(), res),
Err(e) => send_error(id, -32603, &e).await, Err(e) => send_error(id, -32603, &e).await,
@@ -1001,10 +996,10 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
} }
} }
_ => { _ => {
if !id.is_null() { if id.is_null() {
send_error(id, -32601, "Method not found").await;
} else {
// Ignore notifications silently // Ignore notifications silently
} else {
send_error(id, -32601, "Method not found").await;
} }
} }
} }
@@ -1025,7 +1020,7 @@ fn init_logging(app_name: &str) -> tracing_appender::non_blocking::WorkerGuard {
.join(".gemini/mcp_memory/logs"); .join(".gemini/mcp_memory/logs");
std::fs::create_dir_all(&log_dir).unwrap_or_default(); std::fs::create_dir_all(&log_dir).unwrap_or_default();
let file_appender = tracing_appender::rolling::daily(log_dir, format!("{}.log", app_name)); let file_appender = tracing_appender::rolling::daily(log_dir, format!("{app_name}.log"));
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
let _ = tracing_subscriber::fmt() let _ = tracing_subscriber::fmt()
+3 -6
View File
@@ -12,10 +12,7 @@ fn main() {
let is_dirty = Command::new("git") let is_dirty = Command::new("git")
.args(["status", "--porcelain"]) .args(["status", "--porcelain"])
.output() .output().is_ok_and(|out| !out.stdout.is_empty());
.ok()
.map(|out| !out.stdout.is_empty())
.unwrap_or(false);
if is_dirty { if is_dirty {
git_hash.push_str("-dirty"); git_hash.push_str("-dirty");
@@ -23,8 +20,8 @@ fn main() {
let build_date = chrono::Local::now().format("%y.%m.%d.%H%M%S").to_string(); let build_date = chrono::Local::now().format("%y.%m.%d.%H%M%S").to_string();
let version = format!("{} ({})", build_date, git_hash); let version = format!("{build_date} ({git_hash})");
println!("cargo:rustc-env=APP_VERSION={}", version); println!("cargo:rustc-env=APP_VERSION={version}");
if std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default() == "windows" { if std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default() == "windows" {
let mut res = winres::WindowsResource::new(); let mut res = winres::WindowsResource::new();
+5 -7
View File
@@ -11,9 +11,9 @@ fn test_eager_tools_parity() {
let memory_source = std::fs::read_to_string(entry.path()).unwrap(); let memory_source = std::fs::read_to_string(entry.path()).unwrap();
let parts: Vec<&str> = memory_source.split("crate::mcp::tool_def").collect(); let parts: Vec<&str> = memory_source.split("crate::mcp::tool_def").collect();
for part in parts.iter().skip(1) { for part in parts.iter().skip(1) {
if let Some(start) = part.find("\"") { if let Some(start) = part.find('"') {
let rest = &part[start + 1..]; let rest = &part[start + 1..];
if let Some(end) = rest.find("\"") { if let Some(end) = rest.find('"') {
memory_tools.insert(rest[..end].to_string()); memory_tools.insert(rest[..end].to_string());
} }
} }
@@ -34,7 +34,7 @@ fn test_eager_tools_parity() {
&& let Some(start) = line.find("\"name\": \"") && let Some(start) = line.find("\"name\": \"")
{ {
let rest = &line[start + 9..]; let rest = &line[start + 9..];
if let Some(end) = rest.find("\"") { if let Some(end) = rest.find('"') {
nvim_tools.insert(rest[..end].to_string()); nvim_tools.insert(rest[..end].to_string());
} }
} }
@@ -57,8 +57,7 @@ fn test_eager_tools_parity() {
let name = tool.as_str().unwrap(); let name = tool.as_str().unwrap();
assert!( assert!(
memory_tools.contains(name), memory_tools.contains(name),
"Windows config Memory tool '{}' not implemented in handlers.rs!", "Windows config Memory tool '{name}' not implemented in handlers.rs!"
name
); );
} }
} }
@@ -68,8 +67,7 @@ fn test_eager_tools_parity() {
let name = tool.as_str().unwrap(); let name = tool.as_str().unwrap();
assert!( assert!(
nvim_tools.contains(name), nvim_tools.contains(name),
"Windows config Nvim tool '{}' not implemented in nvim-core!", "Windows config Nvim tool '{name}' not implemented in nvim-core!"
name
); );
} }
} }
+1 -1
View File
@@ -16,5 +16,5 @@ fn main() {
.unwrap_or_else(|| "unknown".to_string()); .unwrap_or_else(|| "unknown".to_string());
let version = format!("{} ({})", git_date.trim(), git_hash.trim()); let version = format!("{} ({})", git_date.trim(), git_hash.trim());
println!("cargo:rustc-env=APP_VERSION={}", version); println!("cargo:rustc-env=APP_VERSION={version}");
} }
+4 -5
View File
@@ -17,7 +17,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.danger_accept_invalid_certs(true) .danger_accept_invalid_certs(true)
.build()?; .build()?;
let sse_url = format!("{}/sse", target); let sse_url = format!("{target}/sse");
tracing::info!("Connecting to SSE: {}", sse_url); tracing::info!("Connecting to SSE: {}", sse_url);
@@ -59,9 +59,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing::info!("Received POST endpoint: {}", data_content); tracing::info!("Received POST endpoint: {}", data_content);
post_endpoint = Some(data_content); post_endpoint = Some(data_content);
break; break;
} else {
tracing::info!("Received early SSE data: {}", text);
} }
tracing::info!("Received early SSE data: {}", text);
} }
if post_endpoint.is_some() { if post_endpoint.is_some() {
break; break;
@@ -69,7 +68,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
let post_endpoint = post_endpoint.ok_or("Did not receive endpoint from SSE stream")?; let post_endpoint = post_endpoint.ok_or("Did not receive endpoint from SSE stream")?;
let post_url = format!("{}{}", target, post_endpoint); let post_url = format!("{target}{post_endpoint}");
let payload = r#"{"jsonrpc":"2.0","id":999,"method":"server/discover","params":{}}"#; let payload = r#"{"jsonrpc":"2.0","id":999,"method":"server/discover","params":{}}"#;
@@ -98,7 +97,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
_ = timeout.tick() => { _ = timeout.tick() => {
tracing::warn!("Timed out waiting for SSE response."); tracing::warn!("Timed out waiting for SSE response.");
} }
_ = async { () = async {
while let Some(chunk) = stream.next().await { while let Some(chunk) = stream.next().await {
if let Ok(bytes) = chunk { if let Ok(bytes) = chunk {
tracing::info!("Received SSE Chunk: {}", String::from_utf8_lossy(&bytes)); tracing::info!("Received SSE Chunk: {}", String::from_utf8_lossy(&bytes));
+7 -10
View File
@@ -14,31 +14,28 @@ pub fn extract_log_prefix(json_str: &str, is_response: bool) -> String {
let id = ID_REGEX let id = ID_REGEX
.captures(json_str) .captures(json_str)
.and_then(|c| c.get(1)) .and_then(|c| c.get(1))
.map(|m| m.as_str()) .map_or("null", |m| m.as_str());
.unwrap_or("null");
if is_response { if is_response {
let is_error = ERROR_REGEX.is_match(json_str) || IS_ERROR_REGEX.is_match(json_str); let is_error = ERROR_REGEX.is_match(json_str) || IS_ERROR_REGEX.is_match(json_str);
return format!("Response id={} [Error: {}]", id, is_error); return format!("Response id={id} [Error: {is_error}]");
} }
let method = METHOD_REGEX let method = METHOD_REGEX
.captures(json_str) .captures(json_str)
.and_then(|c| c.get(1)) .and_then(|c| c.get(1))
.map(|m| m.as_str()) .map_or("", |m| m.as_str());
.unwrap_or("");
if method == "tools/call" { if method == "tools/call" {
let tool = TOOL_REGEX let tool = TOOL_REGEX
.captures(json_str) .captures(json_str)
.and_then(|c| c.get(1)) .and_then(|c| c.get(1))
.map(|m| m.as_str()) .map_or("unknown", |m| m.as_str());
.unwrap_or("unknown"); format!("ToolCall[{tool}] id={id}")
format!("ToolCall[{}] id={}", tool, id)
} else if !method.is_empty() { } else if !method.is_empty() {
format!("Request[{}] id={}", method, id) format!("Request[{method}] id={id}")
} else if id != "null" { } else if id != "null" {
format!("Response id={}", id) format!("Response id={id}")
} else { } else {
"Message".to_string() "Message".to_string()
} }
+6 -6
View File
@@ -17,7 +17,7 @@ fn init_logging(app_name: &str) -> Option<tracing_appender::non_blocking::Worker
base_dir.push(".gemini/mcp_memory/logs"); base_dir.push(".gemini/mcp_memory/logs");
std::fs::create_dir_all(&base_dir).unwrap_or_default(); std::fs::create_dir_all(&base_dir).unwrap_or_default();
let file_appender = tracing_appender::rolling::daily(base_dir, format!("{}.log", app_name)); let file_appender = tracing_appender::rolling::daily(base_dir, format!("{app_name}.log"));
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
let _ = tracing_subscriber::fmt() let _ = tracing_subscriber::fmt()
@@ -45,16 +45,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = shutdown_tx.send(()).await; let _ = shutdown_tx.send(()).await;
}); });
let target_url = if cli.target != "http://localhost:3000" { let target_url = if cli.target == "http://localhost:3000" {
cli.target
} else {
let port = std::env::var("MCP_PORT").unwrap_or_else(|_| "3000".to_string()); let port = std::env::var("MCP_PORT").unwrap_or_else(|_| "3000".to_string());
format!("http://127.0.0.1:{}", port) format!("http://127.0.0.1:{port}")
} else {
cli.target
}; };
let ws_url = target_url let ws_url = target_url
.replace("http://", "ws://") .replace("http://", "ws://")
.replace("https://", "wss://"); .replace("https://", "wss://");
let ws_url = format!("{}/ws?client=proxy", ws_url); let ws_url = format!("{ws_url}/ws?client=proxy");
loop { loop {
if shutdown_rx.try_recv().is_ok() { if shutdown_rx.try_recv().is_ok() {
+11 -11
View File
@@ -14,7 +14,7 @@ impl Drop for ChildGuard {
fn send_message(stdin: &mut std::process::ChildStdin, msg: Value) { fn send_message(stdin: &mut std::process::ChildStdin, msg: Value) {
let s = serde_json::to_string(&msg).unwrap(); let s = serde_json::to_string(&msg).unwrap();
let payload = format!("{}\n", s); let payload = format!("{s}\n");
stdin.write_all(payload.as_bytes()).unwrap(); stdin.write_all(payload.as_bytes()).unwrap();
stdin.flush().unwrap(); stdin.flush().unwrap();
} }
@@ -56,9 +56,9 @@ async fn test_full_system_e2e_performance() {
let nvim_exe = debug_dir.join(format!("{}{}", nvim_name, std::env::consts::EXE_SUFFIX)); let nvim_exe = debug_dir.join(format!("{}{}", nvim_name, std::env::consts::EXE_SUFFIX));
let stub_exe = debug_dir.join(format!("mcp-memory-stub{}", std::env::consts::EXE_SUFFIX)); let stub_exe = debug_dir.join(format!("mcp-memory-stub{}", std::env::consts::EXE_SUFFIX));
assert!(server_exe.exists(), "Server not found at {:?}", server_exe); assert!(server_exe.exists(), "Server not found at {server_exe:?}");
assert!(nvim_exe.exists(), "Nvim not found at {:?}", nvim_exe); assert!(nvim_exe.exists(), "Nvim not found at {nvim_exe:?}");
assert!(stub_exe.exists(), "Stub not found at {:?}", stub_exe); assert!(stub_exe.exists(), "Stub not found at {stub_exe:?}");
// 1. Start Server // 1. Start Server
let _server = ChildGuard( let _server = ChildGuard(
@@ -83,7 +83,7 @@ async fn test_full_system_e2e_performance() {
let mut started = false; let mut started = false;
for _ in 0..30 { for _ in 0..30 {
if let Ok(resp) = client if let Ok(resp) = client
.get(format!("http://127.0.0.1:{}/health", test_port)) .get(format!("http://127.0.0.1:{test_port}/health"))
.send() .send()
.await .await
&& resp.status().is_success() && resp.status().is_success()
@@ -99,7 +99,7 @@ async fn test_full_system_e2e_performance() {
let mut stub = ChildGuard( let mut stub = ChildGuard(
Command::new(&stub_exe) Command::new(&stub_exe)
.arg("--target") .arg("--target")
.arg(format!("http://127.0.0.1:{}", test_port)) .arg(format!("http://127.0.0.1:{test_port}"))
.env("MCP_MEMORY_STORE_DIR", temp_dir.to_str().unwrap()) .env("MCP_MEMORY_STORE_DIR", temp_dir.to_str().unwrap())
.env("MCP_AUTH_TOKEN", test_auth_token) .env("MCP_AUTH_TOKEN", test_auth_token)
.env("RUST_LOG", "debug") .env("RUST_LOG", "debug")
@@ -144,7 +144,7 @@ async fn test_full_system_e2e_performance() {
send_message(&mut stub_stdin, tools_req); send_message(&mut stub_stdin, tools_req);
} else { } else {
let s = serde_json::to_string(&tools_req).unwrap(); let s = serde_json::to_string(&tools_req).unwrap();
stub_stdin.write_all(format!("{}\n", s).as_bytes()).unwrap(); stub_stdin.write_all(format!("{s}\n").as_bytes()).unwrap();
stub_stdin.flush().unwrap(); stub_stdin.flush().unwrap();
} }
@@ -156,7 +156,7 @@ async fn test_full_system_e2e_performance() {
assert_eq!(resp["id"], i); assert_eq!(resp["id"], i);
} }
let stub_duration = start_time.elapsed(); let stub_duration = start_time.elapsed();
println!("Stub 100 requests: {:?}", stub_duration); println!("Stub 100 requests: {stub_duration:?}");
// Send 100 concurrent-like sequential rapid requests to Win-Nvim // Send 100 concurrent-like sequential rapid requests to Win-Nvim
println!("Starting 100 requests to nvim..."); println!("Starting 100 requests to nvim...");
@@ -173,7 +173,7 @@ async fn test_full_system_e2e_performance() {
send_message(&mut nvim_stdin, tools_req); send_message(&mut nvim_stdin, tools_req);
} else { } else {
let s = serde_json::to_string(&tools_req).unwrap(); let s = serde_json::to_string(&tools_req).unwrap();
nvim_stdin.write_all(format!("{}\n", s).as_bytes()).unwrap(); nvim_stdin.write_all(format!("{s}\n").as_bytes()).unwrap();
nvim_stdin.flush().unwrap(); nvim_stdin.flush().unwrap();
} }
@@ -187,8 +187,8 @@ async fn test_full_system_e2e_performance() {
} }
let nvim_duration = start_time_nvim.elapsed(); let nvim_duration = start_time_nvim.elapsed();
println!("Stub 100 requests: {:?}", stub_duration); println!("Stub 100 requests: {stub_duration:?}");
println!("Win-Nvim 100 requests: {:?}", nvim_duration); println!("Win-Nvim 100 requests: {nvim_duration:?}");
let _ = std::fs::remove_dir_all(temp_dir); let _ = std::fs::remove_dir_all(temp_dir);
} }
+3 -5
View File
@@ -31,8 +31,7 @@ async fn test_stub_connection_refused() {
assert!( assert!(
res.is_ok(), res.is_ok(),
"Stub hung on connection refused! Took {:?}", "Stub hung on connection refused! Took {elapsed:?}"
elapsed
); );
} }
@@ -65,7 +64,7 @@ async fn test_stub_handles_eof_cleanly() {
let res = tokio::time::timeout(Duration::from_secs(5), child.wait()).await; let res = tokio::time::timeout(Duration::from_secs(5), child.wait()).await;
let elapsed = start.elapsed(); let elapsed = start.elapsed();
assert!(res.is_ok(), "Stub hung after EOF! Took {:?}", elapsed); assert!(res.is_ok(), "Stub hung after EOF! Took {elapsed:?}");
} }
#[tokio::test] #[tokio::test]
@@ -102,7 +101,6 @@ async fn test_stub_sse_fallback_failure() {
assert!( assert!(
res.is_ok(), res.is_ok(),
"Stub hung on fallback failure! Took {:?}", "Stub hung on fallback failure! Took {elapsed:?}"
elapsed
); );
} }
+1 -1
View File
@@ -16,5 +16,5 @@ fn main() {
.unwrap_or_else(|| "unknown".to_string()); .unwrap_or_else(|| "unknown".to_string());
let version = format!("{} ({})", git_date.trim(), git_hash.trim()); let version = format!("{} ({})", git_date.trim(), git_hash.trim());
println!("cargo:rustc-env=APP_VERSION={}", version); println!("cargo:rustc-env=APP_VERSION={version}");
} }
+1 -1
View File
@@ -4,7 +4,7 @@ use std::process::{Command, Stdio};
fn send_message(stdin: &mut std::process::ChildStdin, msg: Value) { fn send_message(stdin: &mut std::process::ChildStdin, msg: Value) {
let s = serde_json::to_string(&msg).unwrap(); let s = serde_json::to_string(&msg).unwrap();
stdin.write_all(format!("{}\n", s).as_bytes()).unwrap(); stdin.write_all(format!("{s}\n").as_bytes()).unwrap();
stdin.flush().unwrap(); stdin.flush().unwrap();
} }