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
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user