Resolve a deferred "Extract Variable" code action by computing the full workspace edit. Called from `resolve_code_action` when `action_kind` is `"refactor.extractVariable"` or `"refactor.extractVariableAll"`.
(
&self,
data: &CodeActionData,
content: &str,
)
| 742 | /// Called from `resolve_code_action` when `action_kind` is |
| 743 | /// `"refactor.extractVariable"` or `"refactor.extractVariableAll"`. |
| 744 | pub(crate) fn resolve_extract_variable( |
| 745 | &self, |
| 746 | data: &CodeActionData, |
| 747 | content: &str, |
| 748 | ) -> Option<WorkspaceEdit> { |
| 749 | let all_occurrences = data |
| 750 | .extra |
| 751 | .get("all_occurrences") |
| 752 | .and_then(|v| v.as_bool()) |
| 753 | .unwrap_or(data.action_kind == "refactor.extractVariableAll"); |
| 754 | |
| 755 | let start_offset = position_to_byte_offset(content, data.range.start); |
| 756 | let end_offset = position_to_byte_offset(content, data.range.end); |
| 757 | |
| 758 | if start_offset >= end_offset || end_offset > content.len() { |
| 759 | return None; |
| 760 | } |
| 761 | |
| 762 | let selected_text = &content[start_offset..end_offset]; |
| 763 | let trimmed = selected_text.trim(); |
| 764 | |
| 765 | if trimmed.is_empty() || !is_valid_expression(trimmed) { |
| 766 | return None; |
| 767 | } |
| 768 | |
| 769 | // Generate variable name and deduplicate. |
| 770 | let base_name = generate_variable_name(selected_text); |
| 771 | let scope_map = build_scope_map(content, start_offset as u32); |
| 772 | let existing_vars = scope_map.variables_in_scope(start_offset as u32); |
| 773 | let var_name = deduplicate_name(&base_name, &existing_vars); |
| 774 | |
| 775 | let rhs = strip_outer_parens(trimmed); |
| 776 | let replacement_text = format!("${}", var_name); |
| 777 | |
| 778 | let doc_uri: Url = match data.uri.parse() { |
| 779 | Ok(u) => u, |
| 780 | Err(_) => return None, |
| 781 | }; |
| 782 | |
| 783 | if all_occurrences { |
| 784 | // ── All occurrences mode ──────────────────────────────── |
| 785 | let (scope_start, scope_end) = scope_map |
| 786 | .enclosing_frame(start_offset as u32) |
| 787 | .map(|f| (f.start as usize, f.end as usize)) |
| 788 | .unwrap_or((0, content.len())); |
| 789 | |
| 790 | let trim_start_delta = selected_text.len() - selected_text.trim_start().len(); |
| 791 | let trim_end_delta = selected_text.len() - selected_text.trim_end().len(); |
| 792 | let trimmed_start = start_offset + trim_start_delta; |
| 793 | let trimmed_end = end_offset - trim_end_delta; |
| 794 | |
| 795 | let other_occurrences = find_identical_occurrences( |
| 796 | content, |
| 797 | trimmed, |
| 798 | trimmed_start, |
| 799 | trimmed_end, |
| 800 | scope_start, |
| 801 | scope_end, |
no test coverage detected