feat: event-driven parity, Windows shell detection, dirty build timestamps, and gatekeeper integration
This commit is contained in:
1 parent
64857f9d5e
commit
f4dcf3acbf
33 files changed
+3501
-143
No files matched your search
+97
-6
@@ -319,6 +319,7 @@ static PENDING_REQUESTS: LazyLock<
|
||||
pub struct NvimState {
|
||||
pub cursor: String,
|
||||
pub active_buffer_id: u64,
|
||||
pub active_buffer_name: String,
|
||||
}
|
||||
|
||||
static NVIM_STATE: LazyLock<Arc<std::sync::Mutex<NvimState>>> =
|
||||
@@ -341,8 +342,27 @@ fn handle_nvim_notification(params: &[rmpv::Value]) {
|
||||
state.cursor = format!("Line: {}, Column: {}", row, col);
|
||||
}
|
||||
}
|
||||
"TextChanged" => {
|
||||
tracing::debug!("Shadow buffer text changed event received");
|
||||
"TextChanged" | "BufEnter" => {
|
||||
if params.len() > 1 {
|
||||
let buf_id = match ¶ms[1] {
|
||||
rmpv::Value::Integer(i) => i.as_u64().unwrap_or(0),
|
||||
_ => 0,
|
||||
};
|
||||
let buf_name = if params.len() > 2 {
|
||||
match ¶ms[2] {
|
||||
rmpv::Value::String(s) => s.as_str().unwrap_or("").to_string(),
|
||||
_ => String::new(),
|
||||
}
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let mut state = NVIM_STATE.lock().unwrap_or_else(|e| e.into_inner());
|
||||
state.active_buffer_id = buf_id;
|
||||
if !buf_name.is_empty() {
|
||||
state.active_buffer_name = buf_name;
|
||||
}
|
||||
}
|
||||
tracing::debug!("Neovim buffer changed/entered event received");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -591,7 +611,9 @@ async fn get_nvim_connection() -> Result<mpsc::Sender<NvimRequest>, String> {
|
||||
vim.api.nvim_create_autocmd({"TextChanged", "TextChangedI", "BufEnter"}, {
|
||||
group = "MCP_Tracking",
|
||||
callback = function()
|
||||
pcall(vim.rpcnotify, channel, "mcp_event", "TextChanged", vim.api.nvim_get_current_buf())
|
||||
local b = vim.api.nvim_get_current_buf()
|
||||
local n = vim.api.nvim_buf_get_name(b)
|
||||
pcall(vim.rpcnotify, channel, "mcp_event", "TextChanged", b, n)
|
||||
end
|
||||
})
|
||||
"#;
|
||||
@@ -1686,7 +1708,7 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
bufnr = 0
|
||||
end
|
||||
_G.gemini.preview_diff(diff_id, bufnr, start_line, end_line, lines)
|
||||
return "Preview added"
|
||||
return { status = "Preview added", diff_id = diff_id }
|
||||
else
|
||||
error("gemini UI not loaded")
|
||||
end
|
||||
@@ -1708,6 +1730,61 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
send_error(id, -32602, "Missing arguments: requires file_path, start_line, end_line, and preview_content").await;
|
||||
}
|
||||
}
|
||||
"prompt" | "prompt_user" => {
|
||||
let prompt_text = args
|
||||
.get("prompt")
|
||||
.or_else(|| args.get("prompt_text"))
|
||||
.and_then(|v| v.as_str());
|
||||
if let Some(prompt) = prompt_text {
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
let request_id = args
|
||||
.get("request_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|| {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_millis()
|
||||
.to_string()
|
||||
});
|
||||
|
||||
let options_arr = match args.get("options").and_then(|v| v.as_array()) {
|
||||
Some(arr) => {
|
||||
let rmp_arr: Vec<rmpv::Value> = arr
|
||||
.iter()
|
||||
.filter_map(|item| item.as_str())
|
||||
.map(|s| rmpv::Value::String(s.into()))
|
||||
.collect();
|
||||
rmpv::Value::Array(rmp_arr)
|
||||
}
|
||||
None => rmpv::Value::Nil,
|
||||
};
|
||||
|
||||
let lua_code = r#"
|
||||
local prompt_text, options, request_id = ...
|
||||
if _G.gemini and _G.gemini.prompt_user then
|
||||
_G.gemini.prompt_user(prompt_text, options, request_id)
|
||||
return { status = "Prompt displayed", request_id = request_id }
|
||||
else
|
||||
error("gemini UI not loaded")
|
||||
end
|
||||
"#;
|
||||
handle_lua_result!(
|
||||
id,
|
||||
execute_nvim_lua_with_args(
|
||||
lua_code,
|
||||
vec![
|
||||
rmpv::Value::String(prompt.into()),
|
||||
options_arr,
|
||||
rmpv::Value::String(request_id.into()),
|
||||
]
|
||||
)
|
||||
);
|
||||
} else {
|
||||
send_error(id, -32602, "Missing 'prompt' or 'prompt_text'").await;
|
||||
}
|
||||
}
|
||||
"extmark" => {
|
||||
if let (Some(line), Some(text)) = (
|
||||
args.get("line").and_then(serde_json::Value::as_i64),
|
||||
@@ -1996,8 +2073,22 @@ mod tests {
|
||||
]),
|
||||
];
|
||||
handle_nvim_notification(¶ms);
|
||||
let state = NVIM_STATE.lock().unwrap();
|
||||
assert_eq!(state.cursor, "Line: 15, Column: 4");
|
||||
{
|
||||
let state = NVIM_STATE.lock().unwrap();
|
||||
assert_eq!(state.cursor, "Line: 15, Column: 4");
|
||||
}
|
||||
|
||||
let text_params = vec![
|
||||
rmpv::Value::String("TextChanged".into()),
|
||||
rmpv::Value::Integer(157.into()),
|
||||
rmpv::Value::String("server/src/dashboard.ts".into()),
|
||||
];
|
||||
handle_nvim_notification(&text_params);
|
||||
{
|
||||
let state = NVIM_STATE.lock().unwrap();
|
||||
assert_eq!(state.active_buffer_id, 157);
|
||||
assert_eq!(state.active_buffer_name, "server/src/dashboard.ts");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
Reference in new issue
Block a user