Skip to content

Commit adde3a9

Browse files
chore: website - parse the regexp (#989)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent a4dcf3c commit adde3a9

File tree

9 files changed

+374
-105
lines changed

9 files changed

+374
-105
lines changed

website/package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

website/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"prettier": "^3.6.2",
3838
"prettier-plugin-svelte": "^3.4.0",
3939
"prettier-plugin-tailwindcss": "^0.6.13",
40+
"regexp-tree": "^0.1.27",
4041
"regexp-worker": "..",
4142
"svelte": "^5.34.9",
4243
"svelte-check": "^4.2.2",

website/src/lib/Editor.svelte

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<script lang="ts">
2+
import type { Snippet } from 'svelte';
3+
4+
interface Props {
5+
content?: string;
6+
format?: (content: string | undefined) => ReturnType<Snippet>;
7+
}
8+
9+
let { content = $bindable(), format }: Props = $props();
10+
</script>
11+
12+
<div class="container">
13+
{#if format}
14+
<div class="editable behind" contenteditable="plaintext-only">{@render format(content)}</div>
15+
<div class="editable in-front" bind:textContent={content} contenteditable="plaintext-only"></div>
16+
{:else}
17+
<div class="editable" bind:textContent={content} contenteditable="plaintext-only"></div>
18+
{/if}
19+
</div>
20+
21+
<style>
22+
.container {
23+
position: relative;
24+
width: 100%;
25+
height: 100%;
26+
display: flex;
27+
flex-direction: column;
28+
}
29+
.editable {
30+
width: 100%;
31+
height: 100%;
32+
font-family: monospace;
33+
font-size: 1rem;
34+
line-height: 1.5;
35+
padding: 0.5rem;
36+
box-sizing: border-box;
37+
overflow-y: auto;
38+
white-space: pre-wrap; /* Preserve whitespace and line breaks */
39+
border-radius: 5px;
40+
border: 1px solid var(--color-border, #ccc);
41+
color: var(--color-text, #333);
42+
background-color: var(--color-bg, #f5f5f5);
43+
}
44+
45+
.editable.behind {
46+
position: absolute;
47+
top: 0;
48+
left: 0;
49+
width: 100%;
50+
height: 100%;
51+
background-color: var(--color-bg, #f5f5f5);
52+
z-index: 1;
53+
}
54+
55+
.editable.in-front {
56+
position: relative;
57+
z-index: 10;
58+
color: var(--color-overlay, #33333310);
59+
background-color: #00000000;
60+
caret-color: var(--color-caret, #000);
61+
}
62+
</style>

website/src/lib/Playground.svelte

Lines changed: 36 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
import type { MatchAllAsRangePairsResult } from 'regexp-worker';
33
import { createRegExpWorker, TimeoutError, toRegExp } from 'regexp-worker';
44
5+
import Editor from './Editor.svelte';
56
import ErrorMsg from './ErrorMsg.svelte';
7+
import RegExpEditor from './RegExpEditor.svelte';
68
import RegExpFlags from './RegExpFlags.svelte';
79
import { defaultRegexp, usageText } from './usage-text';
810
@@ -168,21 +170,25 @@
168170
</div>
169171
</div>
170172
<div class="box content nested-wrapper">
171-
<div class="box grid-regexp">
173+
<div class="v-box grid-regexp">
172174
<strong>RegExp:</strong>
173-
<textarea name="regexp" class="fixed_width regexp-input" bind:value={regexpSource}></textarea>
175+
<RegExpEditor bind:source={regexpSource} bind:flags={regexpFlags} --color-bg="#f5f5f5" --color-text="#333" --color-caret="#333"
176+
></RegExpEditor>
174177
</div>
175-
<div class="box grid-flags">
176-
<strong>Flags:</strong>
178+
<div class="h-box grid-flags">
177179
<div>
180+
<strong>Flags:</strong>
181+
</div>
182+
<div class="wide">
178183
<RegExpFlags bind:value={regexpFlags} />
179184
</div>
180185
</div>
181186
<div class="box grid-editor">
182-
<div class="edit_container">
183-
<div class="beneath" contenteditable="plaintext-only">{@render snipFragments()}</div>
184-
<div class="edit_box" bind:innerText contenteditable="plaintext-only"></div>
185-
</div>
187+
<Editor bind:content={innerText} --color-bg="#f5f5f5" --color-text="#333" --color-caret="#333">
188+
{#snippet format()}
189+
{@render snipFragments()}
190+
{/snippet}
191+
</Editor>
186192
</div>
187193
</div>
188194
<div class="box footer"></div>
@@ -201,32 +207,7 @@
201207
202208
mark {
203209
background-color: #cf4;
204-
color: #0000;
205-
}
206-
.edit_container {
207-
font-family: var(--font-mono);
208-
box-sizing: border-box;
209-
background-color: #f9f9f9;
210-
color: white;
211-
padding: 10px;
212-
left: 0;
213-
top: 0;
214-
min-height: 500px;
215-
width: 100%;
216-
margin: 0;
217-
}
218-
.edit_box {
219-
color: black;
220-
font-family: var(--font-mono);
221-
box-sizing: border-box;
222-
position: relative;
223-
text-align: left;
224-
padding: 10px;
225-
min-height: 300px;
226-
width: 100%;
227-
height: 100%;
228-
overflow: auto;
229-
background-color: #f9f9f9;
210+
color: #000;
230211
}
231212
.warning {
232213
color: yellow;
@@ -236,39 +217,16 @@
236217
font-family: var(--font-mono);
237218
}
238219
239-
[contenteditable] {
240-
padding: 10px;
241-
color: #090909;
242-
caret-color: green;
243-
background-color: #f0f0f044;
244-
text-wrap: wrap;
245-
}
246-
247-
.beneath {
248-
box-sizing: border-box;
249-
position: absolute;
250-
padding: 10px;
251-
top: 15px;
252-
left: 15px;
253-
right: 15px;
254-
text-align: left;
255-
/* width: 100%; */
256-
text-wrap: wrap;
257-
color: #00000040;
258-
background-color: #f9f9f900;
259-
box-sizing: border-box;
260-
overflow-wrap: break-word;
261-
}
262-
263220
.nested-wrapper {
264221
width: 100%;
265222
display: grid;
266223
box-sizing: border-box;
267224
grid-gap: 0px;
268-
grid-template-columns: 33% 33% auto;
225+
grid-template-columns: auto;
269226
grid-template-areas:
270-
'regexp regexp flags'
271-
'editor editor editor';
227+
'regexp'
228+
'flags'
229+
'editor';
272230
background-color: #fff;
273231
color: #444;
274232
}
@@ -282,21 +240,6 @@
282240
font-size: 100%;
283241
}
284242
285-
.regexp-input {
286-
/* display: inline-block; */
287-
width: 98%;
288-
/* box-sizing: border-box; */
289-
min-height: 2em;
290-
margin: 4px 0;
291-
height: 6em;
292-
field-sizing: content;
293-
padding: 4px;
294-
resize: vertical;
295-
font-family: var(--font-mono);
296-
background-color: #f9f9f9f9;
297-
color: #000;
298-
}
299-
300243
.grid-regexp {
301244
grid-area: regexp;
302245
/* position: relative; */
@@ -334,14 +277,30 @@
334277
color: #444;
335278
}
336279
337-
.box {
280+
.box,
281+
.v-box,
282+
.h-box {
338283
box-sizing: border-box;
339284
background-color: #444;
340285
color: #fff;
341286
padding: 5px;
342287
font-size: 100%;
343288
}
344289
290+
.v-box {
291+
display: flex;
292+
flex-direction: column;
293+
}
294+
295+
.h-box {
296+
display: flex;
297+
flex-direction: row;
298+
}
299+
300+
.wide {
301+
flex: 1;
302+
}
303+
345304
.header {
346305
grid-area: header;
347306
text-align: center;
@@ -370,28 +329,4 @@
370329
overflow-x: auto;
371330
color: white;
372331
}
373-
374-
/* .topleft {
375-
position: absolute;
376-
top: 0;
377-
left: 0;
378-
}
379-
380-
.topright {
381-
position: absolute;
382-
top: 0;
383-
right: 0;
384-
}
385-
386-
.bottomleft {
387-
position: absolute;
388-
bottom: 0;
389-
left: 0;
390-
}
391-
392-
.bottomright {
393-
position: absolute;
394-
bottom: 0;
395-
right: 0;
396-
} */
397332
</style>
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<script lang="ts">
2+
import Editor from './Editor.svelte';
3+
import type { ParsedEntry } from './regexpParsing.js';
4+
import { parseRegExp } from './regexpParsing.js';
5+
6+
let { source = $bindable(), flags = $bindable() } = $props<{ source: string; flags: string }>();
7+
8+
function contentToEntries(source: string): ParsedEntry[] | undefined {
9+
try {
10+
return parseRegExp(source, flags);
11+
} catch {
12+
return undefined;
13+
}
14+
}
15+
16+
function entriesToFragments(source: string, entries: ParsedEntry[] | undefined): Fragment[] {
17+
if (!entries) {
18+
return [{ content: source, className: undefined }];
19+
}
20+
return entries.map((entry) => {
21+
let className: string | undefined;
22+
switch (entry.type) {
23+
case 'Text':
24+
className = undefined;
25+
break;
26+
case 'Comment':
27+
className = 'comment';
28+
break;
29+
case 'Char':
30+
className = 'char';
31+
break;
32+
case 'Group':
33+
className = `group brace-level-${(entry.depth || 0) + 1}`;
34+
break;
35+
default:
36+
className = 'expression';
37+
}
38+
return { className, content: entry.text };
39+
});
40+
}
41+
42+
interface Fragment {
43+
className?: string;
44+
content: string;
45+
}
46+
</script>
47+
48+
{#snippet rFragment(f: Fragment)}{#if f.className}<span class={f.className}>{f.content}</span>{:else}{f.content}{/if}{/snippet}
49+
50+
{#snippet rFragments(frags: Fragment[])}{#each frags as f, index (index)}{@render rFragment(f)}{/each}{/snippet}
51+
52+
<Editor bind:content={source}>
53+
{#snippet format(content: string | undefined)}
54+
{@render rFragments(entriesToFragments(content || '', contentToEntries(content || '')))}
55+
{/snippet}
56+
</Editor>
57+
58+
<style>
59+
.expression {
60+
color: #bb9900;
61+
}
62+
63+
.comment {
64+
color: #696;
65+
}
66+
67+
.char {
68+
color: #333;
69+
}
70+
71+
.brace-level-1 {
72+
color: #e06c75;
73+
}
74+
.brace-level-2 {
75+
color: #d19a66;
76+
}
77+
.brace-level-3 {
78+
color: #e5c07b;
79+
}
80+
.brace-level-4 {
81+
color: #98c379;
82+
}
83+
.brace-level-5 {
84+
color: #56b6c2;
85+
}
86+
.brace-level-6 {
87+
color: #61afef;
88+
}
89+
.brace-level-7 {
90+
color: #c678dd;
91+
}
92+
</style>

0 commit comments

Comments
 (0)