use std::path::PathBuf;
use crate::tools::apply_patch::preflight_apply_patch;
use super::*;
pub(super) fn edited_paths_for_tool(tool_name: &str, input: &serde_json::Value) -> Vec<PathBuf> {
let semantic = crate::tools::canonical_action::canonical_action_alias(tool_name, input);
match semantic {
"edit_file" | "write_file" => {
if let Some(path) = input.get("path").and_then(|v| v.as_str()) {
vec![PathBuf::from(path)]
} else {
Vec::new()
}
}
"apply_patch" => preflight_apply_patch(input)
.map(|preflight| {
preflight
.touched_files
.into_iter()
.map(PathBuf::from)
.collect()
})
.unwrap_or_default(),
_ => Vec::new(),
}
}
impl Engine {
pub(super) async fn run_post_edit_lsp_hook(
&mut self,
tool_name: &str,
tool_input: &serde_json::Value,
) {
if !self.lsp_manager.config().enabled {
return;
}
let paths = edited_paths_for_tool(tool_name, tool_input);
let mut found = 0usize;
let mut files = 0usize;
for path in paths {
let absolute = if path.is_absolute() {
path.clone()
} else {
self.session.workspace.join(&path)
};
let seq = self.turn_counter;
if let Some(block) = self.lsp_manager.diagnostics_for(&absolute, seq).await {
found = found.saturating_add(block.items.len());
files = files.saturating_add(1);
self.pending_lsp_blocks.push(block);
}
}
if found > 0 {
let _ = self
.tx_event
.send(Event::LspRepairUpdate {
diagnostics_found: found,
files,
injected: false,
})
.await;
}
}
pub(super) async fn flush_pending_lsp_diagnostics(&mut self) {
if self.pending_lsp_blocks.is_empty() {
return;
}
let blocks = std::mem::take(&mut self.pending_lsp_blocks);
let found: usize = blocks.iter().map(|b| b.items.len()).sum();
let files = blocks.len();
let rendered = crate::lsp::render_blocks(&blocks);
if rendered.is_empty() {
return;
}
self.add_session_message(self.runtime_text_message_with_turn_metadata(
rendered,
crate::core::ops::UserInputProvenance::Runtime,
))
.await;
let _ = self
.tx_event
.send(Event::LspRepairUpdate {
diagnostics_found: found,
files,
injected: true,
})
.await;
}
}
#[cfg(test)]
mod primitive_name_tests {
use super::*;
use serde_json::json;
#[test]
fn lowercase_file_mutations_reach_the_lsp_hook() {
for name in ["write", "edit", "write_file", "edit_file"] {
assert_eq!(
edited_paths_for_tool(name, &json!({"path": "src/lib.rs"})),
vec![PathBuf::from("src/lib.rs")]
);
}
}
}