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:
asepharyana
2026-07-18 03:18:27 +07:00
co-authored by Claude Opus 4.8
parent b02754acd2
commit 9a6ab62562
31 changed files with 628 additions and 870 deletions
+42 -30
View File
@@ -303,24 +303,35 @@ impl LspClient {
)
}
/// Call a textDocument/positional method (hover, completion, definition, references).
///
/// Builds the standard `{ textDocument: { uri }, position: { line, character } }` body
/// and delegates to `self.call`. `extra` is merged into the body when present (used by
/// `references` to include the `context` block).
fn call_positional(
&mut self,
method: &str,
uri: &str,
line: u32,
character: u32,
extra: Option<serde_json::Value>,
) -> anyhow::Result<Value> {
let mut body = json!({
"textDocument": { "uri": uri },
"position": { "line": line, "character": character },
});
if let Some(ref extra) = extra {
merge_json(&mut body, extra);
}
self.call(method, &body)
}
pub fn hover(&mut self, uri: &str, line: u32, character: u32) -> anyhow::Result<Value> {
self.call(
"textDocument/hover",
&json!({
"textDocument": { "uri": uri },
"position": { "line": line, "character": character }
}),
)
self.call_positional("textDocument/hover", uri, line, character, None)
}
pub fn completion(&mut self, uri: &str, line: u32, character: u32) -> anyhow::Result<Value> {
self.call(
"textDocument/completion",
&json!({
"textDocument": { "uri": uri },
"position": { "line": line, "character": character }
}),
)
self.call_positional("textDocument/completion", uri, line, character, None)
}
pub fn goto_definition(
@@ -329,25 +340,13 @@ impl LspClient {
line: u32,
character: u32,
) -> anyhow::Result<Value> {
self.call(
"textDocument/definition",
&json!({
"textDocument": { "uri": uri },
"position": { "line": line, "character": character }
}),
)
self.call_positional("textDocument/definition", uri, line, character, None)
}
pub fn references(&mut self, uri: &str, line: u32, character: u32) -> anyhow::Result<Value> {
self.call(
"textDocument/references",
&json!({
"textDocument": { "uri": uri },
"position": { "line": line, "character": character },
"context": {
"includeDeclaration": true
}
}),
self.call_positional(
"textDocument/references", uri, line, character,
Some(json!({"context": { "includeDeclaration": true }})),
)
}
@@ -384,6 +383,19 @@ impl Drop for LspClient {
}
}
/// Merge the fields of `b` into the object `a` (mutating `a` in place).
///
/// Used by `LspClient::call_positional` to layer extra fields (e.g. `context`)
/// onto the standard positional-query body. When `a` is not an object or `b`
/// is not an object this is a no-op.
fn merge_json(a: &mut serde_json::Value, b: &serde_json::Value) {
if let (Some(map), Some(extra)) = (a.as_object_mut(), b.as_object()) {
for (k, v) in extra {
map.insert(k.clone(), v.clone());
}
}
}
pub fn path_to_lsp_uri(path: &str) -> String {
file_path_to_uri(path)
}