|
1 | 1 | const graphemes = new Intl.Segmenter(undefined, { granularity: "grapheme" }) |
2 | 2 |
|
| 3 | +function promptOffsetWidth(value: string) { |
| 4 | + let width = 0 |
| 5 | + for (const part of graphemes.segment(value)) { |
| 6 | + // Textarea offsets count newlines as one position; Bun.stringWidth counts them as zero. |
| 7 | + width += part.segment === "\n" ? 1 : Bun.stringWidth(part.segment) |
| 8 | + } |
| 9 | + return width |
| 10 | +} |
| 11 | + |
3 | 12 | function displayOffsetIndex(value: string, offset: number) { |
4 | 13 | if (offset <= 0) return 0 |
5 | 14 |
|
6 | 15 | let width = 0 |
7 | 16 | for (const part of graphemes.segment(value)) { |
8 | | - const next = width + Bun.stringWidth(part.segment) |
| 17 | + const next = width + promptOffsetWidth(part.segment) |
9 | 18 | if (next > offset) return part.index |
10 | 19 | width = next |
11 | 20 | } |
12 | 21 |
|
13 | 22 | return value.length |
14 | 23 | } |
15 | 24 |
|
16 | | -export function displaySlice(value: string, start = 0, end = Bun.stringWidth(value)) { |
| 25 | +export function displaySlice(value: string, start = 0, end = promptOffsetWidth(value)) { |
17 | 26 | return value.slice(displayOffsetIndex(value, start), displayOffsetIndex(value, end)) |
18 | 27 | } |
19 | 28 |
|
20 | 29 | export function displayCharAt(value: string, offset: number) { |
21 | 30 | let width = 0 |
22 | 31 | for (const part of graphemes.segment(value)) { |
23 | | - const next = width + Bun.stringWidth(part.segment) |
| 32 | + const next = width + promptOffsetWidth(part.segment) |
24 | 33 | if (offset === width || offset < next) return part.segment |
25 | 34 | width = next |
26 | 35 | } |
27 | 36 | } |
28 | 37 |
|
29 | | -export function mentionTriggerIndex(value: string, offset = Bun.stringWidth(value)) { |
| 38 | +export function mentionTriggerIndex(value: string, offset = promptOffsetWidth(value)) { |
30 | 39 | const text = displaySlice(value, 0, offset) |
31 | 40 | const index = text.lastIndexOf("@") |
32 | 41 | if (index === -1) return |
33 | 42 |
|
34 | 43 | const before = index === 0 ? undefined : text[index - 1] |
35 | 44 | const query = text.slice(index) |
36 | 45 | if ((before === undefined || /\s/.test(before)) && !/\s/.test(query)) { |
37 | | - return Bun.stringWidth(text.slice(0, index)) |
| 46 | + return promptOffsetWidth(text.slice(0, index)) |
38 | 47 | } |
39 | 48 | } |
0 commit comments