@nocturnium/svelte-ide 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/components/ai/AIMessageContent.svelte +24 -14
- package/dist/components/ai/AIPanel.svelte +22 -0
- package/dist/components/editor/CollaborativeEditor.svelte +68 -5
- package/dist/components/editor/CollaborativeEditor.svelte.d.ts +14 -0
- package/dist/components/editor/ContextLens.svelte +16 -10
- package/dist/components/editor/CustomEditor.svelte +52 -33
- package/dist/components/editor/CustomEditor.svelte.d.ts +2 -2
- package/dist/components/editor/EchoCursorLayer.svelte +43 -11
- package/dist/components/editor/Editor.svelte +17 -0
- package/dist/components/editor/Editor.svelte.d.ts +9 -0
- package/dist/components/editor/EditorPane.svelte +18 -1
- package/dist/components/editor/EditorPane.svelte.d.ts +5 -0
- package/dist/components/editor/EditorSelections.svelte +27 -11
- package/dist/components/editor/EditorSelections.svelte.d.ts +1 -0
- package/dist/components/editor/GhostBracketLayer.svelte +38 -25
- package/dist/components/editor/core/folding.d.ts +11 -0
- package/dist/components/editor/core/folding.js +41 -0
- package/dist/components/editor/core/index.d.ts +0 -5
- package/dist/components/editor/core/index.js +4 -5
- package/dist/components/editor/core/state.d.ts +5 -0
- package/dist/components/editor/core/state.js +131 -12
- package/dist/components/editor/editor-find.d.ts +1 -0
- package/dist/components/editor/editor-find.js +6 -5
- package/dist/components/editor/editor-input.d.ts +1 -0
- package/dist/components/editor/editor-input.js +4 -1
- package/dist/components/editor/editor-scroll.d.ts +1 -0
- package/dist/components/editor/editor-scroll.js +2 -1
- package/dist/components/editor/index.d.ts +19 -3
- package/dist/components/editor/index.js +18 -4
- package/dist/components/editor/tokenizer/base.d.ts +1 -25
- package/dist/components/editor/tokenizer/base.js +0 -172
- package/dist/components/editor/tokenizer/index.d.ts +4 -0
- package/dist/components/editor/tokenizer/index.js +1 -1
- package/dist/components/editor/tokenizer/languages/html.d.ts +3 -2
- package/dist/components/editor/tokenizer/languages/html.js +64 -6
- package/dist/components/editor/tokenizer/languages/javascript.d.ts +0 -3
- package/dist/components/editor/tokenizer/languages/javascript.js +1 -2
- package/dist/components/editor/tokenizer/languages/svelte.d.ts +1 -1
- package/dist/components/editor/tokenizer/languages/svelte.js +6 -1
- package/dist/components/editor/tokenizer/types.d.ts +0 -28
- package/dist/crdt/awareness.d.ts +8 -2
- package/dist/crdt/awareness.js +11 -4
- package/dist/crdt/document.d.ts +10 -1
- package/dist/crdt/document.js +15 -7
- package/dist/crdt/index.d.ts +8 -2
- package/dist/crdt/index.js +5 -2
- package/dist/crdt/undo.d.ts +2 -7
- package/dist/crdt/undo.js +1 -8
- package/dist/index.d.ts +7 -9
- package/dist/index.js +7 -9
- package/dist/services/error-handling.d.ts +2 -11
- package/dist/services/error-handling.js +15 -4
- package/dist/services/lsp-client.d.ts +3 -0
- package/dist/services/lsp-client.js +55 -10
- package/dist/services/mock-ai.js +1 -1
- package/dist/services/optimistic.d.ts +8 -5
- package/dist/services/optimistic.js +36 -10
- package/dist/services/vfs-client.js +11 -3
- package/dist/stores/agents.svelte.js +3 -2
- package/dist/stores/ai-persistence.svelte.js +7 -2
- package/dist/stores/ai.svelte.js +3 -2
- package/dist/stores/collaboration.svelte.d.ts +1 -1
- package/dist/stores/collaboration.svelte.js +3 -2
- package/dist/stores/editor.svelte.js +29 -5
- package/dist/stores/layout.svelte.js +3 -0
- package/dist/stores/plugin.svelte.js +9 -3
- package/dist/stores/vfs.svelte.js +26 -9
- package/dist/styles/theme.css +43 -0
- package/dist/types/vfs.d.ts +15 -1
- package/dist/types/vfs.js +9 -0
- package/dist/utils/language.d.ts +4 -3
- package/dist/utils/language.js +8 -18
- package/package.json +1 -1
- package/dist/components/editor/MinimalEditor.svelte +0 -75
- package/dist/components/editor/MinimalEditor.svelte.d.ts +0 -6
- package/dist/components/editor/MinimalEditor2.svelte +0 -84
- package/dist/components/editor/MinimalEditor2.svelte.d.ts +0 -6
|
@@ -96,6 +96,23 @@
|
|
|
96
96
|
return `top: ${top}px; left: ${left}px;`;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
function getEchoColorToken(cursor: EchoCursor): string {
|
|
100
|
+
const tokens = [
|
|
101
|
+
'--ide-success',
|
|
102
|
+
'--ide-warning',
|
|
103
|
+
'--ide-syntax-tag',
|
|
104
|
+
'--ide-syntax-type',
|
|
105
|
+
'--ide-ai-assistant',
|
|
106
|
+
'--ide-error',
|
|
107
|
+
'--ide-accent',
|
|
108
|
+
'--ide-accent-strong',
|
|
109
|
+
'--ide-syntax-function',
|
|
110
|
+
'--ide-syntax-string'
|
|
111
|
+
];
|
|
112
|
+
const index = echoCursors.findIndex((echo) => echo.id === cursor.id);
|
|
113
|
+
return tokens[Math.max(index, 0) % tokens.length];
|
|
114
|
+
}
|
|
115
|
+
|
|
99
116
|
/**
|
|
100
117
|
* Handle remove echo click
|
|
101
118
|
*/
|
|
@@ -116,7 +133,7 @@
|
|
|
116
133
|
class="echo-cursor"
|
|
117
134
|
class:echo-cursor--replaying={isReplaying}
|
|
118
135
|
class:echo-cursor--active={cursor.active}
|
|
119
|
-
style="{getCursorStyle(cursor)} --echo-color: {cursor
|
|
136
|
+
style="{getCursorStyle(cursor)} --echo-color: var({getEchoColorToken(cursor)});"
|
|
120
137
|
>
|
|
121
138
|
<!-- Cursor line -->
|
|
122
139
|
<div class="echo-cursor__caret" style="height: {lineHeight}px;"></div>
|
|
@@ -228,7 +245,7 @@
|
|
|
228
245
|
left: 0;
|
|
229
246
|
padding: 2px 6px;
|
|
230
247
|
background: var(--echo-color);
|
|
231
|
-
color:
|
|
248
|
+
color: var(--ide-text-inverse);
|
|
232
249
|
font-size: 10px;
|
|
233
250
|
font-weight: 600;
|
|
234
251
|
border-radius: 4px;
|
|
@@ -241,7 +258,7 @@
|
|
|
241
258
|
left: 0;
|
|
242
259
|
margin-top: 2px;
|
|
243
260
|
padding: 1px 4px;
|
|
244
|
-
background:
|
|
261
|
+
background: var(--ide-bg-overlay);
|
|
245
262
|
color: var(--echo-color);
|
|
246
263
|
font-size: 9px;
|
|
247
264
|
font-family: monospace;
|
|
@@ -262,10 +279,10 @@
|
|
|
262
279
|
width: 14px;
|
|
263
280
|
height: 14px;
|
|
264
281
|
padding: 0;
|
|
265
|
-
background:
|
|
282
|
+
background: color-mix(in srgb, var(--ide-error) 90%, transparent);
|
|
266
283
|
border: none;
|
|
267
284
|
border-radius: 50%;
|
|
268
|
-
color:
|
|
285
|
+
color: var(--ide-text-inverse);
|
|
269
286
|
font-size: 10px;
|
|
270
287
|
line-height: 14px;
|
|
271
288
|
text-align: center;
|
|
@@ -279,7 +296,7 @@
|
|
|
279
296
|
}
|
|
280
297
|
|
|
281
298
|
.echo-cursor__remove:hover {
|
|
282
|
-
background:
|
|
299
|
+
background: var(--ide-error);
|
|
283
300
|
}
|
|
284
301
|
|
|
285
302
|
.echo-cursor__replay {
|
|
@@ -288,13 +305,13 @@
|
|
|
288
305
|
left: 4px;
|
|
289
306
|
padding: 2px 6px;
|
|
290
307
|
background: var(--echo-color);
|
|
291
|
-
color:
|
|
308
|
+
color: var(--ide-text-inverse);
|
|
292
309
|
font-size: 12px;
|
|
293
310
|
font-family: monospace;
|
|
294
311
|
border-radius: 4px;
|
|
295
312
|
white-space: pre;
|
|
296
313
|
transition: opacity 0.2s ease;
|
|
297
|
-
box-shadow:
|
|
314
|
+
box-shadow: var(--ide-shadow-md);
|
|
298
315
|
}
|
|
299
316
|
|
|
300
317
|
.echo-cursor__ripple {
|
|
@@ -330,11 +347,11 @@
|
|
|
330
347
|
align-items: center;
|
|
331
348
|
gap: 6px;
|
|
332
349
|
padding: 6px 12px;
|
|
333
|
-
background:
|
|
334
|
-
border: 1px solid
|
|
350
|
+
background: color-mix(in srgb, var(--ide-success) 15%, transparent);
|
|
351
|
+
border: 1px solid color-mix(in srgb, var(--ide-success) 30%, transparent);
|
|
335
352
|
border-radius: 6px;
|
|
336
353
|
font-size: 12px;
|
|
337
|
-
color:
|
|
354
|
+
color: var(--ide-success);
|
|
338
355
|
pointer-events: auto;
|
|
339
356
|
}
|
|
340
357
|
|
|
@@ -360,4 +377,19 @@
|
|
|
360
377
|
.echo-mode-indicator__count {
|
|
361
378
|
font-weight: 500;
|
|
362
379
|
}
|
|
380
|
+
|
|
381
|
+
@media (prefers-reduced-motion: reduce) {
|
|
382
|
+
.echo-cursor__caret,
|
|
383
|
+
.echo-cursor--replaying .echo-cursor__caret,
|
|
384
|
+
.echo-cursor__ripple,
|
|
385
|
+
.echo-mode-indicator__icon {
|
|
386
|
+
animation: none;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.echo-cursor__delay,
|
|
390
|
+
.echo-cursor__remove,
|
|
391
|
+
.echo-cursor__replay {
|
|
392
|
+
transition: none;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
363
395
|
</style>
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import CustomEditor from './CustomEditor.svelte';
|
|
10
10
|
import type { EditorPreferences } from '../../types';
|
|
11
|
+
import type { AIAwareness } from './core/ai-awareness';
|
|
11
12
|
|
|
12
13
|
interface Props {
|
|
13
14
|
/** Document content */
|
|
@@ -20,6 +21,14 @@
|
|
|
20
21
|
preferences?: Partial<EditorPreferences>;
|
|
21
22
|
/** Additional CSS class */
|
|
22
23
|
class?: string;
|
|
24
|
+
/** Enable code folding */
|
|
25
|
+
folding?: boolean;
|
|
26
|
+
/** Enable multi-cursor editing */
|
|
27
|
+
multiCursor?: boolean;
|
|
28
|
+
/** Maximum number of cursors */
|
|
29
|
+
maxCursors?: number;
|
|
30
|
+
/** AI agents for Ghost Pair visualization */
|
|
31
|
+
aiAgents?: AIAwareness[];
|
|
23
32
|
/** Called when content changes */
|
|
24
33
|
onChange?: (content: string) => void;
|
|
25
34
|
/** Called when cursor position changes */
|
|
@@ -34,6 +43,10 @@
|
|
|
34
43
|
readonly = false,
|
|
35
44
|
preferences = {},
|
|
36
45
|
class: className = '',
|
|
46
|
+
folding = true,
|
|
47
|
+
multiCursor = true,
|
|
48
|
+
maxCursors = 100,
|
|
49
|
+
aiAgents = [],
|
|
37
50
|
onChange,
|
|
38
51
|
onCursorChange,
|
|
39
52
|
onSave
|
|
@@ -46,6 +59,10 @@
|
|
|
46
59
|
{language}
|
|
47
60
|
{readonly}
|
|
48
61
|
{preferences}
|
|
62
|
+
{folding}
|
|
63
|
+
{multiCursor}
|
|
64
|
+
{maxCursors}
|
|
65
|
+
{aiAgents}
|
|
49
66
|
{onChange}
|
|
50
67
|
{onCursorChange}
|
|
51
68
|
{onSave}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EditorPreferences } from '../../types';
|
|
2
|
+
import type { AIAwareness } from './core/ai-awareness';
|
|
2
3
|
interface Props {
|
|
3
4
|
/** Document content */
|
|
4
5
|
content: string;
|
|
@@ -10,6 +11,14 @@ interface Props {
|
|
|
10
11
|
preferences?: Partial<EditorPreferences>;
|
|
11
12
|
/** Additional CSS class */
|
|
12
13
|
class?: string;
|
|
14
|
+
/** Enable code folding */
|
|
15
|
+
folding?: boolean;
|
|
16
|
+
/** Enable multi-cursor editing */
|
|
17
|
+
multiCursor?: boolean;
|
|
18
|
+
/** Maximum number of cursors */
|
|
19
|
+
maxCursors?: number;
|
|
20
|
+
/** AI agents for Ghost Pair visualization */
|
|
21
|
+
aiAgents?: AIAwareness[];
|
|
13
22
|
/** Called when content changes */
|
|
14
23
|
onChange?: (content: string) => void;
|
|
15
24
|
/** Called when cursor position changes */
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import Editor from './Editor.svelte';
|
|
3
3
|
import EditorTabs from './EditorTabs.svelte';
|
|
4
4
|
import type { EditorPreferences } from '../../types';
|
|
5
|
+
import type { AIAwareness } from './core/ai-awareness';
|
|
5
6
|
import {
|
|
6
7
|
getTabs,
|
|
7
8
|
getActiveTab,
|
|
@@ -15,11 +16,23 @@
|
|
|
15
16
|
|
|
16
17
|
interface Props {
|
|
17
18
|
preferences?: Partial<EditorPreferences>;
|
|
19
|
+
folding?: boolean;
|
|
20
|
+
multiCursor?: boolean;
|
|
21
|
+
maxCursors?: number;
|
|
22
|
+
aiAgents?: AIAwareness[];
|
|
18
23
|
onSave?: (path: string, content: string) => Promise<void>;
|
|
19
24
|
class?: string;
|
|
20
25
|
}
|
|
21
26
|
|
|
22
|
-
let {
|
|
27
|
+
let {
|
|
28
|
+
preferences = {},
|
|
29
|
+
folding = true,
|
|
30
|
+
multiCursor = true,
|
|
31
|
+
maxCursors = 100,
|
|
32
|
+
aiAgents = [],
|
|
33
|
+
onSave,
|
|
34
|
+
class: className = ''
|
|
35
|
+
}: Props = $props();
|
|
23
36
|
|
|
24
37
|
// Use getter functions for reactive access
|
|
25
38
|
let tabs = $derived(getTabs());
|
|
@@ -70,6 +83,10 @@
|
|
|
70
83
|
language={activeTab.language}
|
|
71
84
|
readonly={activeTab.aiEditing}
|
|
72
85
|
{preferences}
|
|
86
|
+
{folding}
|
|
87
|
+
{multiCursor}
|
|
88
|
+
{maxCursors}
|
|
89
|
+
{aiAgents}
|
|
73
90
|
onChange={handleChange}
|
|
74
91
|
onCursorChange={handleCursorChange}
|
|
75
92
|
onSave={handleSave}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { EditorPreferences } from '../../types';
|
|
2
|
+
import type { AIAwareness } from './core/ai-awareness';
|
|
2
3
|
interface Props {
|
|
3
4
|
preferences?: Partial<EditorPreferences>;
|
|
5
|
+
folding?: boolean;
|
|
6
|
+
multiCursor?: boolean;
|
|
7
|
+
maxCursors?: number;
|
|
8
|
+
aiAgents?: AIAwareness[];
|
|
4
9
|
onSave?: (path: string, content: string) => Promise<void>;
|
|
5
10
|
class?: string;
|
|
6
11
|
}
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
viewportHeight: number;
|
|
27
27
|
getLine: (n: number) => { text: string } | undefined;
|
|
28
28
|
lineCount: number;
|
|
29
|
+
lineToVisualRow?: (line: number) => number;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
let {
|
|
@@ -39,7 +40,8 @@
|
|
|
39
40
|
scrollTop,
|
|
40
41
|
viewportHeight,
|
|
41
42
|
getLine,
|
|
42
|
-
lineCount
|
|
43
|
+
lineCount,
|
|
44
|
+
lineToVisualRow = (line) => line
|
|
43
45
|
}: Props = $props();
|
|
44
46
|
|
|
45
47
|
// Selection rects memoization
|
|
@@ -70,17 +72,17 @@
|
|
|
70
72
|
|
|
71
73
|
// Calculate visible line range (with 1-line buffer for smooth scrolling)
|
|
72
74
|
const vh = viewportHeight || FALLBACK_VIEWPORT_HEIGHT;
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
+
const firstVisibleRow = Math.max(0, Math.floor(scrollTop / lineHeight) - 1);
|
|
76
|
+
const lastVisibleRow = Math.max(0, Math.ceil((scrollTop + vh) / lineHeight) + 1);
|
|
75
77
|
|
|
76
78
|
// Create cache key from all cursors, scroll position, and measurement values
|
|
77
79
|
const cursorKeys = cursors
|
|
78
80
|
.map(
|
|
79
81
|
(c) =>
|
|
80
|
-
`${c.id}:${c.selection.anchor.line}:${c.selection.anchor.column}-${c.selection.head.line}:${c.selection.head.column}`
|
|
82
|
+
`${c.id}:${c.selection.anchor.line}/${lineToVisualRow(c.selection.anchor.line)}:${c.selection.anchor.column}-${c.selection.head.line}/${lineToVisualRow(c.selection.head.line)}:${c.selection.head.column}`
|
|
81
83
|
)
|
|
82
84
|
.join('|');
|
|
83
|
-
const key = `${cursorKeys}@${
|
|
85
|
+
const key = `${cursorKeys}@${firstVisibleRow}-${lastVisibleRow}:${charWidth}:${lineHeight}:${gutterWidth}`;
|
|
84
86
|
if (key === cachedSelectionKey) {
|
|
85
87
|
return cachedSelectionRects;
|
|
86
88
|
}
|
|
@@ -100,13 +102,14 @@
|
|
|
100
102
|
const start = getSelectionStart(cursor.selection);
|
|
101
103
|
const end = getSelectionEnd(cursor.selection);
|
|
102
104
|
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
const renderEnd = Math.min(end.line, lastVisibleLine);
|
|
105
|
+
const renderStart = Math.max(start.line, 0);
|
|
106
|
+
const renderEnd = Math.min(end.line, lineCount - 1);
|
|
106
107
|
|
|
107
108
|
for (let line = renderStart; line <= renderEnd; line++) {
|
|
108
109
|
const lineContent = getLine(line);
|
|
109
110
|
if (!lineContent) continue;
|
|
111
|
+
const visualRow = lineToVisualRow(line);
|
|
112
|
+
if (visualRow < firstVisibleRow || visualRow > lastVisibleRow) continue;
|
|
110
113
|
|
|
111
114
|
let startCol = 0;
|
|
112
115
|
let endCol = lineContent.text.length;
|
|
@@ -122,7 +125,7 @@
|
|
|
122
125
|
const width = Math.max((endCol - startCol) * charWidth, 4);
|
|
123
126
|
|
|
124
127
|
rects.push({
|
|
125
|
-
top:
|
|
128
|
+
top: visualRow * lineHeight,
|
|
126
129
|
left: gutterWidth + contentPadding + startCol * charWidth,
|
|
127
130
|
width,
|
|
128
131
|
height: lineHeight,
|
|
@@ -139,7 +142,7 @@
|
|
|
139
142
|
// Get cursor style for a specific cursor position
|
|
140
143
|
function getCursorStyleForPosition(pos: Position): string {
|
|
141
144
|
const left = gutterWidth + contentPadding + pos.column * charWidth;
|
|
142
|
-
const top = pos.line * lineHeight;
|
|
145
|
+
const top = lineToVisualRow(pos.line) * lineHeight;
|
|
143
146
|
return `left: ${left}px; top: ${top}px; height: ${lineHeight}px;`;
|
|
144
147
|
}
|
|
145
148
|
</script>
|
|
@@ -156,11 +159,12 @@
|
|
|
156
159
|
</div>
|
|
157
160
|
|
|
158
161
|
<!-- Cursors (all cursors rendered with primary/secondary distinction) -->
|
|
159
|
-
{#if
|
|
162
|
+
{#if !isReadonly}
|
|
160
163
|
{#each cursors as cursor (cursor.id)}
|
|
161
164
|
<div
|
|
162
165
|
class="custom-editor__cursor"
|
|
163
166
|
class:custom-editor__cursor--secondary={!cursor.isPrimary}
|
|
167
|
+
class:custom-editor__cursor--hidden={!cursorVisible}
|
|
164
168
|
style={getCursorStyleForPosition(cursor.selection.head)}
|
|
165
169
|
></div>
|
|
166
170
|
{/each}
|
|
@@ -193,6 +197,7 @@
|
|
|
193
197
|
background: var(--color-nocturnium-aurora-blue);
|
|
194
198
|
z-index: 10;
|
|
195
199
|
pointer-events: none;
|
|
200
|
+
opacity: 1;
|
|
196
201
|
transition: opacity 80ms;
|
|
197
202
|
}
|
|
198
203
|
|
|
@@ -201,4 +206,15 @@
|
|
|
201
206
|
background: var(--ide-interactive-muted);
|
|
202
207
|
opacity: 0.85;
|
|
203
208
|
}
|
|
209
|
+
|
|
210
|
+
.custom-editor__cursor--hidden {
|
|
211
|
+
opacity: 0;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
@media (prefers-reduced-motion: reduce) {
|
|
215
|
+
.custom-editor__cursor {
|
|
216
|
+
opacity: 1;
|
|
217
|
+
transition: none;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
204
220
|
</style>
|
|
@@ -19,6 +19,7 @@ interface Props {
|
|
|
19
19
|
text: string;
|
|
20
20
|
} | undefined;
|
|
21
21
|
lineCount: number;
|
|
22
|
+
lineToVisualRow?: (line: number) => number;
|
|
22
23
|
}
|
|
23
24
|
declare const EditorSelections: import("svelte").Component<Props, {}, "">;
|
|
24
25
|
type EditorSelections = ReturnType<typeof EditorSelections>;
|
|
@@ -107,23 +107,23 @@
|
|
|
107
107
|
/**
|
|
108
108
|
* Get color for confidence level
|
|
109
109
|
*/
|
|
110
|
-
function
|
|
111
|
-
if (confidence >= 0.85) return '
|
|
112
|
-
if (confidence >= 0.7) return '
|
|
113
|
-
return '
|
|
110
|
+
function getConfidenceToken(confidence: number): string {
|
|
111
|
+
if (confidence >= 0.85) return '--ide-status-created';
|
|
112
|
+
if (confidence >= 0.7) return '--ide-status-modified';
|
|
113
|
+
return '--ide-accent-strong';
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/**
|
|
117
117
|
* Get severity color
|
|
118
118
|
*/
|
|
119
|
-
function
|
|
119
|
+
function getSeverityToken(severity: BracketMismatch['severity']): string {
|
|
120
120
|
switch (severity) {
|
|
121
121
|
case 'error':
|
|
122
|
-
return '
|
|
122
|
+
return '--ide-status-deleted';
|
|
123
123
|
case 'warning':
|
|
124
|
-
return '
|
|
124
|
+
return '--ide-status-modified';
|
|
125
125
|
default:
|
|
126
|
-
return '
|
|
126
|
+
return '--ide-text-muted';
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
</script>
|
|
@@ -132,12 +132,12 @@
|
|
|
132
132
|
<div class="ghost-bracket-layer" aria-hidden="true">
|
|
133
133
|
<!-- Ghost bracket suggestions -->
|
|
134
134
|
{#each ghosts as ghost (ghost.id)}
|
|
135
|
-
{@const color =
|
|
135
|
+
{@const color = getConfidenceToken(ghost.confidence)}
|
|
136
136
|
{@const connectorStyle = getConnectorStyle(ghost)}
|
|
137
137
|
|
|
138
138
|
<!-- Connector line to matching bracket -->
|
|
139
139
|
{#if connectorStyle && hoveredGhost?.id === ghost.id}
|
|
140
|
-
<div class="ghost-connector" style="{connectorStyle} --ghost-color: {color};">
|
|
140
|
+
<div class="ghost-connector" style="{connectorStyle} --ghost-color: var({color});">
|
|
141
141
|
<div class="ghost-connector__line"></div>
|
|
142
142
|
</div>
|
|
143
143
|
{/if}
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
<div
|
|
147
147
|
class="ghost-bracket"
|
|
148
148
|
role="tooltip"
|
|
149
|
-
style="{getGhostStyle(ghost)} --ghost-color: {color};"
|
|
149
|
+
style="{getGhostStyle(ghost)} --ghost-color: var({color});"
|
|
150
150
|
onmouseenter={() => (hoveredGhost = ghost)}
|
|
151
151
|
onmouseleave={() => (hoveredGhost = null)}
|
|
152
152
|
>
|
|
@@ -187,10 +187,10 @@
|
|
|
187
187
|
|
|
188
188
|
<!-- Bracket mismatch markers -->
|
|
189
189
|
{#each mismatches as mismatch (`${mismatch.position.line}:${mismatch.position.column}:${mismatch.issue}`)}
|
|
190
|
-
{@const color =
|
|
190
|
+
{@const color = getSeverityToken(mismatch.severity)}
|
|
191
191
|
<div
|
|
192
192
|
class="bracket-mismatch bracket-mismatch--{mismatch.issue}"
|
|
193
|
-
style="{getMismatchStyle(mismatch)} --mismatch-color: {color};"
|
|
193
|
+
style="{getMismatchStyle(mismatch)} --mismatch-color: var({color});"
|
|
194
194
|
title={mismatch.issue === 'unclosed'
|
|
195
195
|
? `Unclosed '${mismatch.character}'`
|
|
196
196
|
: mismatch.issue === 'unexpected'
|
|
@@ -253,7 +253,7 @@
|
|
|
253
253
|
top: -16px;
|
|
254
254
|
left: 0;
|
|
255
255
|
padding: 1px 4px;
|
|
256
|
-
background:
|
|
256
|
+
background: var(--ide-bg-overlay);
|
|
257
257
|
color: var(--ghost-color);
|
|
258
258
|
font-size: 9px;
|
|
259
259
|
font-family: monospace;
|
|
@@ -272,17 +272,17 @@
|
|
|
272
272
|
left: 0;
|
|
273
273
|
margin-top: 4px;
|
|
274
274
|
padding: 8px;
|
|
275
|
-
background: var(--
|
|
276
|
-
border: 1px solid var(--
|
|
275
|
+
background: var(--ide-bg-elevated);
|
|
276
|
+
border: 1px solid var(--ide-border);
|
|
277
277
|
border-radius: 6px;
|
|
278
|
-
box-shadow:
|
|
278
|
+
box-shadow: var(--ide-shadow-lg);
|
|
279
279
|
min-width: 140px;
|
|
280
280
|
z-index: 100;
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
.ghost-bracket__reason {
|
|
284
284
|
font-size: 11px;
|
|
285
|
-
color: var(--
|
|
285
|
+
color: var(--ide-text-secondary);
|
|
286
286
|
margin-bottom: 8px;
|
|
287
287
|
line-height: 1.3;
|
|
288
288
|
}
|
|
@@ -304,21 +304,21 @@
|
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
.ghost-bracket__btn--accept {
|
|
307
|
-
background:
|
|
308
|
-
color:
|
|
307
|
+
background: color-mix(in srgb, var(--ide-status-created) 20%, transparent);
|
|
308
|
+
color: var(--ide-status-created);
|
|
309
309
|
}
|
|
310
310
|
|
|
311
311
|
.ghost-bracket__btn--accept:hover {
|
|
312
|
-
background:
|
|
312
|
+
background: color-mix(in srgb, var(--ide-status-created) 30%, transparent);
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
.ghost-bracket__btn--dismiss {
|
|
316
|
-
background:
|
|
317
|
-
color:
|
|
316
|
+
background: color-mix(in srgb, var(--ide-status-deleted) 20%, transparent);
|
|
317
|
+
color: var(--ide-status-deleted);
|
|
318
318
|
}
|
|
319
319
|
|
|
320
320
|
.ghost-bracket__btn--dismiss:hover {
|
|
321
|
-
background:
|
|
321
|
+
background: color-mix(in srgb, var(--ide-status-deleted) 30%, transparent);
|
|
322
322
|
}
|
|
323
323
|
|
|
324
324
|
/* Connector line */
|
|
@@ -376,7 +376,7 @@
|
|
|
376
376
|
left: 0;
|
|
377
377
|
padding: 1px 3px;
|
|
378
378
|
background: var(--mismatch-color);
|
|
379
|
-
color:
|
|
379
|
+
color: var(--ide-text-inverse);
|
|
380
380
|
font-size: 9px;
|
|
381
381
|
font-family: monospace;
|
|
382
382
|
border-radius: 2px;
|
|
@@ -387,4 +387,17 @@
|
|
|
387
387
|
.bracket-mismatch:hover .bracket-mismatch__expected {
|
|
388
388
|
opacity: 1;
|
|
389
389
|
}
|
|
390
|
+
|
|
391
|
+
@media (prefers-reduced-motion: reduce) {
|
|
392
|
+
.ghost-bracket__char,
|
|
393
|
+
.bracket-mismatch--unclosed .bracket-mismatch__underline {
|
|
394
|
+
animation: none;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.ghost-bracket__confidence,
|
|
398
|
+
.ghost-bracket__btn,
|
|
399
|
+
.bracket-mismatch__expected {
|
|
400
|
+
transition: none;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
390
403
|
</style>
|
|
@@ -109,6 +109,17 @@ export declare class FoldManager {
|
|
|
109
109
|
* Get visible lines (line numbers that should be rendered)
|
|
110
110
|
*/
|
|
111
111
|
getVisibleLines(totalLines: number): number[];
|
|
112
|
+
/**
|
|
113
|
+
* Map a raw document line to its compacted visual row.
|
|
114
|
+
*
|
|
115
|
+
* Visible lines map to their exact row in getVisibleLines(totalLines). Hidden
|
|
116
|
+
* lines map to the row of the nearest visible fold header at or above them.
|
|
117
|
+
*/
|
|
118
|
+
lineToVisualRow(line: number, totalLines: number): number;
|
|
119
|
+
/**
|
|
120
|
+
* Map a compacted visual row back to the raw document line rendered there.
|
|
121
|
+
*/
|
|
122
|
+
visualRowToLine(visualRow: number, totalLines: number): number;
|
|
112
123
|
/**
|
|
113
124
|
* Get the number of hidden lines after a fold start
|
|
114
125
|
*/
|
|
@@ -641,6 +641,47 @@ export class FoldManager {
|
|
|
641
641
|
}
|
|
642
642
|
return visible;
|
|
643
643
|
}
|
|
644
|
+
/**
|
|
645
|
+
* Map a raw document line to its compacted visual row.
|
|
646
|
+
*
|
|
647
|
+
* Visible lines map to their exact row in getVisibleLines(totalLines). Hidden
|
|
648
|
+
* lines map to the row of the nearest visible fold header at or above them.
|
|
649
|
+
*/
|
|
650
|
+
lineToVisualRow(line, totalLines) {
|
|
651
|
+
if (totalLines <= 0)
|
|
652
|
+
return 0;
|
|
653
|
+
const clampedLine = Math.max(0, Math.min(Math.floor(line), totalLines - 1));
|
|
654
|
+
const visible = this.getVisibleLines(totalLines);
|
|
655
|
+
if (visible.length === 0)
|
|
656
|
+
return 0;
|
|
657
|
+
let low = 0;
|
|
658
|
+
let high = visible.length;
|
|
659
|
+
while (low < high) {
|
|
660
|
+
const mid = Math.floor((low + high) / 2);
|
|
661
|
+
if (visible[mid] < clampedLine) {
|
|
662
|
+
low = mid + 1;
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
high = mid;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
if (visible[low] === clampedLine) {
|
|
669
|
+
return low;
|
|
670
|
+
}
|
|
671
|
+
return Math.max(0, low - 1);
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Map a compacted visual row back to the raw document line rendered there.
|
|
675
|
+
*/
|
|
676
|
+
visualRowToLine(visualRow, totalLines) {
|
|
677
|
+
if (totalLines <= 0)
|
|
678
|
+
return 0;
|
|
679
|
+
const visible = this.getVisibleLines(totalLines);
|
|
680
|
+
if (visible.length === 0)
|
|
681
|
+
return 0;
|
|
682
|
+
const clampedRow = Math.max(0, Math.min(Math.floor(visualRow), visible.length - 1));
|
|
683
|
+
return visible[clampedRow];
|
|
684
|
+
}
|
|
644
685
|
/**
|
|
645
686
|
* Get the number of hidden lines after a fold start
|
|
646
687
|
*/
|
|
@@ -4,18 +4,13 @@
|
|
|
4
4
|
export * from './state';
|
|
5
5
|
export * from './navigation';
|
|
6
6
|
export * from './keybindings';
|
|
7
|
-
export * from './crdt-binding';
|
|
8
7
|
export * from './search';
|
|
9
8
|
export * from './folding';
|
|
10
9
|
export * from './multi-cursor';
|
|
11
10
|
export * from './complexity-analyzer';
|
|
12
11
|
export * from './ai-awareness';
|
|
13
|
-
export * from './ghost-pair';
|
|
14
12
|
export * from './semantic-analyzer';
|
|
15
13
|
export * from './commands';
|
|
16
|
-
export * from './timeline';
|
|
17
|
-
export * from './conflict-predictor';
|
|
18
|
-
export * from './echo-cursor';
|
|
19
14
|
export * from './bracket-healer';
|
|
20
15
|
export * from './git-blame';
|
|
21
16
|
export * from './snippet-manager';
|
|
@@ -4,18 +4,17 @@
|
|
|
4
4
|
export * from './state';
|
|
5
5
|
export * from './navigation';
|
|
6
6
|
export * from './keybindings';
|
|
7
|
-
|
|
7
|
+
// NOTE: './crdt-binding' is intentionally NOT re-exported here. It imports yjs
|
|
8
|
+
// (an optional peer dependency), so leaking it through this barrel would force
|
|
9
|
+
// yjs onto every consumer of the non-collaborative editor. The CRDT binding is
|
|
10
|
+
// available through the dedicated `@nocturnium/svelte-ide/crdt` entry instead.
|
|
8
11
|
export * from './search';
|
|
9
12
|
export * from './folding';
|
|
10
13
|
export * from './multi-cursor';
|
|
11
14
|
export * from './complexity-analyzer';
|
|
12
15
|
export * from './ai-awareness';
|
|
13
|
-
export * from './ghost-pair';
|
|
14
16
|
export * from './semantic-analyzer';
|
|
15
17
|
export * from './commands';
|
|
16
|
-
export * from './timeline';
|
|
17
|
-
export * from './conflict-predictor';
|
|
18
|
-
export * from './echo-cursor';
|
|
19
18
|
export * from './bracket-healer';
|
|
20
19
|
export * from './git-blame';
|
|
21
20
|
export * from './snippet-manager';
|
|
@@ -305,6 +305,10 @@ export declare class EditorState {
|
|
|
305
305
|
* Deep copy a selection to prevent reference issues in history
|
|
306
306
|
*/
|
|
307
307
|
private deepCopySelection;
|
|
308
|
+
private transformCursorUpdatesForInsert;
|
|
309
|
+
private transformPositionForInsert;
|
|
310
|
+
private transformCursorUpdatesForDelete;
|
|
311
|
+
private transformPositionForDelete;
|
|
308
312
|
/**
|
|
309
313
|
* Check if undo is available
|
|
310
314
|
*/
|
|
@@ -317,6 +321,7 @@ export declare class EditorState {
|
|
|
317
321
|
* Compare two tokenizer states for equality
|
|
318
322
|
*/
|
|
319
323
|
private tokenizerStatesEqual;
|
|
324
|
+
private tokenizerStateValuesEqual;
|
|
320
325
|
/**
|
|
321
326
|
* Re-tokenize a range of lines with early-exit optimization
|
|
322
327
|
*/
|