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
+126
-69
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)));
|
LazyLock::new(|| Arc::new(std::sync::Mutex::new(None)));
|
||||||
|
|
||||||
pub async fn spawn_headless_nvim() -> Result<String, String> {
|
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());
|
return Err("Error: Neovim is not installed or not in PATH. Cannot execute nvim tool. Fallback to basic terminal tools.".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+65
-42
@@ -169,18 +169,22 @@ static NVIM_STATE: LazyLock<Arc<std::sync::Mutex<NvimState>>> =
|
|||||||
LazyLock::new(|| Arc::new(std::sync::Mutex::new(NvimState::default())));
|
LazyLock::new(|| Arc::new(std::sync::Mutex::new(NvimState::default())));
|
||||||
|
|
||||||
fn handle_nvim_notification(params: &[rmpv::Value]) {
|
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] {
|
if let rmpv::Value::String(event) = ¶ms[0] {
|
||||||
match event.as_str().unwrap_or("") {
|
match event.as_str().unwrap_or("") {
|
||||||
"CursorMoved" => {
|
"CursorMoved" => {
|
||||||
if params.len() > 1
|
if params.len() > 1
|
||||||
&& let rmpv::Value::Array(pos) = ¶ms[1]
|
&& let rmpv::Value::Array(pos) = ¶ms[1]
|
||||||
&& pos.len() >= 4
|
&& pos.len() >= 4
|
||||||
&& let (rmpv::Value::Integer(row), rmpv::Value::Integer(col)) = (&pos[1], &pos[2]) {
|
&& let (rmpv::Value::Integer(row), rmpv::Value::Integer(col)) =
|
||||||
let mut state = NVIM_STATE.lock().unwrap_or_else(|e| e.into_inner());
|
(&pos[1], &pos[2])
|
||||||
state.cursor = format!("Line: {}, Column: {}", row, col);
|
{
|
||||||
}
|
let mut state = NVIM_STATE.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
},
|
state.cursor = format!("Line: {}, Column: {}", row, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
"TextChanged" => {
|
"TextChanged" => {
|
||||||
tracing::debug!("Shadow buffer text changed event received");
|
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());
|
let mut conn_lock = NVIM_CONN.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
if let Some(sender) = conn_lock.as_ref() {
|
if let Some(sender) = conn_lock.as_ref()
|
||||||
if !sender.is_closed() {
|
&& !sender.is_closed()
|
||||||
let current_socket = {
|
{
|
||||||
let active_lock = ACTIVE_SOCKET.lock().unwrap_or_else(|e| e.into_inner());
|
let current_socket = {
|
||||||
active_lock.clone()
|
let active_lock = ACTIVE_SOCKET.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
};
|
active_lock.clone()
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(ref interactive) = interactive_socket {
|
if let Some(ref interactive) = interactive_socket {
|
||||||
if Some(interactive.clone()) != current_socket {
|
if Some(interactive.clone()) != current_socket {
|
||||||
tracing::info!("Interactive Preemption: New Neovim instance detected at {}. Disconnecting from current.", interactive);
|
tracing::info!(
|
||||||
should_kill_headless = true;
|
"Interactive Preemption: New Neovim instance detected at {}. Disconnecting from current.",
|
||||||
*conn_lock = None;
|
interactive
|
||||||
{
|
);
|
||||||
let mut active_lock2 = ACTIVE_SOCKET.lock().unwrap_or_else(|e| e.into_inner());
|
should_kill_headless = true;
|
||||||
*active_lock2 = None;
|
*conn_lock = None;
|
||||||
}
|
{
|
||||||
} else {
|
let mut active_lock2 =
|
||||||
return Ok(sender.clone());
|
ACTIVE_SOCKET.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
|
*active_lock2 = None;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Ok(sender.clone());
|
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?
|
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)]
|
#[cfg(windows)]
|
||||||
let stream = {
|
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) {
|
if let Some((_, reply_sender)) = pending_clone2.remove(&msgid) {
|
||||||
let _ = reply_sender.send(Ok(val));
|
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]
|
&& let rmpv::Value::String(method) = &arr[1]
|
||||||
&& method.as_str().unwrap_or("") == "mcp_event"
|
&& method.as_str().unwrap_or("") == "mcp_event"
|
||||||
&& let rmpv::Value::Array(params) = &arr[2] {
|
&& let rmpv::Value::Array(params) = &arr[2]
|
||||||
handle_nvim_notification(params);
|
{
|
||||||
}
|
handle_nvim_notification(params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue;
|
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 (reply_tx, _reply_rx) = tokio::sync::oneshot::channel();
|
||||||
let _ = tx_clone.send(NvimRequest {
|
let _ = tx_clone
|
||||||
msgid,
|
.send(NvimRequest {
|
||||||
req,
|
msgid,
|
||||||
reply: reply_tx,
|
req,
|
||||||
}).await;
|
reply: reply_tx,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
tracing::info!("Injected bidirectional event tracking autocmds into Neovim");
|
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,
|
id,
|
||||||
result: Some(json!({"resources": []})),
|
result: Some(json!({"resources": []})),
|
||||||
error: None,
|
error: None,
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
"resources/templates/list" => {
|
"resources/templates/list" => {
|
||||||
send_response(JsonRpcResponse {
|
send_response(JsonRpcResponse {
|
||||||
@@ -789,7 +805,8 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
|||||||
id,
|
id,
|
||||||
result: Some(json!({"resourceTemplates": []})),
|
result: Some(json!({"resourceTemplates": []})),
|
||||||
error: None,
|
error: None,
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
"prompts/list" => {
|
"prompts/list" => {
|
||||||
send_response(JsonRpcResponse {
|
send_response(JsonRpcResponse {
|
||||||
@@ -797,7 +814,8 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
|||||||
id,
|
id,
|
||||||
result: Some(json!({"prompts": []})),
|
result: Some(json!({"prompts": []})),
|
||||||
error: None,
|
error: None,
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
"tools/list" => {
|
"tools/list" => {
|
||||||
@@ -1431,8 +1449,10 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
|||||||
|
|
||||||
"nvim_read_file" => {
|
"nvim_read_file" => {
|
||||||
if let Some(file) = args.get("file").and_then(|v| v.as_str()) {
|
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 start_line =
|
||||||
let end_line = args.get("end_line").and_then(|v| v.as_i64()).unwrap_or(-1);
|
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 escaped_file = file.replace('\\', "\\\\").replace('"', "\\\"");
|
||||||
let code = format!("
|
let code = format!("
|
||||||
@@ -1466,7 +1486,8 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
|||||||
args.get("pattern").and_then(|v| v.as_str()),
|
args.get("pattern").and_then(|v| v.as_str()),
|
||||||
) {
|
) {
|
||||||
let escaped_file = file.replace('\\', "\\\\").replace('"', "\\\"");
|
let escaped_file = file.replace('\\', "\\\\").replace('"', "\\\"");
|
||||||
let escaped_pattern = pattern.replace('\\', "\\\\").replace('"', "\\\"");
|
let escaped_pattern =
|
||||||
|
pattern.replace('\\', "\\\\").replace('"', "\\\"");
|
||||||
let code = format!("
|
let code = format!("
|
||||||
local file = \"{escaped_file}\"
|
local file = \"{escaped_file}\"
|
||||||
local pattern = \"{escaped_pattern}\"
|
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()
|
let exe_path = std::env::current_exe()
|
||||||
.map(|p| p.to_string_lossy().to_string())
|
.map(|p| p.to_string_lossy().to_string())
|
||||||
.unwrap_or_else(|_| "unknown".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!(
|
let info = format!(
|
||||||
"Server: {}\nVersion: {}\nOS: {}\nExecutable: {}\nBackend Socket: {}",
|
"Server: {}\nVersion: {}\nOS: {}\nExecutable: {}\nBackend Socket: {}",
|
||||||
app_name, app_version, os, exe_path, socket
|
app_name, app_version, os, exe_path, socket
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ pub async fn wait_for_event_handler(
|
|||||||
loop {
|
loop {
|
||||||
match rx.recv().await {
|
match rx.recv().await {
|
||||||
Ok(event) => {
|
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
|
let session_matches = session_id
|
||||||
.as_ref()
|
.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 {
|
if topic_matches && session_matches {
|
||||||
return axum::Json(event);
|
return axum::Json(event);
|
||||||
|
|||||||
+11
-11
@@ -50,17 +50,17 @@ pub async fn nvim_telemetry_handler(
|
|||||||
let _ = tx.try_send(msg_str.clone());
|
let _ = tx.try_send(msg_str.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload.event == "BufWritePost" {
|
if payload.event == "BufWritePost"
|
||||||
if let Some(ref file_path) = payload.file {
|
&& let Some(ref file_path) = payload.file
|
||||||
let normalized_file = file_path.replace("\\", "/");
|
{
|
||||||
let topic = format!("nvim:save:{}", normalized_file);
|
let normalized_file = file_path.replace("\\", "/");
|
||||||
let event = crate::state::GenericEvent {
|
let topic = format!("nvim:save:{}", normalized_file);
|
||||||
topic,
|
let event = crate::state::GenericEvent {
|
||||||
session_id: Some(payload.session_id.clone()),
|
topic,
|
||||||
payload: serde_json::json!(&payload),
|
session_id: Some(payload.session_id.clone()),
|
||||||
};
|
payload: serde_json::json!(&payload),
|
||||||
let _ = state.handler.state.event_bus_tx.send(event);
|
};
|
||||||
}
|
let _ = state.handler.state.event_bus_tx.send(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
axum::Json(serde_json::json!({"status": "ok"}))
|
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> {
|
async fn execute(&self, _args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||||
let data = state
|
state
|
||||||
.prefs
|
.prefs
|
||||||
.read_with(|prefs| serde_json::to_string(prefs).map_err(|e| e.to_string()));
|
.read_with(|prefs| serde_json::to_string(prefs).map_err(|e| e.to_string()))
|
||||||
data
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ impl McpTool for ListContextWorkspacesHandler {
|
|||||||
let data = state.context_workspaces.read_with(|ws| {
|
let data = state.context_workspaces.read_with(|ws| {
|
||||||
let filtered: Vec<_> = ws
|
let filtered: Vec<_> = ws
|
||||||
.iter()
|
.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();
|
.collect();
|
||||||
serde_json::to_string(&filtered).map_err(|e| e.to_string())
|
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 res_list = handler.handle_request(req_list_res).await.unwrap();
|
||||||
let resources_arr = res_list["result"]["resources"].as_array().unwrap();
|
let resources_arr = res_list["result"]["resources"].as_array().unwrap();
|
||||||
assert!(resources_arr.iter().any(|r| r["uri"] == "memory://tasks/active"));
|
assert!(
|
||||||
assert!(resources_arr.iter().any(|r| r["uri"] == "memory://pinned_files"));
|
resources_arr
|
||||||
|
.iter()
|
||||||
|
.any(|r| r["uri"] == "memory://tasks/active")
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
resources_arr
|
||||||
|
.iter()
|
||||||
|
.any(|r| r["uri"] == "memory://pinned_files")
|
||||||
|
);
|
||||||
|
|
||||||
// Test resources/read
|
// Test resources/read
|
||||||
let req_read_res = json!({
|
let req_read_res = json!({
|
||||||
@@ -600,8 +608,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
let res_read = handler.handle_request(req_read_res).await.unwrap();
|
let res_read = handler.handle_request(req_read_res).await.unwrap();
|
||||||
assert_eq!(res_read["result"]["contents"][0]["uri"], "memory://tasks/active");
|
assert_eq!(
|
||||||
assert!(res_read["result"]["contents"][0]["text"].as_str().unwrap().contains("[]")); // Empty tasks
|
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
|
// Test prompts/list
|
||||||
let req_list_prompts = json!({
|
let req_list_prompts = json!({
|
||||||
@@ -627,7 +643,12 @@ mod tests {
|
|||||||
let res_get = handler.handle_request(req_get_prompt).await.unwrap();
|
let res_get = handler.handle_request(req_get_prompt).await.unwrap();
|
||||||
let messages = res_get["result"]["messages"].as_array().unwrap();
|
let messages = res_get["result"]["messages"].as_array().unwrap();
|
||||||
assert_eq!(messages[0]["role"], "user");
|
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]
|
#[tokio::test]
|
||||||
|
|||||||
+3
-1
@@ -28,7 +28,9 @@ impl<T: DeserializeOwned + Default + Serialize + Clone + Send + Sync + 'static>
|
|||||||
let key_inner = key_clone.clone();
|
let key_inner = key_clone.clone();
|
||||||
let json_data = {
|
let json_data = {
|
||||||
let lock = cache_clone.read().unwrap_or_else(|e| e.into_inner());
|
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 {
|
if let Some(json_data) = json_data {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use std::io::{BufRead, BufReader, Write, Read};
|
use std::io::{BufRead, BufReader, Read, Write};
|
||||||
use std::process::{Command, Stdio};
|
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) {
|
||||||
@@ -161,7 +161,11 @@ fn test_mcp_initialization_and_tools_list() {
|
|||||||
|
|
||||||
send_message(&mut stdin, call_req);
|
send_message(&mut stdin, call_req);
|
||||||
let call_resp = read_message(&mut stdout).expect("Failed to read tools/call response");
|
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["jsonrpc"], "2.0");
|
||||||
assert_eq!(call_resp["id"], req_id);
|
assert_eq!(call_resp["id"], req_id);
|
||||||
}
|
}
|
||||||
@@ -202,5 +206,9 @@ fn test_mcp_initialization_and_tools_list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let status = child.wait().expect("Failed to wait on child");
|
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