From 4ee045fce98067dcb8426cef79587ba3c6506d05 Mon Sep 17 00:00:00 2001 From: Ivan Starkov Date: Fri, 11 Oct 2024 11:22:56 +0300 Subject: [PATCH] fix: Fix expression editor decoration (#4261) ## Description 2 bugs ### Click on test broke decoration ![image](https://github.com/user-attachments/assets/43a98ea1-08bd-4044-92ff-0a3735dfd6dc) ![image](https://github.com/user-attachments/assets/49d577d1-fa8f-40a1-9798-1fd41b5eaf40) ### Symbols after decoration broke decoration ![image](https://github.com/user-attachments/assets/27f96aa4-f512-44fb-99c8-604817b4dbf8) ![image](https://github.com/user-attachments/assets/93eff6b4-1e40-430e-a406-99b0bdcecd90) ### Would be good to improve Error messages: image ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 5de6) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file --- .../app/builder/shared/expression-editor.tsx | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/apps/builder/app/builder/shared/expression-editor.tsx b/apps/builder/app/builder/shared/expression-editor.tsx index 2a8bd75b10..6b49ffc0a1 100644 --- a/apps/builder/app/builder/shared/expression-editor.tsx +++ b/apps/builder/app/builder/shared/expression-editor.tsx @@ -271,12 +271,31 @@ class VariableWidget extends WidgetType { const variableMatcher = new MatchDecorator({ regexp: /(\$ws\$dataSource\$\w+)/g, - decoration: (match, view) => { + + decorate: (add, from, _to, match, view) => { + const startPos = match.index; + const name = match[1]; - const [data] = view.state.facet(VariablesData); - return Decoration.replace({ - widget: new VariableWidget(data.aliases.get(name) ?? name), - }); + const [{ aliases }] = view.state.facet(VariablesData); + + // The regexp may match variables not in scope, but the key problem we're solving is this: + // We have an alias $ws$dataSource$321 -> SomeVar, which we display as '[SomeVar]' ([] means decoration in the editor). + // If the user types a symbol (e.g., 'a') immediately after '[SomeVar]', + // the raw text becomes $ws$dataSource$321a, but we want to display '[SomeVar]a'. + const dataSourceId = [...aliases.keys()].find((key) => name.includes(key)); + + if (dataSourceId === undefined) { + return; + } + const endPos = startPos + dataSourceId.length; + + add( + from, + endPos, + Decoration.replace({ + widget: new VariableWidget(aliases.get(dataSourceId)!), + }) + ); }, });