refactor: DRY cleanup — extract shared helpers, remove duplication across tools, LSP, overlays, and runtime
Eliminate ~500 lines of duplicate code across 31 files by extracting shared functions, helpers, and consolidating repeated patterns. Highlights: - Toast helpers (toast_info/success/warning/error) on AppStateRest - push_event() helper for turn-event queue (19 callers consolidated) - log_write_edit_tool() shared fn (turn.rs + engine.rs ~50 lines saved) - resolve_api_key() shared fn (spawn.rs + provider.rs) - LSP call_positional() helper on LspClient - lsp_cursor_params() shared schema for 4 tool files -overlay_block() helper for consistent overlay title/border styling - cycle_selected_index(), path_not_found/a_directory() helpers - mark_dirty(), save_settings() on AppStateRest - Remove redundant Err(e) => Err(e) arms in LSP tools - Consolidate generate_workspace_tree (turn.rs → workspace.rs) - Simplify background-review wrapper args in auto/mod.rs Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b02754acd2
commit
9a6ab62562
@@ -50,6 +50,48 @@ fn known_extensions_for(language_id: &str) -> &[&'static str] {
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the standard `server` + `path` + `line` + `column` parameter schema
|
||||
/// used by cursor-based LSP tools (definition, references, completion).
|
||||
///
|
||||
/// When `with_language_id` is `true`, an optional `language_id` property is
|
||||
/// included (for tools like hover that pass it to `didOpen`).
|
||||
pub fn lsp_cursor_params(with_language_id: bool) -> serde_json::Value {
|
||||
let mut props = serde_json::json!({
|
||||
"server": {
|
||||
"type": "string",
|
||||
"description": "Name of the connected LSP server. Optional — auto-detected from the file extension if omitted."
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Path to the file (relative to workspace root)"
|
||||
},
|
||||
"line": {
|
||||
"type": "integer",
|
||||
"description": "Line number (0-based)"
|
||||
},
|
||||
"column": {
|
||||
"type": "integer",
|
||||
"description": "Column number (0-based)"
|
||||
}
|
||||
});
|
||||
if with_language_id {
|
||||
if let Some(obj) = props.as_object_mut() {
|
||||
obj.insert(
|
||||
"language_id".to_string(),
|
||||
serde_json::json!({
|
||||
"type": "string",
|
||||
"description": "Language identifier (e.g. 'rust', 'typescript'). Optional if already set via lsp_connect."
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": props,
|
||||
"required": ["path", "line", "column"]
|
||||
})
|
||||
}
|
||||
|
||||
/// Guess which connected LSP server should handle `path` based on its extension.
|
||||
///
|
||||
/// Flow: extract extension from `path` -> for each connected server, check
|
||||
@@ -132,7 +174,16 @@ fn resolve_server_name(ctx: &ToolCtx, args: &Value, path: &str) -> Result<String
|
||||
/// Opens the file on the server via `didOpen`, invokes the query closure,
|
||||
/// then closes the file via `didClose`. Returns the query result along with
|
||||
/// the 0-based line and column for post-processing.
|
||||
fn run_lsp_query<F, R>(ctx: &ToolCtx, args: &Value, op: F) -> Result<(R, u32, u32)>
|
||||
///
|
||||
/// When `text` is `Some`, the provided content is used instead of reading
|
||||
/// from disk (used by `LspDiagnostics` which receives the full text as an
|
||||
/// argument).
|
||||
fn run_lsp_query<F, R>(
|
||||
ctx: &ToolCtx,
|
||||
args: &Value,
|
||||
text: Option<&str>,
|
||||
op: F,
|
||||
) -> Result<(R, u32, u32)>
|
||||
where
|
||||
F: FnOnce(&mut crate::app::lsp::LspClient, &str, u32, u32) -> Result<R>,
|
||||
{
|
||||
@@ -150,8 +201,11 @@ where
|
||||
let abs_path = crate::tool::resolve_path(&ctx.workspaces, &rel_path)?;
|
||||
let uri = path_to_lsp_uri(&abs_path.to_string_lossy());
|
||||
|
||||
let file_content =
|
||||
std::fs::read_to_string(&abs_path).map_err(|e| anyhow!("failed to read file '{rel_path}': {e}"))?;
|
||||
let file_content = match text {
|
||||
Some(t) => t.to_string(),
|
||||
None => std::fs::read_to_string(&abs_path)
|
||||
.map_err(|e| anyhow!("failed to read file '{rel_path}': {e}"))?,
|
||||
};
|
||||
|
||||
let manager = ctx
|
||||
.lsp_manager
|
||||
|
||||
Reference in New Issue
Block a user