style(clippy): auto-fix code style issues and unnecessary map_or allocations detected by cargo clippy
This commit is contained in:
1 parent
febd48c65d
commit
706e9ad172
9 files changed
+131
-74
No files matched your search
@@ -8,7 +8,11 @@ pub static HEADLESS_PROC: LazyLock<Arc<std::sync::Mutex<Option<tokio::process::C
|
||||
LazyLock::new(|| Arc::new(std::sync::Mutex::new(None)));
|
||||
|
||||
pub async fn spawn_headless_nvim() -> Result<String, String> {
|
||||
if std::process::Command::new("nvim").arg("--version").output().is_err() {
|
||||
if std::process::Command::new("nvim")
|
||||
.arg("--version")
|
||||
.output()
|
||||
.is_err()
|
||||
{
|
||||
return Err("Error: Neovim is not installed or not in PATH. Cannot execute nvim tool. Fallback to basic terminal tools.".to_string());
|
||||
}
|
||||
|
||||
|
||||
+69
-46
@@ -64,7 +64,7 @@ async fn is_interactive(socket_path: &str) -> bool {
|
||||
if socket_path.contains("agy-headless-nvim") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if let Ok(output) = tokio::process::Command::new("nvim")
|
||||
.arg("--server")
|
||||
.arg(socket_path)
|
||||
@@ -169,18 +169,22 @@ static NVIM_STATE: LazyLock<Arc<std::sync::Mutex<NvimState>>> =
|
||||
LazyLock::new(|| Arc::new(std::sync::Mutex::new(NvimState::default())));
|
||||
|
||||
fn handle_nvim_notification(params: &[rmpv::Value]) {
|
||||
if params.is_empty() { return; }
|
||||
if params.is_empty() {
|
||||
return;
|
||||
}
|
||||
if let rmpv::Value::String(event) = ¶ms[0] {
|
||||
match event.as_str().unwrap_or("") {
|
||||
"CursorMoved" => {
|
||||
if params.len() > 1
|
||||
&& let rmpv::Value::Array(pos) = ¶ms[1]
|
||||
&& pos.len() >= 4
|
||||
&& let (rmpv::Value::Integer(row), rmpv::Value::Integer(col)) = (&pos[1], &pos[2]) {
|
||||
let mut state = NVIM_STATE.lock().unwrap_or_else(|e| e.into_inner());
|
||||
state.cursor = format!("Line: {}, Column: {}", row, col);
|
||||
}
|
||||
},
|
||||
&& pos.len() >= 4
|
||||
&& let (rmpv::Value::Integer(row), rmpv::Value::Integer(col)) =
|
||||
(&pos[1], &pos[2])
|
||||
{
|
||||
let mut state = NVIM_STATE.lock().unwrap_or_else(|e| e.into_inner());
|
||||
state.cursor = format!("Line: {}, Column: {}", row, col);
|
||||
}
|
||||
}
|
||||
"TextChanged" => {
|
||||
tracing::debug!("Shadow buffer text changed event received");
|
||||
}
|
||||
@@ -195,28 +199,32 @@ async fn get_nvim_connection() -> Result<mpsc::Sender<NvimRequest>, String> {
|
||||
|
||||
{
|
||||
let mut conn_lock = NVIM_CONN.lock().unwrap_or_else(|e| e.into_inner());
|
||||
if let Some(sender) = conn_lock.as_ref() {
|
||||
if !sender.is_closed() {
|
||||
let current_socket = {
|
||||
let active_lock = ACTIVE_SOCKET.lock().unwrap_or_else(|e| e.into_inner());
|
||||
active_lock.clone()
|
||||
};
|
||||
if let Some(sender) = conn_lock.as_ref()
|
||||
&& !sender.is_closed()
|
||||
{
|
||||
let current_socket = {
|
||||
let active_lock = ACTIVE_SOCKET.lock().unwrap_or_else(|e| e.into_inner());
|
||||
active_lock.clone()
|
||||
};
|
||||
|
||||
if let Some(ref interactive) = interactive_socket {
|
||||
if Some(interactive.clone()) != current_socket {
|
||||
tracing::info!("Interactive Preemption: New Neovim instance detected at {}. Disconnecting from current.", interactive);
|
||||
should_kill_headless = true;
|
||||
*conn_lock = None;
|
||||
{
|
||||
let mut active_lock2 = ACTIVE_SOCKET.lock().unwrap_or_else(|e| e.into_inner());
|
||||
*active_lock2 = None;
|
||||
}
|
||||
} else {
|
||||
return Ok(sender.clone());
|
||||
if let Some(ref interactive) = interactive_socket {
|
||||
if Some(interactive.clone()) != current_socket {
|
||||
tracing::info!(
|
||||
"Interactive Preemption: New Neovim instance detected at {}. Disconnecting from current.",
|
||||
interactive
|
||||
);
|
||||
should_kill_headless = true;
|
||||
*conn_lock = None;
|
||||
{
|
||||
let mut active_lock2 =
|
||||
ACTIVE_SOCKET.lock().unwrap_or_else(|e| e.into_inner());
|
||||
*active_lock2 = None;
|
||||
}
|
||||
} else {
|
||||
return Ok(sender.clone());
|
||||
}
|
||||
} else {
|
||||
return Ok(sender.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,7 +246,10 @@ async fn get_nvim_connection() -> Result<mpsc::Sender<NvimRequest>, String> {
|
||||
spawn_headless_nvim().await?
|
||||
};
|
||||
|
||||
tracing::info!("Establishing new persistent connection to Neovim at {}", socket_path);
|
||||
tracing::info!(
|
||||
"Establishing new persistent connection to Neovim at {}",
|
||||
socket_path
|
||||
);
|
||||
|
||||
#[cfg(windows)]
|
||||
let stream = {
|
||||
@@ -308,12 +319,14 @@ async fn get_nvim_connection() -> Result<mpsc::Sender<NvimRequest>, String> {
|
||||
if let Some((_, reply_sender)) = pending_clone2.remove(&msgid) {
|
||||
let _ = reply_sender.send(Ok(val));
|
||||
}
|
||||
} else if arr.len() >= 3 && arr[0] == rmpv::Value::Integer(2.into())
|
||||
} else if arr.len() >= 3
|
||||
&& arr[0] == rmpv::Value::Integer(2.into())
|
||||
&& let rmpv::Value::String(method) = &arr[1]
|
||||
&& method.as_str().unwrap_or("") == "mcp_event"
|
||||
&& let rmpv::Value::Array(params) = &arr[2] {
|
||||
handle_nvim_notification(params);
|
||||
}
|
||||
&& method.as_str().unwrap_or("") == "mcp_event"
|
||||
&& let rmpv::Value::Array(params) = &arr[2]
|
||||
{
|
||||
handle_nvim_notification(params);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -407,11 +420,13 @@ async fn get_nvim_connection() -> Result<mpsc::Sender<NvimRequest>, String> {
|
||||
]),
|
||||
]);
|
||||
let (reply_tx, _reply_rx) = tokio::sync::oneshot::channel();
|
||||
let _ = tx_clone.send(NvimRequest {
|
||||
msgid,
|
||||
req,
|
||||
reply: reply_tx,
|
||||
}).await;
|
||||
let _ = tx_clone
|
||||
.send(NvimRequest {
|
||||
msgid,
|
||||
req,
|
||||
reply: reply_tx,
|
||||
})
|
||||
.await;
|
||||
tracing::info!("Injected bidirectional event tracking autocmds into Neovim");
|
||||
});
|
||||
|
||||
@@ -781,7 +796,8 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
id,
|
||||
result: Some(json!({"resources": []})),
|
||||
error: None,
|
||||
}).await;
|
||||
})
|
||||
.await;
|
||||
}
|
||||
"resources/templates/list" => {
|
||||
send_response(JsonRpcResponse {
|
||||
@@ -789,7 +805,8 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
id,
|
||||
result: Some(json!({"resourceTemplates": []})),
|
||||
error: None,
|
||||
}).await;
|
||||
})
|
||||
.await;
|
||||
}
|
||||
"prompts/list" => {
|
||||
send_response(JsonRpcResponse {
|
||||
@@ -797,7 +814,8 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
id,
|
||||
result: Some(json!({"prompts": []})),
|
||||
error: None,
|
||||
}).await;
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
"tools/list" => {
|
||||
@@ -1428,12 +1446,14 @@ 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 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}\"
|
||||
@@ -1459,14 +1479,15 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
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 escaped_pattern =
|
||||
pattern.replace('\\', "\\\\").replace('"', "\\\"");
|
||||
let code = format!("
|
||||
local file = \"{escaped_file}\"
|
||||
local pattern = \"{escaped_pattern}\"
|
||||
@@ -1545,7 +1566,9 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
let exe_path = std::env::current_exe()
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.unwrap_or_else(|_| "unknown".to_string());
|
||||
let socket = get_socket_path().await.unwrap_or_else(|e| format!("Error: {}", e));
|
||||
let socket = get_socket_path()
|
||||
.await
|
||||
.unwrap_or_else(|e| format!("Error: {}", e));
|
||||
let info = format!(
|
||||
"Server: {}\nVersion: {}\nOS: {}\nExecutable: {}\nBackend Socket: {}",
|
||||
app_name, app_version, os, exe_path, socket
|
||||
|
||||
@@ -17,10 +17,10 @@ pub async fn wait_for_event_handler(
|
||||
loop {
|
||||
match rx.recv().await {
|
||||
Ok(event) => {
|
||||
let topic_matches = topic.as_ref().map_or(true, |t| t == &event.topic);
|
||||
let topic_matches = topic.as_ref().is_none_or(|t| t == &event.topic);
|
||||
let session_matches = session_id
|
||||
.as_ref()
|
||||
.map_or(true, |s| Some(s) == event.session_id.as_ref());
|
||||
.is_none_or(|s| Some(s) == event.session_id.as_ref());
|
||||
|
||||
if topic_matches && session_matches {
|
||||
return axum::Json(event);
|
||||
|
||||
+11
-11
@@ -50,17 +50,17 @@ pub async fn nvim_telemetry_handler(
|
||||
let _ = tx.try_send(msg_str.clone());
|
||||
}
|
||||
|
||||
if payload.event == "BufWritePost" {
|
||||
if let Some(ref file_path) = payload.file {
|
||||
let normalized_file = file_path.replace("\\", "/");
|
||||
let topic = format!("nvim:save:{}", normalized_file);
|
||||
let event = crate::state::GenericEvent {
|
||||
topic,
|
||||
session_id: Some(payload.session_id.clone()),
|
||||
payload: serde_json::json!(&payload),
|
||||
};
|
||||
let _ = state.handler.state.event_bus_tx.send(event);
|
||||
}
|
||||
if payload.event == "BufWritePost"
|
||||
&& let Some(ref file_path) = payload.file
|
||||
{
|
||||
let normalized_file = file_path.replace("\\", "/");
|
||||
let topic = format!("nvim:save:{}", normalized_file);
|
||||
let event = crate::state::GenericEvent {
|
||||
topic,
|
||||
session_id: Some(payload.session_id.clone()),
|
||||
payload: serde_json::json!(&payload),
|
||||
};
|
||||
let _ = state.handler.state.event_bus_tx.send(event);
|
||||
}
|
||||
|
||||
axum::Json(serde_json::json!({"status": "ok"}))
|
||||
|
||||
@@ -274,10 +274,9 @@ impl McpTool for ReadPreferencesHandler {
|
||||
}
|
||||
|
||||
async fn execute(&self, _args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
let data = state
|
||||
state
|
||||
.prefs
|
||||
.read_with(|prefs| serde_json::to_string(prefs).map_err(|e| e.to_string()));
|
||||
data
|
||||
.read_with(|prefs| serde_json::to_string(prefs).map_err(|e| e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -275,7 +275,7 @@ impl McpTool for ListContextWorkspacesHandler {
|
||||
let data = state.context_workspaces.read_with(|ws| {
|
||||
let filtered: Vec<_> = ws
|
||||
.iter()
|
||||
.filter(|w| req.namespace.as_ref().map_or(true, |ns| &w.namespace == ns))
|
||||
.filter(|w| req.namespace.as_ref().is_none_or(|ns| &w.namespace == ns))
|
||||
.collect();
|
||||
serde_json::to_string(&filtered).map_err(|e| e.to_string())
|
||||
})?;
|
||||
|
||||
+26
-5
@@ -587,8 +587,16 @@ mod tests {
|
||||
});
|
||||
let res_list = handler.handle_request(req_list_res).await.unwrap();
|
||||
let resources_arr = res_list["result"]["resources"].as_array().unwrap();
|
||||
assert!(resources_arr.iter().any(|r| r["uri"] == "memory://tasks/active"));
|
||||
assert!(resources_arr.iter().any(|r| r["uri"] == "memory://pinned_files"));
|
||||
assert!(
|
||||
resources_arr
|
||||
.iter()
|
||||
.any(|r| r["uri"] == "memory://tasks/active")
|
||||
);
|
||||
assert!(
|
||||
resources_arr
|
||||
.iter()
|
||||
.any(|r| r["uri"] == "memory://pinned_files")
|
||||
);
|
||||
|
||||
// Test resources/read
|
||||
let req_read_res = json!({
|
||||
@@ -600,8 +608,16 @@ mod tests {
|
||||
}
|
||||
});
|
||||
let res_read = handler.handle_request(req_read_res).await.unwrap();
|
||||
assert_eq!(res_read["result"]["contents"][0]["uri"], "memory://tasks/active");
|
||||
assert!(res_read["result"]["contents"][0]["text"].as_str().unwrap().contains("[]")); // Empty tasks
|
||||
assert_eq!(
|
||||
res_read["result"]["contents"][0]["uri"],
|
||||
"memory://tasks/active"
|
||||
);
|
||||
assert!(
|
||||
res_read["result"]["contents"][0]["text"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("[]")
|
||||
); // Empty tasks
|
||||
|
||||
// Test prompts/list
|
||||
let req_list_prompts = json!({
|
||||
@@ -627,7 +643,12 @@ mod tests {
|
||||
let res_get = handler.handle_request(req_get_prompt).await.unwrap();
|
||||
let messages = res_get["result"]["messages"].as_array().unwrap();
|
||||
assert_eq!(messages[0]["role"], "user");
|
||||
assert!(messages[0]["content"]["text"].as_str().unwrap().contains("standup report"));
|
||||
assert!(
|
||||
messages[0]["content"]["text"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("standup report")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
+3
-1
@@ -28,7 +28,9 @@ impl<T: DeserializeOwned + Default + Serialize + Clone + Send + Sync + 'static>
|
||||
let key_inner = key_clone.clone();
|
||||
let json_data = {
|
||||
let lock = cache_clone.read().unwrap_or_else(|e| e.into_inner());
|
||||
serde_json::to_vec(&*lock).map_err(|e| tracing::error!("Failed to serialize memory store: {}", e)).ok()
|
||||
serde_json::to_vec(&*lock)
|
||||
.map_err(|e| tracing::error!("Failed to serialize memory store: {}", e))
|
||||
.ok()
|
||||
};
|
||||
|
||||
if let Some(json_data) = json_data {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use serde_json::{Value, json};
|
||||
use std::io::{BufRead, BufReader, Write, Read};
|
||||
use std::io::{BufRead, BufReader, Read, Write};
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn send_message(stdin: &mut std::process::ChildStdin, msg: Value) {
|
||||
@@ -161,7 +161,11 @@ fn test_mcp_initialization_and_tools_list() {
|
||||
|
||||
send_message(&mut stdin, call_req);
|
||||
let call_resp = read_message(&mut stdout).expect("Failed to read tools/call response");
|
||||
println!("Response for {}: {}", tool_name, serde_json::to_string(&call_resp).unwrap());
|
||||
println!(
|
||||
"Response for {}: {}",
|
||||
tool_name,
|
||||
serde_json::to_string(&call_resp).unwrap()
|
||||
);
|
||||
assert_eq!(call_resp["jsonrpc"], "2.0");
|
||||
assert_eq!(call_resp["id"], req_id);
|
||||
}
|
||||
@@ -200,7 +204,11 @@ fn test_mcp_initialization_and_tools_list() {
|
||||
let _ = stderr.read_to_string(&mut stderr_output);
|
||||
println!("Child STDERR: {}", stderr_output);
|
||||
}
|
||||
|
||||
|
||||
let status = child.wait().expect("Failed to wait on child");
|
||||
assert!(status.success(), "Child process did not exit successfully. Stderr: {}", stderr_output);
|
||||
assert!(
|
||||
status.success(),
|
||||
"Child process did not exit successfully. Stderr: {}",
|
||||
stderr_output
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user