@nocturnium/svelte-ide 1.0.0-rc.1
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/LICENSE +21 -0
- package/README.md +251 -0
- package/dist/components/agents/AgentActivityPanel.svelte +565 -0
- package/dist/components/agents/AgentActivityPanel.svelte.d.ts +24 -0
- package/dist/components/agents/AgentAvatar.svelte +417 -0
- package/dist/components/agents/AgentAvatar.svelte.d.ts +23 -0
- package/dist/components/agents/AgentCursor.svelte +224 -0
- package/dist/components/agents/AgentCursor.svelte.d.ts +35 -0
- package/dist/components/agents/AgentPresenceBar.svelte +261 -0
- package/dist/components/agents/AgentPresenceBar.svelte.d.ts +20 -0
- package/dist/components/agents/index.d.ts +4 -0
- package/dist/components/agents/index.js +5 -0
- package/dist/components/ai/AIConversationList.svelte +524 -0
- package/dist/components/ai/AIConversationList.svelte.d.ts +17 -0
- package/dist/components/ai/AIEditPreview.svelte +132 -0
- package/dist/components/ai/AIEditPreview.svelte.d.ts +8 -0
- package/dist/components/ai/AIInlineEdit.svelte +155 -0
- package/dist/components/ai/AIInlineEdit.svelte.d.ts +10 -0
- package/dist/components/ai/AIMessage.svelte +239 -0
- package/dist/components/ai/AIMessage.svelte.d.ts +13 -0
- package/dist/components/ai/AIMessageActions.svelte +176 -0
- package/dist/components/ai/AIMessageActions.svelte.d.ts +12 -0
- package/dist/components/ai/AIMessageContent.svelte +355 -0
- package/dist/components/ai/AIMessageContent.svelte.d.ts +7 -0
- package/dist/components/ai/AIPanel.svelte +561 -0
- package/dist/components/ai/AIPanel.svelte.d.ts +7 -0
- package/dist/components/ai/AISuggestionWidget.svelte +132 -0
- package/dist/components/ai/AISuggestionWidget.svelte.d.ts +10 -0
- package/dist/components/ai/AIToolCallDisplay.svelte +317 -0
- package/dist/components/ai/AIToolCallDisplay.svelte.d.ts +12 -0
- package/dist/components/ai/index.d.ts +9 -0
- package/dist/components/ai/index.js +10 -0
- package/dist/components/core/Avatar.svelte +110 -0
- package/dist/components/core/Avatar.svelte.d.ts +12 -0
- package/dist/components/core/Badge.svelte +98 -0
- package/dist/components/core/Badge.svelte.d.ts +11 -0
- package/dist/components/core/Button.svelte +175 -0
- package/dist/components/core/Button.svelte.d.ts +18 -0
- package/dist/components/core/ConnectionStatus.svelte +294 -0
- package/dist/components/core/ConnectionStatus.svelte.d.ts +20 -0
- package/dist/components/core/ContextMenu.svelte +176 -0
- package/dist/components/core/ContextMenu.svelte.d.ts +19 -0
- package/dist/components/core/ErrorBoundary.svelte +277 -0
- package/dist/components/core/ErrorBoundary.svelte.d.ts +23 -0
- package/dist/components/core/Icon.svelte +107 -0
- package/dist/components/core/Icon.svelte.d.ts +8 -0
- package/dist/components/core/Input.svelte +138 -0
- package/dist/components/core/Input.svelte.d.ts +20 -0
- package/dist/components/core/Kbd.svelte +34 -0
- package/dist/components/core/Kbd.svelte.d.ts +7 -0
- package/dist/components/core/ResizeHandle.svelte +200 -0
- package/dist/components/core/ResizeHandle.svelte.d.ts +23 -0
- package/dist/components/core/Spinner.svelte +35 -0
- package/dist/components/core/Spinner.svelte.d.ts +7 -0
- package/dist/components/core/Textarea.svelte +112 -0
- package/dist/components/core/Textarea.svelte.d.ts +18 -0
- package/dist/components/core/Tooltip.svelte +103 -0
- package/dist/components/core/Tooltip.svelte.d.ts +11 -0
- package/dist/components/core/index.d.ts +13 -0
- package/dist/components/core/index.js +14 -0
- package/dist/components/editor/AIFocusLayer.svelte +430 -0
- package/dist/components/editor/AIFocusLayer.svelte.d.ts +32 -0
- package/dist/components/editor/Breadcrumbs.svelte +435 -0
- package/dist/components/editor/Breadcrumbs.svelte.d.ts +33 -0
- package/dist/components/editor/BreakpointLayer.svelte +642 -0
- package/dist/components/editor/BreakpointLayer.svelte.d.ts +20 -0
- package/dist/components/editor/CognitiveLoadMeter.svelte +324 -0
- package/dist/components/editor/CognitiveLoadMeter.svelte.d.ts +18 -0
- package/dist/components/editor/CollaborativeEditor.svelte +218 -0
- package/dist/components/editor/CollaborativeEditor.svelte.d.ts +32 -0
- package/dist/components/editor/CommandPalette.svelte +434 -0
- package/dist/components/editor/CommandPalette.svelte.d.ts +11 -0
- package/dist/components/editor/ComplexityLayer.svelte +293 -0
- package/dist/components/editor/ComplexityLayer.svelte.d.ts +23 -0
- package/dist/components/editor/ConflictZoneLayer.svelte +441 -0
- package/dist/components/editor/ConflictZoneLayer.svelte.d.ts +25 -0
- package/dist/components/editor/ContextLens.svelte +262 -0
- package/dist/components/editor/ContextLens.svelte.d.ts +27 -0
- package/dist/components/editor/CustomEditor.svelte +1242 -0
- package/dist/components/editor/CustomEditor.svelte.d.ts +37 -0
- package/dist/components/editor/DebugConsole.svelte +646 -0
- package/dist/components/editor/DebugConsole.svelte.d.ts +41 -0
- package/dist/components/editor/EchoCursorLayer.svelte +363 -0
- package/dist/components/editor/EchoCursorLayer.svelte.d.ts +24 -0
- package/dist/components/editor/Editor.svelte +61 -0
- package/dist/components/editor/Editor.svelte.d.ts +22 -0
- package/dist/components/editor/EditorGutter.svelte +119 -0
- package/dist/components/editor/EditorGutter.svelte.d.ts +19 -0
- package/dist/components/editor/EditorLines.svelte +182 -0
- package/dist/components/editor/EditorLines.svelte.d.ts +43 -0
- package/dist/components/editor/EditorPane.svelte +134 -0
- package/dist/components/editor/EditorPane.svelte.d.ts +9 -0
- package/dist/components/editor/EditorSelections.svelte +186 -0
- package/dist/components/editor/EditorSelections.svelte.d.ts +25 -0
- package/dist/components/editor/EditorTabs.svelte +170 -0
- package/dist/components/editor/EditorTabs.svelte.d.ts +12 -0
- package/dist/components/editor/FileExplorer.svelte +811 -0
- package/dist/components/editor/FileExplorer.svelte.d.ts +67 -0
- package/dist/components/editor/FileIcon.svelte +110 -0
- package/dist/components/editor/FileIcon.svelte.d.ts +10 -0
- package/dist/components/editor/FindReplace.svelte +448 -0
- package/dist/components/editor/FindReplace.svelte.d.ts +40 -0
- package/dist/components/editor/GhostBracketLayer.svelte +391 -0
- package/dist/components/editor/GhostBracketLayer.svelte.d.ts +24 -0
- package/dist/components/editor/GitBlameLayer.svelte +436 -0
- package/dist/components/editor/GitBlameLayer.svelte.d.ts +18 -0
- package/dist/components/editor/InlineDiagnosticsLayer.svelte +540 -0
- package/dist/components/editor/InlineDiagnosticsLayer.svelte.d.ts +35 -0
- package/dist/components/editor/InlineDiffLayer.svelte +337 -0
- package/dist/components/editor/InlineDiffLayer.svelte.d.ts +31 -0
- package/dist/components/editor/MinimalEditor.svelte +75 -0
- package/dist/components/editor/MinimalEditor.svelte.d.ts +6 -0
- package/dist/components/editor/MinimalEditor2.svelte +84 -0
- package/dist/components/editor/MinimalEditor2.svelte.d.ts +6 -0
- package/dist/components/editor/Minimap.svelte +327 -0
- package/dist/components/editor/Minimap.svelte.d.ts +34 -0
- package/dist/components/editor/PluginPreviewSandbox.svelte +793 -0
- package/dist/components/editor/PluginPreviewSandbox.svelte.d.ts +49 -0
- package/dist/components/editor/ProblemsPanel.svelte +628 -0
- package/dist/components/editor/ProblemsPanel.svelte.d.ts +25 -0
- package/dist/components/editor/QuickActionsMenu.svelte +403 -0
- package/dist/components/editor/QuickActionsMenu.svelte.d.ts +18 -0
- package/dist/components/editor/SnippetPalette.svelte +530 -0
- package/dist/components/editor/SnippetPalette.svelte.d.ts +16 -0
- package/dist/components/editor/StructureMap.svelte +431 -0
- package/dist/components/editor/StructureMap.svelte.d.ts +37 -0
- package/dist/components/editor/SymbolOutline.svelte +722 -0
- package/dist/components/editor/SymbolOutline.svelte.d.ts +44 -0
- package/dist/components/editor/TimelineScrubber.svelte +470 -0
- package/dist/components/editor/TimelineScrubber.svelte.d.ts +40 -0
- package/dist/components/editor/TokenRenderer.svelte +69 -0
- package/dist/components/editor/TokenRenderer.svelte.d.ts +15 -0
- package/dist/components/editor/constants.d.ts +32 -0
- package/dist/components/editor/constants.js +36 -0
- package/dist/components/editor/core/ai-awareness.d.ts +176 -0
- package/dist/components/editor/core/ai-awareness.js +210 -0
- package/dist/components/editor/core/bracket-healer.d.ts +189 -0
- package/dist/components/editor/core/bracket-healer.js +406 -0
- package/dist/components/editor/core/breakpoints.d.ts +203 -0
- package/dist/components/editor/core/breakpoints.js +414 -0
- package/dist/components/editor/core/commands.d.ts +108 -0
- package/dist/components/editor/core/commands.js +246 -0
- package/dist/components/editor/core/complexity-analyzer.d.ts +123 -0
- package/dist/components/editor/core/complexity-analyzer.js +376 -0
- package/dist/components/editor/core/conflict-predictor.d.ts +135 -0
- package/dist/components/editor/core/conflict-predictor.js +316 -0
- package/dist/components/editor/core/crdt-binding.d.ts +118 -0
- package/dist/components/editor/core/crdt-binding.js +286 -0
- package/dist/components/editor/core/diagnostics.d.ts +210 -0
- package/dist/components/editor/core/diagnostics.js +335 -0
- package/dist/components/editor/core/echo-cursor.d.ts +201 -0
- package/dist/components/editor/core/echo-cursor.js +267 -0
- package/dist/components/editor/core/folding.d.ts +124 -0
- package/dist/components/editor/core/folding.js +672 -0
- package/dist/components/editor/core/ghost-pair.d.ts +122 -0
- package/dist/components/editor/core/ghost-pair.js +221 -0
- package/dist/components/editor/core/git-blame.d.ts +170 -0
- package/dist/components/editor/core/git-blame.js +324 -0
- package/dist/components/editor/core/index.d.ts +26 -0
- package/dist/components/editor/core/index.js +24 -0
- package/dist/components/editor/core/keybindings.d.ts +79 -0
- package/dist/components/editor/core/keybindings.js +357 -0
- package/dist/components/editor/core/multi-cursor.d.ts +196 -0
- package/dist/components/editor/core/multi-cursor.js +521 -0
- package/dist/components/editor/core/navigation.d.ts +107 -0
- package/dist/components/editor/core/navigation.js +408 -0
- package/dist/components/editor/core/quick-actions.d.ts +189 -0
- package/dist/components/editor/core/quick-actions.js +427 -0
- package/dist/components/editor/core/search.d.ts +88 -0
- package/dist/components/editor/core/search.js +192 -0
- package/dist/components/editor/core/semantic-analyzer.d.ts +77 -0
- package/dist/components/editor/core/semantic-analyzer.js +424 -0
- package/dist/components/editor/core/snippet-manager.d.ts +202 -0
- package/dist/components/editor/core/snippet-manager.js +565 -0
- package/dist/components/editor/core/state.d.ts +367 -0
- package/dist/components/editor/core/state.js +900 -0
- package/dist/components/editor/core/timeline.d.ts +204 -0
- package/dist/components/editor/core/timeline.js +349 -0
- package/dist/components/editor/editor-find.d.ts +56 -0
- package/dist/components/editor/editor-find.js +148 -0
- package/dist/components/editor/editor-input.d.ts +77 -0
- package/dist/components/editor/editor-input.js +445 -0
- package/dist/components/editor/editor-multicursor.d.ts +21 -0
- package/dist/components/editor/editor-multicursor.js +196 -0
- package/dist/components/editor/editor-scroll.d.ts +14 -0
- package/dist/components/editor/editor-scroll.js +34 -0
- package/dist/components/editor/index.d.ts +15 -0
- package/dist/components/editor/index.js +21 -0
- package/dist/components/editor/languages.d.ts +62 -0
- package/dist/components/editor/languages.js +285 -0
- package/dist/components/editor/theme.d.ts +88 -0
- package/dist/components/editor/theme.js +139 -0
- package/dist/components/editor/tokenizer/base.d.ts +40 -0
- package/dist/components/editor/tokenizer/base.js +203 -0
- package/dist/components/editor/tokenizer/index.d.ts +56 -0
- package/dist/components/editor/tokenizer/index.js +215 -0
- package/dist/components/editor/tokenizer/languages/css.d.ts +17 -0
- package/dist/components/editor/tokenizer/languages/css.js +194 -0
- package/dist/components/editor/tokenizer/languages/go.d.ts +17 -0
- package/dist/components/editor/tokenizer/languages/go.js +220 -0
- package/dist/components/editor/tokenizer/languages/html.d.ts +24 -0
- package/dist/components/editor/tokenizer/languages/html.js +145 -0
- package/dist/components/editor/tokenizer/languages/javascript.d.ts +56 -0
- package/dist/components/editor/tokenizer/languages/javascript.js +452 -0
- package/dist/components/editor/tokenizer/languages/json.d.ts +12 -0
- package/dist/components/editor/tokenizer/languages/json.js +91 -0
- package/dist/components/editor/tokenizer/languages/markdown.d.ts +16 -0
- package/dist/components/editor/tokenizer/languages/markdown.js +156 -0
- package/dist/components/editor/tokenizer/languages/python.d.ts +20 -0
- package/dist/components/editor/tokenizer/languages/python.js +227 -0
- package/dist/components/editor/tokenizer/languages/svelte.d.ts +40 -0
- package/dist/components/editor/tokenizer/languages/svelte.js +326 -0
- package/dist/components/editor/tokenizer/types.d.ts +86 -0
- package/dist/components/editor/tokenizer/types.js +4 -0
- package/dist/components/layout/IDELayout.svelte +274 -0
- package/dist/components/layout/IDELayout.svelte.d.ts +29 -0
- package/dist/components/layout/StatusBar.svelte +511 -0
- package/dist/components/layout/StatusBar.svelte.d.ts +47 -0
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.js +3 -0
- package/dist/components/lsp/AutocompleteWidget.svelte +364 -0
- package/dist/components/lsp/AutocompleteWidget.svelte.d.ts +33 -0
- package/dist/components/lsp/DiagnosticMarker.svelte +166 -0
- package/dist/components/lsp/DiagnosticMarker.svelte.d.ts +19 -0
- package/dist/components/lsp/DiagnosticsPanel.svelte +388 -0
- package/dist/components/lsp/DiagnosticsPanel.svelte.d.ts +21 -0
- package/dist/components/lsp/HoverTooltip.svelte +274 -0
- package/dist/components/lsp/HoverTooltip.svelte.d.ts +24 -0
- package/dist/components/lsp/LSPEditor.svelte +486 -0
- package/dist/components/lsp/LSPEditor.svelte.d.ts +39 -0
- package/dist/components/lsp/SignatureHelpWidget.svelte +216 -0
- package/dist/components/lsp/SignatureHelpWidget.svelte.d.ts +22 -0
- package/dist/components/lsp/index.d.ts +6 -0
- package/dist/components/lsp/index.js +7 -0
- package/dist/components/plugins/PluginCard.svelte +153 -0
- package/dist/components/plugins/PluginCard.svelte.d.ts +19 -0
- package/dist/components/plugins/PluginPanel.svelte +280 -0
- package/dist/components/plugins/PluginPanel.svelte.d.ts +8 -0
- package/dist/components/plugins/PluginProposalForm.svelte +250 -0
- package/dist/components/plugins/PluginProposalForm.svelte.d.ts +6 -0
- package/dist/components/plugins/PluginStatusBadge.svelte +14 -0
- package/dist/components/plugins/PluginStatusBadge.svelte.d.ts +8 -0
- package/dist/components/plugins/index.d.ts +4 -0
- package/dist/components/plugins/index.js +5 -0
- package/dist/components/vfs/LockConflictDialog.svelte +705 -0
- package/dist/components/vfs/LockConflictDialog.svelte.d.ts +21 -0
- package/dist/components/vfs/LockIndicator.svelte +194 -0
- package/dist/components/vfs/LockIndicator.svelte.d.ts +29 -0
- package/dist/components/vfs/LockOverlay.svelte +344 -0
- package/dist/components/vfs/LockOverlay.svelte.d.ts +17 -0
- package/dist/components/vfs/VersionConflictDialog.svelte +549 -0
- package/dist/components/vfs/VersionConflictDialog.svelte.d.ts +24 -0
- package/dist/components/vfs/index.d.ts +4 -0
- package/dist/components/vfs/index.js +5 -0
- package/dist/crdt/awareness.d.ts +42 -0
- package/dist/crdt/awareness.js +109 -0
- package/dist/crdt/document.d.ts +101 -0
- package/dist/crdt/document.js +187 -0
- package/dist/crdt/index.d.ts +9 -0
- package/dist/crdt/index.js +8 -0
- package/dist/crdt/provider.d.ts +85 -0
- package/dist/crdt/provider.js +150 -0
- package/dist/crdt/types.d.ts +61 -0
- package/dist/crdt/types.js +4 -0
- package/dist/crdt/undo.d.ts +34 -0
- package/dist/crdt/undo.js +70 -0
- package/dist/index.d.ts +277 -0
- package/dist/index.js +280 -0
- package/dist/plugins/index.d.ts +103 -0
- package/dist/plugins/index.js +153 -0
- package/dist/services/error-handling.d.ts +95 -0
- package/dist/services/error-handling.js +413 -0
- package/dist/services/ide-integration.d.ts +83 -0
- package/dist/services/ide-integration.js +367 -0
- package/dist/services/lsp-client.d.ts +69 -0
- package/dist/services/lsp-client.js +667 -0
- package/dist/services/mock-ai.d.ts +37 -0
- package/dist/services/mock-ai.js +318 -0
- package/dist/services/optimistic.d.ts +141 -0
- package/dist/services/optimistic.js +367 -0
- package/dist/services/vfs-client.d.ts +81 -0
- package/dist/services/vfs-client.js +348 -0
- package/dist/stores/agents.svelte.d.ts +85 -0
- package/dist/stores/agents.svelte.js +459 -0
- package/dist/stores/ai-persistence.svelte.d.ts +76 -0
- package/dist/stores/ai-persistence.svelte.js +334 -0
- package/dist/stores/ai.svelte.d.ts +140 -0
- package/dist/stores/ai.svelte.js +383 -0
- package/dist/stores/collaboration.svelte.d.ts +164 -0
- package/dist/stores/collaboration.svelte.js +334 -0
- package/dist/stores/editor.svelte.d.ts +131 -0
- package/dist/stores/editor.svelte.js +250 -0
- package/dist/stores/index.d.ts +10 -0
- package/dist/stores/index.js +29 -0
- package/dist/stores/layout.svelte.d.ts +171 -0
- package/dist/stores/layout.svelte.js +351 -0
- package/dist/stores/plugin.svelte.d.ts +121 -0
- package/dist/stores/plugin.svelte.js +410 -0
- package/dist/stores/vfs.svelte.d.ts +123 -0
- package/dist/stores/vfs.svelte.js +680 -0
- package/dist/styles/theme.css +623 -0
- package/dist/types/agents.d.ts +127 -0
- package/dist/types/agents.js +5 -0
- package/dist/types/ai.d.ts +137 -0
- package/dist/types/ai.js +4 -0
- package/dist/types/crdt.d.ts +222 -0
- package/dist/types/crdt.js +5 -0
- package/dist/types/editor.d.ts +52 -0
- package/dist/types/editor.js +18 -0
- package/dist/types/events.d.ts +133 -0
- package/dist/types/events.js +4 -0
- package/dist/types/filesystem.d.ts +77 -0
- package/dist/types/filesystem.js +4 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.js +12 -0
- package/dist/types/lsp.d.ts +691 -0
- package/dist/types/lsp.js +108 -0
- package/dist/types/plugin.d.ts +239 -0
- package/dist/types/plugin.js +5 -0
- package/dist/types/vfs.d.ts +191 -0
- package/dist/types/vfs.js +18 -0
- package/dist/utils/format.d.ts +55 -0
- package/dist/utils/format.js +152 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/keybindings.d.ts +33 -0
- package/dist/utils/keybindings.js +171 -0
- package/dist/utils/language.d.ts +27 -0
- package/dist/utils/language.js +222 -0
- package/package.json +178 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard handling for the custom editor
|
|
3
|
+
*
|
|
4
|
+
* This module provides keybinding management and keyboard event handling.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Normalize key event to consistent format
|
|
8
|
+
*/
|
|
9
|
+
function normalizeKey(e) {
|
|
10
|
+
return e.key;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Check if modifiers match
|
|
14
|
+
*/
|
|
15
|
+
function modifiersMatch(e, modifiers) {
|
|
16
|
+
const ctrl = modifiers?.ctrl ?? false;
|
|
17
|
+
const shift = modifiers?.shift ?? false;
|
|
18
|
+
const alt = modifiers?.alt ?? false;
|
|
19
|
+
const meta = modifiers?.meta ?? false;
|
|
20
|
+
// Handle Cmd on Mac as Ctrl
|
|
21
|
+
const ctrlOrMeta = e.ctrlKey || e.metaKey;
|
|
22
|
+
return ((ctrl ? ctrlOrMeta : !ctrlOrMeta) &&
|
|
23
|
+
(shift ? e.shiftKey : !e.shiftKey) &&
|
|
24
|
+
(alt ? e.altKey : !e.altKey) &&
|
|
25
|
+
(meta === e.metaKey || ctrl) // Allow meta to match either on its own or as part of ctrl
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Platform detection
|
|
30
|
+
*/
|
|
31
|
+
const isMac = typeof navigator !== 'undefined' && /Mac/.test(navigator.platform);
|
|
32
|
+
/**
|
|
33
|
+
* Create default keybindings for the editor
|
|
34
|
+
*/
|
|
35
|
+
export function createDefaultKeybindings(state, nav, options = {}) {
|
|
36
|
+
const pageSize = options.pageSize ?? 20;
|
|
37
|
+
const keybindings = [];
|
|
38
|
+
// ============================================
|
|
39
|
+
// Navigation
|
|
40
|
+
// ============================================
|
|
41
|
+
// Arrow keys
|
|
42
|
+
keybindings.push({
|
|
43
|
+
key: 'ArrowLeft',
|
|
44
|
+
handler: () => nav.moveLeft(),
|
|
45
|
+
description: 'Move cursor left',
|
|
46
|
+
readonly: true
|
|
47
|
+
}, {
|
|
48
|
+
key: 'ArrowLeft',
|
|
49
|
+
modifiers: { shift: true },
|
|
50
|
+
handler: () => nav.moveLeft(true),
|
|
51
|
+
description: 'Extend selection left',
|
|
52
|
+
readonly: true
|
|
53
|
+
}, {
|
|
54
|
+
key: 'ArrowRight',
|
|
55
|
+
handler: () => nav.moveRight(),
|
|
56
|
+
description: 'Move cursor right',
|
|
57
|
+
readonly: true
|
|
58
|
+
}, {
|
|
59
|
+
key: 'ArrowRight',
|
|
60
|
+
modifiers: { shift: true },
|
|
61
|
+
handler: () => nav.moveRight(true),
|
|
62
|
+
description: 'Extend selection right',
|
|
63
|
+
readonly: true
|
|
64
|
+
}, {
|
|
65
|
+
key: 'ArrowUp',
|
|
66
|
+
handler: () => nav.moveUp(),
|
|
67
|
+
description: 'Move cursor up',
|
|
68
|
+
readonly: true
|
|
69
|
+
}, {
|
|
70
|
+
key: 'ArrowUp',
|
|
71
|
+
modifiers: { shift: true },
|
|
72
|
+
handler: () => nav.moveUp(true),
|
|
73
|
+
description: 'Extend selection up',
|
|
74
|
+
readonly: true
|
|
75
|
+
}, {
|
|
76
|
+
key: 'ArrowDown',
|
|
77
|
+
handler: () => nav.moveDown(),
|
|
78
|
+
description: 'Move cursor down',
|
|
79
|
+
readonly: true
|
|
80
|
+
}, {
|
|
81
|
+
key: 'ArrowDown',
|
|
82
|
+
modifiers: { shift: true },
|
|
83
|
+
handler: () => nav.moveDown(true),
|
|
84
|
+
description: 'Extend selection down',
|
|
85
|
+
readonly: true
|
|
86
|
+
});
|
|
87
|
+
// Word navigation
|
|
88
|
+
keybindings.push({
|
|
89
|
+
key: 'ArrowLeft',
|
|
90
|
+
modifiers: { ctrl: true },
|
|
91
|
+
handler: () => nav.moveWordLeft(),
|
|
92
|
+
description: 'Move to previous word',
|
|
93
|
+
readonly: true
|
|
94
|
+
}, {
|
|
95
|
+
key: 'ArrowLeft',
|
|
96
|
+
modifiers: { ctrl: true, shift: true },
|
|
97
|
+
handler: () => nav.moveWordLeft(true),
|
|
98
|
+
description: 'Extend selection to previous word',
|
|
99
|
+
readonly: true
|
|
100
|
+
}, {
|
|
101
|
+
key: 'ArrowRight',
|
|
102
|
+
modifiers: { ctrl: true },
|
|
103
|
+
handler: () => nav.moveWordRight(),
|
|
104
|
+
description: 'Move to next word',
|
|
105
|
+
readonly: true
|
|
106
|
+
}, {
|
|
107
|
+
key: 'ArrowRight',
|
|
108
|
+
modifiers: { ctrl: true, shift: true },
|
|
109
|
+
handler: () => nav.moveWordRight(true),
|
|
110
|
+
description: 'Extend selection to next word',
|
|
111
|
+
readonly: true
|
|
112
|
+
});
|
|
113
|
+
// Line navigation
|
|
114
|
+
keybindings.push({
|
|
115
|
+
key: 'Home',
|
|
116
|
+
handler: () => nav.moveToLineStart(),
|
|
117
|
+
description: 'Move to line start',
|
|
118
|
+
readonly: true
|
|
119
|
+
}, {
|
|
120
|
+
key: 'Home',
|
|
121
|
+
modifiers: { shift: true },
|
|
122
|
+
handler: () => nav.moveToLineStart(true),
|
|
123
|
+
description: 'Extend selection to line start',
|
|
124
|
+
readonly: true
|
|
125
|
+
}, {
|
|
126
|
+
key: 'End',
|
|
127
|
+
handler: () => nav.moveToLineEnd(),
|
|
128
|
+
description: 'Move to line end',
|
|
129
|
+
readonly: true
|
|
130
|
+
}, {
|
|
131
|
+
key: 'End',
|
|
132
|
+
modifiers: { shift: true },
|
|
133
|
+
handler: () => nav.moveToLineEnd(true),
|
|
134
|
+
description: 'Extend selection to line end',
|
|
135
|
+
readonly: true
|
|
136
|
+
});
|
|
137
|
+
// Document navigation
|
|
138
|
+
keybindings.push({
|
|
139
|
+
key: 'Home',
|
|
140
|
+
modifiers: { ctrl: true },
|
|
141
|
+
handler: () => nav.moveToDocumentStart(),
|
|
142
|
+
description: 'Move to document start',
|
|
143
|
+
readonly: true
|
|
144
|
+
}, {
|
|
145
|
+
key: 'Home',
|
|
146
|
+
modifiers: { ctrl: true, shift: true },
|
|
147
|
+
handler: () => nav.moveToDocumentStart(true),
|
|
148
|
+
description: 'Extend selection to document start',
|
|
149
|
+
readonly: true
|
|
150
|
+
}, {
|
|
151
|
+
key: 'End',
|
|
152
|
+
modifiers: { ctrl: true },
|
|
153
|
+
handler: () => nav.moveToDocumentEnd(),
|
|
154
|
+
description: 'Move to document end',
|
|
155
|
+
readonly: true
|
|
156
|
+
}, {
|
|
157
|
+
key: 'End',
|
|
158
|
+
modifiers: { ctrl: true, shift: true },
|
|
159
|
+
handler: () => nav.moveToDocumentEnd(true),
|
|
160
|
+
description: 'Extend selection to document end',
|
|
161
|
+
readonly: true
|
|
162
|
+
});
|
|
163
|
+
// Page navigation
|
|
164
|
+
keybindings.push({
|
|
165
|
+
key: 'PageUp',
|
|
166
|
+
handler: () => nav.movePageUp(pageSize),
|
|
167
|
+
description: 'Move up one page',
|
|
168
|
+
readonly: true
|
|
169
|
+
}, {
|
|
170
|
+
key: 'PageUp',
|
|
171
|
+
modifiers: { shift: true },
|
|
172
|
+
handler: () => nav.movePageUp(pageSize, true),
|
|
173
|
+
description: 'Extend selection up one page',
|
|
174
|
+
readonly: true
|
|
175
|
+
}, {
|
|
176
|
+
key: 'PageDown',
|
|
177
|
+
handler: () => nav.movePageDown(pageSize),
|
|
178
|
+
description: 'Move down one page',
|
|
179
|
+
readonly: true
|
|
180
|
+
}, {
|
|
181
|
+
key: 'PageDown',
|
|
182
|
+
modifiers: { shift: true },
|
|
183
|
+
handler: () => nav.movePageDown(pageSize, true),
|
|
184
|
+
description: 'Extend selection down one page',
|
|
185
|
+
readonly: true
|
|
186
|
+
});
|
|
187
|
+
// ============================================
|
|
188
|
+
// Selection
|
|
189
|
+
// ============================================
|
|
190
|
+
keybindings.push({
|
|
191
|
+
key: 'a',
|
|
192
|
+
modifiers: { ctrl: true },
|
|
193
|
+
handler: () => state.selectAll(),
|
|
194
|
+
description: 'Select all',
|
|
195
|
+
readonly: true
|
|
196
|
+
});
|
|
197
|
+
// ============================================
|
|
198
|
+
// Editing (only when not readonly)
|
|
199
|
+
// ============================================
|
|
200
|
+
if (!options.readonly) {
|
|
201
|
+
keybindings.push(
|
|
202
|
+
// Basic input is handled by onInput, not keybindings
|
|
203
|
+
// Backspace
|
|
204
|
+
{
|
|
205
|
+
key: 'Backspace',
|
|
206
|
+
handler: () => state.deleteBackward(),
|
|
207
|
+
description: 'Delete character before cursor'
|
|
208
|
+
}, {
|
|
209
|
+
key: 'Backspace',
|
|
210
|
+
modifiers: { ctrl: true },
|
|
211
|
+
handler: () => {
|
|
212
|
+
// Delete word before cursor
|
|
213
|
+
nav.moveWordLeft(true);
|
|
214
|
+
state.deleteSelection();
|
|
215
|
+
},
|
|
216
|
+
description: 'Delete word before cursor'
|
|
217
|
+
},
|
|
218
|
+
// Delete
|
|
219
|
+
{
|
|
220
|
+
key: 'Delete',
|
|
221
|
+
handler: () => state.deleteForward(),
|
|
222
|
+
description: 'Delete character after cursor'
|
|
223
|
+
}, {
|
|
224
|
+
key: 'Delete',
|
|
225
|
+
modifiers: { ctrl: true },
|
|
226
|
+
handler: () => {
|
|
227
|
+
// Delete word after cursor
|
|
228
|
+
nav.moveWordRight(true);
|
|
229
|
+
state.deleteSelection();
|
|
230
|
+
},
|
|
231
|
+
description: 'Delete word after cursor'
|
|
232
|
+
},
|
|
233
|
+
// Enter
|
|
234
|
+
{
|
|
235
|
+
key: 'Enter',
|
|
236
|
+
handler: () => state.insertNewline(),
|
|
237
|
+
description: 'Insert new line'
|
|
238
|
+
},
|
|
239
|
+
// Tab
|
|
240
|
+
{
|
|
241
|
+
key: 'Tab',
|
|
242
|
+
handler: () => state.insertTab(),
|
|
243
|
+
description: 'Insert tab'
|
|
244
|
+
},
|
|
245
|
+
// Undo/Redo
|
|
246
|
+
{
|
|
247
|
+
key: 'z',
|
|
248
|
+
modifiers: { ctrl: true },
|
|
249
|
+
handler: () => state.undo(),
|
|
250
|
+
description: 'Undo'
|
|
251
|
+
}, {
|
|
252
|
+
key: 'z',
|
|
253
|
+
modifiers: { ctrl: true, shift: true },
|
|
254
|
+
handler: () => state.redo(),
|
|
255
|
+
description: 'Redo'
|
|
256
|
+
}, {
|
|
257
|
+
key: 'y',
|
|
258
|
+
modifiers: { ctrl: true },
|
|
259
|
+
handler: () => state.redo(),
|
|
260
|
+
description: 'Redo'
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
// ============================================
|
|
264
|
+
// Custom commands
|
|
265
|
+
// ============================================
|
|
266
|
+
if (options.onSave) {
|
|
267
|
+
keybindings.push({
|
|
268
|
+
key: 's',
|
|
269
|
+
modifiers: { ctrl: true },
|
|
270
|
+
handler: () => {
|
|
271
|
+
options.onSave();
|
|
272
|
+
return true;
|
|
273
|
+
},
|
|
274
|
+
description: 'Save',
|
|
275
|
+
readonly: true
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
return keybindings;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Keyboard handler class
|
|
282
|
+
*/
|
|
283
|
+
export class KeyboardHandler {
|
|
284
|
+
keybindings = [];
|
|
285
|
+
enabled = true;
|
|
286
|
+
/**
|
|
287
|
+
* Set keybindings
|
|
288
|
+
*/
|
|
289
|
+
setKeybindings(keybindings) {
|
|
290
|
+
this.keybindings = keybindings;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Add a keybinding
|
|
294
|
+
*/
|
|
295
|
+
addKeybinding(keybinding) {
|
|
296
|
+
this.keybindings.push(keybinding);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Remove a keybinding
|
|
300
|
+
*/
|
|
301
|
+
removeKeybinding(key, modifiers) {
|
|
302
|
+
this.keybindings = this.keybindings.filter((kb) => !(kb.key === key && this.modifiersEqual(kb.modifiers, modifiers)));
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Enable/disable keyboard handling
|
|
306
|
+
*/
|
|
307
|
+
setEnabled(enabled) {
|
|
308
|
+
this.enabled = enabled;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Handle a keyboard event
|
|
312
|
+
* Returns true if the event was handled
|
|
313
|
+
*/
|
|
314
|
+
handleKeyDown(e, readonly = false) {
|
|
315
|
+
if (!this.enabled) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
const key = normalizeKey(e);
|
|
319
|
+
// Find matching keybinding
|
|
320
|
+
for (const binding of this.keybindings) {
|
|
321
|
+
if (binding.key === key && modifiersMatch(e, binding.modifiers)) {
|
|
322
|
+
// Skip non-readonly bindings in readonly mode
|
|
323
|
+
if (readonly && !binding.readonly) {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const result = binding.handler();
|
|
327
|
+
if (result !== false) {
|
|
328
|
+
e.preventDefault();
|
|
329
|
+
e.stopPropagation();
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Check if modifiers are equal
|
|
338
|
+
*/
|
|
339
|
+
modifiersEqual(a, b) {
|
|
340
|
+
return ((a?.ctrl ?? false) === (b?.ctrl ?? false) &&
|
|
341
|
+
(a?.shift ?? false) === (b?.shift ?? false) &&
|
|
342
|
+
(a?.alt ?? false) === (b?.alt ?? false) &&
|
|
343
|
+
(a?.meta ?? false) === (b?.meta ?? false));
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Get all keybindings for documentation
|
|
347
|
+
*/
|
|
348
|
+
getKeybindings() {
|
|
349
|
+
return [...this.keybindings];
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Create keyboard handler
|
|
354
|
+
*/
|
|
355
|
+
export function createKeyboardHandler() {
|
|
356
|
+
return new KeyboardHandler();
|
|
357
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-cursor management for the custom editor
|
|
3
|
+
*
|
|
4
|
+
* Provides support for creating, managing, and editing with multiple cursors.
|
|
5
|
+
* Cursors can have selections and are automatically merged when they touch or overlap.
|
|
6
|
+
*/
|
|
7
|
+
import type { Position, Selection } from './state';
|
|
8
|
+
/**
|
|
9
|
+
* A single cursor with optional selection
|
|
10
|
+
*/
|
|
11
|
+
export interface Cursor {
|
|
12
|
+
/** Unique identifier */
|
|
13
|
+
id: string;
|
|
14
|
+
/** Selection range (anchor = head for no selection) */
|
|
15
|
+
selection: Selection;
|
|
16
|
+
/** Whether this is the primary cursor */
|
|
17
|
+
isPrimary: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Configuration for CursorManager
|
|
21
|
+
*/
|
|
22
|
+
export interface CursorManagerConfig {
|
|
23
|
+
/** Maximum number of cursors allowed (default: 100) */
|
|
24
|
+
maxCursors?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Compare two positions
|
|
28
|
+
* Returns negative if a < b, positive if a > b, 0 if equal
|
|
29
|
+
*/
|
|
30
|
+
export declare function comparePositions(a: Position, b: Position): number;
|
|
31
|
+
/**
|
|
32
|
+
* Check if position a is before position b
|
|
33
|
+
*/
|
|
34
|
+
export declare function isPositionBefore(a: Position, b: Position): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Check if position a is before or equal to position b
|
|
37
|
+
*/
|
|
38
|
+
export declare function isPositionBeforeOrEqual(a: Position, b: Position): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Check if two positions are equal
|
|
41
|
+
*/
|
|
42
|
+
export declare function positionsEqual(a: Position, b: Position): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Get the start position of a selection (min of anchor and head)
|
|
45
|
+
*/
|
|
46
|
+
export declare function getSelectionStart(selection: Selection): Position;
|
|
47
|
+
/**
|
|
48
|
+
* Get the end position of a selection (max of anchor and head)
|
|
49
|
+
*/
|
|
50
|
+
export declare function getSelectionEnd(selection: Selection): Position;
|
|
51
|
+
/**
|
|
52
|
+
* Check if a selection is empty (anchor equals head)
|
|
53
|
+
*/
|
|
54
|
+
export declare function isSelectionEmpty(selection: Selection): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Check if two selections overlap or touch
|
|
57
|
+
*/
|
|
58
|
+
export declare function selectionsOverlap(a: Selection, b: Selection): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Merge two selections into one (union)
|
|
61
|
+
*/
|
|
62
|
+
export declare function mergeSelections(a: Selection, b: Selection): Selection;
|
|
63
|
+
export declare class CursorManager {
|
|
64
|
+
private cursors;
|
|
65
|
+
private primaryId;
|
|
66
|
+
private nextId;
|
|
67
|
+
private maxCursors;
|
|
68
|
+
private listeners;
|
|
69
|
+
constructor(config?: CursorManagerConfig);
|
|
70
|
+
/**
|
|
71
|
+
* Get all cursors
|
|
72
|
+
*/
|
|
73
|
+
getCursors(): readonly Cursor[];
|
|
74
|
+
/**
|
|
75
|
+
* Get all cursors sorted by position (top to bottom, left to right)
|
|
76
|
+
*/
|
|
77
|
+
getSortedCursors(): Cursor[];
|
|
78
|
+
/**
|
|
79
|
+
* Get cursors sorted in reverse order (bottom to top)
|
|
80
|
+
* Useful for editing operations to maintain position validity
|
|
81
|
+
*/
|
|
82
|
+
getSortedCursorsReverse(): Cursor[];
|
|
83
|
+
/**
|
|
84
|
+
* Get the primary cursor
|
|
85
|
+
*/
|
|
86
|
+
getPrimary(): Cursor;
|
|
87
|
+
/**
|
|
88
|
+
* Get cursor count
|
|
89
|
+
*/
|
|
90
|
+
get count(): number;
|
|
91
|
+
/**
|
|
92
|
+
* Check if there are multiple cursors
|
|
93
|
+
*/
|
|
94
|
+
get hasMultiple(): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Add a new cursor at a position
|
|
97
|
+
* @param position - Position for the new cursor
|
|
98
|
+
* @param makePrimary - Make this the primary cursor
|
|
99
|
+
* @returns The new cursor, or null if at max capacity
|
|
100
|
+
*/
|
|
101
|
+
addCursor(position: Position, makePrimary?: boolean): Cursor;
|
|
102
|
+
/**
|
|
103
|
+
* Add a cursor with a selection
|
|
104
|
+
*/
|
|
105
|
+
addCursorWithSelection(anchor: Position, head: Position, makePrimary?: boolean): Cursor;
|
|
106
|
+
/**
|
|
107
|
+
* Remove a cursor by ID
|
|
108
|
+
* @returns true if removed, false if it was the last cursor
|
|
109
|
+
*/
|
|
110
|
+
removeCursor(id: string): boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Remove the last added secondary cursor (for Ctrl+U)
|
|
113
|
+
* @returns true if a cursor was removed
|
|
114
|
+
*/
|
|
115
|
+
removeLastSecondary(): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Clear all secondary cursors, keeping only the primary
|
|
118
|
+
*/
|
|
119
|
+
clearSecondary(): void;
|
|
120
|
+
/**
|
|
121
|
+
* Set the primary cursor
|
|
122
|
+
*/
|
|
123
|
+
setPrimary(id: string): void;
|
|
124
|
+
/**
|
|
125
|
+
* Set cursor position (clears selection)
|
|
126
|
+
*/
|
|
127
|
+
setCursor(id: string, position: Position): void;
|
|
128
|
+
/**
|
|
129
|
+
* Batch update cursor positions without triggering merge/emit on each update
|
|
130
|
+
* More efficient for updating multiple cursors at once
|
|
131
|
+
*/
|
|
132
|
+
batchUpdateCursors(updates: Array<{
|
|
133
|
+
id: string;
|
|
134
|
+
position: Position;
|
|
135
|
+
}>): void;
|
|
136
|
+
/**
|
|
137
|
+
* Set cursor selection
|
|
138
|
+
*/
|
|
139
|
+
setSelection(id: string, anchor: Position, head: Position): void;
|
|
140
|
+
/**
|
|
141
|
+
* Extend cursor selection (move head, keep anchor)
|
|
142
|
+
*/
|
|
143
|
+
extendSelection(id: string, head: Position): void;
|
|
144
|
+
/**
|
|
145
|
+
* Set all cursors to new positions (for single cursor operations)
|
|
146
|
+
*/
|
|
147
|
+
setSingleCursor(position: Position): void;
|
|
148
|
+
/**
|
|
149
|
+
* Set single cursor with selection
|
|
150
|
+
*/
|
|
151
|
+
setSingleSelection(anchor: Position, head: Position): void;
|
|
152
|
+
/**
|
|
153
|
+
* Check if any cursor contains a position
|
|
154
|
+
*/
|
|
155
|
+
isPositionInAnyCursor(position: Position): boolean;
|
|
156
|
+
/**
|
|
157
|
+
* Get the closest cursor to a position
|
|
158
|
+
*/
|
|
159
|
+
private getClosestCursor;
|
|
160
|
+
/**
|
|
161
|
+
* Merge overlapping or touching cursors
|
|
162
|
+
*/
|
|
163
|
+
private mergeTouchingCursors;
|
|
164
|
+
/**
|
|
165
|
+
* Add cursor above the current primary cursor
|
|
166
|
+
* @param lineCount - Number of lines in the document
|
|
167
|
+
*/
|
|
168
|
+
addCursorAbove(lineCount: number): boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Add cursor below the current primary cursor
|
|
171
|
+
* @param lineCount - Number of lines in the document
|
|
172
|
+
*/
|
|
173
|
+
addCursorBelow(lineCount: number): boolean;
|
|
174
|
+
/**
|
|
175
|
+
* Subscribe to cursor changes
|
|
176
|
+
* In development mode, throws an error to catch memory leaks early.
|
|
177
|
+
* In production, warns and evicts the oldest listener.
|
|
178
|
+
*/
|
|
179
|
+
onChange(callback: () => void): () => void;
|
|
180
|
+
private emit;
|
|
181
|
+
/**
|
|
182
|
+
* Restore cursors from a saved state (for undo/redo)
|
|
183
|
+
*/
|
|
184
|
+
restore(cursors: Cursor[], primaryId: string): void;
|
|
185
|
+
/**
|
|
186
|
+
* Clone the current state (for undo/redo)
|
|
187
|
+
*/
|
|
188
|
+
clone(): {
|
|
189
|
+
cursors: Cursor[];
|
|
190
|
+
primaryId: string;
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Create a new CursorManager
|
|
195
|
+
*/
|
|
196
|
+
export declare function createCursorManager(config?: CursorManagerConfig): CursorManager;
|