Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

properly interpolate strings that appear as first pipeline step

+116 -9
+7
compiler-core/src/ast/typed.rs
··· 630 630 } 631 631 } 632 632 633 + pub fn is_literal_string(&self) -> bool { 634 + match self { 635 + Self::String { .. } => true, 636 + _ => false, 637 + } 638 + } 639 + 633 640 /// Returns `true` if the typed expr is [`Var`]. 634 641 /// 635 642 /// [`Var`]: TypedExpr::Var
+57 -9
compiler-core/src/language_server/code_action.rs
··· 4956 4956 params: &'a CodeActionParams, 4957 4957 edits: TextEdits<'a>, 4958 4958 string_interpolation: Option<(SrcSpan, StringInterpolation)>, 4959 + string_literal_position: StringLiteralPosition, 4960 + } 4961 + 4962 + #[derive(Debug, Clone, Copy, Eq, PartialEq)] 4963 + pub enum StringLiteralPosition { 4964 + FirstPipelineStep, 4965 + Other, 4959 4966 } 4960 4967 4961 4968 #[derive(Clone, Copy)] ··· 4975 4982 params, 4976 4983 edits: TextEdits::new(line_numbers), 4977 4984 string_interpolation: None, 4985 + string_literal_position: StringLiteralPosition::Other, 4978 4986 } 4979 4987 } 4980 4988 4981 4989 pub fn code_actions(mut self) -> Vec<CodeAction> { 4982 4990 self.visit_typed_module(&self.module.ast); 4983 4991 4984 - let Some((_, interpolation)) = self.string_interpolation else { 4992 + let Some((string_location, interpolation)) = self.string_interpolation else { 4985 4993 return vec![]; 4986 4994 }; 4995 + 4996 + if self.string_literal_position == StringLiteralPosition::FirstPipelineStep { 4997 + self.edits.insert(string_location.start, "{ ".into()); 4998 + } 4987 4999 4988 5000 match interpolation { 4989 5001 StringInterpolation::InterpolateValue { value_location } => { ··· 5015 5027 StringInterpolation::SplitString { .. } => return vec![], 5016 5028 }; 5017 5029 5030 + if self.string_literal_position == StringLiteralPosition::FirstPipelineStep { 5031 + self.edits.insert(string_location.end, " }".into()); 5032 + } 5033 + 5018 5034 let mut action = Vec::with_capacity(1); 5019 5035 CodeActionBuilder::new("Interpolate string") 5020 5036 .kind(CodeActionKind::REFACTOR_REWRITE) ··· 5030 5046 !(at <= string_location.start + 1 || at >= string_location.end - 1) 5031 5047 }) 5032 5048 } 5033 - } 5034 5049 5035 - impl<'ast> ast::visit::Visit<'ast> for InterpolateString<'ast> { 5036 - fn visit_typed_expr_string( 5050 + fn visit_literal_string( 5037 5051 &mut self, 5038 - location: &'ast SrcSpan, 5039 - _type_: &'ast Arc<Type>, 5040 - _value: &'ast EcoString, 5052 + string_location: SrcSpan, 5053 + string_position: StringLiteralPosition, 5041 5054 ) { 5042 5055 // We can only interpolate/split a string if the cursor is somewhere 5043 5056 // within its location, otherwise we skip it. 5044 - let string_range = self.edits.src_span_to_lsp_range(*location); 5057 + let string_range = self.edits.src_span_to_lsp_range(string_location); 5045 5058 if !within(self.params.range, string_range) { 5046 5059 return; 5047 5060 } ··· 5056 5069 value_location: selection, 5057 5070 } 5058 5071 }; 5059 - self.string_interpolation = Some((*location, interpolation)); 5072 + self.string_interpolation = Some((string_location, interpolation)); 5073 + self.string_literal_position = string_position; 5074 + } 5075 + } 5076 + 5077 + impl<'ast> ast::visit::Visit<'ast> for InterpolateString<'ast> { 5078 + fn visit_typed_expr_string( 5079 + &mut self, 5080 + location: &'ast SrcSpan, 5081 + _type_: &'ast Arc<Type>, 5082 + _value: &'ast EcoString, 5083 + ) { 5084 + self.visit_literal_string(*location, StringLiteralPosition::Other); 5085 + } 5086 + 5087 + fn visit_typed_expr_pipeline( 5088 + &mut self, 5089 + _location: &'ast SrcSpan, 5090 + first_value: &'ast TypedPipelineAssignment, 5091 + assignments: &'ast [(TypedPipelineAssignment, PipelineAssignmentKind)], 5092 + finally: &'ast TypedExpr, 5093 + _finally_kind: &'ast PipelineAssignmentKind, 5094 + ) { 5095 + if first_value.value.is_literal_string() { 5096 + self.visit_literal_string( 5097 + first_value.location, 5098 + StringLiteralPosition::FirstPipelineStep, 5099 + ); 5100 + } else { 5101 + ast::visit::visit_typed_pipeline_assignment(self, first_value); 5102 + } 5103 + 5104 + assignments 5105 + .iter() 5106 + .for_each(|(a, _)| ast::visit::visit_typed_pipeline_assignment(self, a)); 5107 + self.visit_typed_expr(finally); 5060 5108 } 5061 5109 }
+22
compiler-core/src/language_server/tests/action.rs
··· 193 193 } 194 194 195 195 #[test] 196 + fn splitting_string_as_first_pipeline_step_inserts_brackets() { 197 + assert_code_action!( 198 + INTERPOLATE_STRING, 199 + r#"pub fn main() { 200 + "wibble wobble" |> io.println 201 + }"#, 202 + find_position_of(" wobble").to_selection(), 203 + ); 204 + } 205 + 206 + #[test] 207 + fn interpolating_string_as_first_pipeline_step_inserts_brackets() { 208 + assert_code_action!( 209 + INTERPOLATE_STRING, 210 + r#"pub fn main() { 211 + "wibble wobble woo" |> io.println 212 + }"#, 213 + find_position_of("wobble ").select_until(find_position_of("wobble ").under_last_char()), 214 + ); 215 + } 216 + 217 + #[test] 196 218 fn test_remove_unused_simple() { 197 219 let src = " 198 220 // test
+15
compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__action__interpolating_string_as_first_pipeline_step_inserts_brackets.snap
··· 1 + --- 2 + source: compiler-core/src/language_server/tests/action.rs 3 + expression: "pub fn main() {\n \"wibble wobble woo\" |> io.println\n}" 4 + --- 5 + ----- BEFORE ACTION 6 + pub fn main() { 7 + "wibble wobble woo" |> io.println 8 + ▔▔▔▔▔▔↑ 9 + } 10 + 11 + 12 + ----- AFTER ACTION 13 + pub fn main() { 14 + { "wibble " <> wobble <> " woo" } |> io.println 15 + }
+15
compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__action__splitting_string_as_first_pipeline_step_inserts_brackets.snap
··· 1 + --- 2 + source: compiler-core/src/language_server/tests/action.rs 3 + expression: "pub fn main() {\n \"wibble wobble\" |> io.println\n}" 4 + --- 5 + ----- BEFORE ACTION 6 + pub fn main() { 7 + "wibble wobble" |> io.println 8 + 9 + } 10 + 11 + 12 + ----- AFTER ACTION 13 + pub fn main() { 14 + { "wibble " <> todo <> " wobble" } |> io.println 15 + }