@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,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quick Actions (Code Actions) Manager
|
|
3
|
+
*
|
|
4
|
+
* Provides contextual code actions like:
|
|
5
|
+
* - Quick fixes for errors/warnings
|
|
6
|
+
* - Refactoring operations
|
|
7
|
+
* - Code generation
|
|
8
|
+
* - Import suggestions
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Quick Actions Manager
|
|
12
|
+
*/
|
|
13
|
+
export class QuickActionsManager {
|
|
14
|
+
_config = {
|
|
15
|
+
enabled: true,
|
|
16
|
+
showLightbulb: true,
|
|
17
|
+
autoShow: true,
|
|
18
|
+
showDelay: 300
|
|
19
|
+
};
|
|
20
|
+
_providers = new Map();
|
|
21
|
+
_currentActions = [];
|
|
22
|
+
_currentContext = null;
|
|
23
|
+
_listeners = new Set();
|
|
24
|
+
_showTimeout = null;
|
|
25
|
+
constructor() {
|
|
26
|
+
// Register built-in providers
|
|
27
|
+
this.registerBuiltinProviders();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Register built-in action providers
|
|
31
|
+
*/
|
|
32
|
+
registerBuiltinProviders() {
|
|
33
|
+
// Quick fix provider for common issues
|
|
34
|
+
this.registerProvider('quickfix', (ctx) => {
|
|
35
|
+
const actions = [];
|
|
36
|
+
// Fix for unused variables
|
|
37
|
+
if (ctx.lineContent.includes('const ') || ctx.lineContent.includes('let ')) {
|
|
38
|
+
const match = ctx.lineContent.match(/(?:const|let)\s+(\w+)/);
|
|
39
|
+
if (match) {
|
|
40
|
+
actions.push({
|
|
41
|
+
id: `remove-unused-${match[1]}`,
|
|
42
|
+
title: `Remove unused variable '${match[1]}'`,
|
|
43
|
+
kind: 'quickfix',
|
|
44
|
+
description: 'Remove the declaration of unused variable',
|
|
45
|
+
edit: {
|
|
46
|
+
changes: [{
|
|
47
|
+
range: {
|
|
48
|
+
start: { line: ctx.position.line, column: 0 },
|
|
49
|
+
end: { line: ctx.position.line + 1, column: 0 }
|
|
50
|
+
},
|
|
51
|
+
newText: ''
|
|
52
|
+
}]
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Add missing semicolon
|
|
58
|
+
if (!ctx.lineContent.trim().endsWith(';') &&
|
|
59
|
+
!ctx.lineContent.trim().endsWith('{') &&
|
|
60
|
+
!ctx.lineContent.trim().endsWith('}') &&
|
|
61
|
+
!ctx.lineContent.trim().endsWith(',') &&
|
|
62
|
+
ctx.lineContent.trim().length > 0) {
|
|
63
|
+
actions.push({
|
|
64
|
+
id: 'add-semicolon',
|
|
65
|
+
title: 'Add missing semicolon',
|
|
66
|
+
kind: 'quickfix',
|
|
67
|
+
isPreferred: true,
|
|
68
|
+
edit: {
|
|
69
|
+
changes: [{
|
|
70
|
+
range: {
|
|
71
|
+
start: { line: ctx.position.line, column: ctx.lineContent.trimEnd().length },
|
|
72
|
+
end: { line: ctx.position.line, column: ctx.lineContent.trimEnd().length }
|
|
73
|
+
},
|
|
74
|
+
newText: ';'
|
|
75
|
+
}]
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return actions;
|
|
80
|
+
});
|
|
81
|
+
// Refactoring provider
|
|
82
|
+
this.registerProvider('refactor', (ctx) => {
|
|
83
|
+
const actions = [];
|
|
84
|
+
// Extract to variable
|
|
85
|
+
if (ctx.selectedText && ctx.selectedText.length > 0) {
|
|
86
|
+
actions.push({
|
|
87
|
+
id: 'extract-variable',
|
|
88
|
+
title: 'Extract to variable',
|
|
89
|
+
kind: 'refactor.extract',
|
|
90
|
+
shortcut: 'Ctrl+Alt+V',
|
|
91
|
+
command: {
|
|
92
|
+
command: 'refactor.extractVariable',
|
|
93
|
+
title: 'Extract Variable',
|
|
94
|
+
arguments: [ctx.selection, ctx.selectedText]
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
// Extract to function
|
|
98
|
+
if (ctx.selectedText.includes('\n') || ctx.selectedText.length > 50) {
|
|
99
|
+
actions.push({
|
|
100
|
+
id: 'extract-function',
|
|
101
|
+
title: 'Extract to function',
|
|
102
|
+
kind: 'refactor.extract',
|
|
103
|
+
shortcut: 'Ctrl+Alt+M',
|
|
104
|
+
command: {
|
|
105
|
+
command: 'refactor.extractFunction',
|
|
106
|
+
title: 'Extract Function',
|
|
107
|
+
arguments: [ctx.selection, ctx.selectedText]
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Rename symbol
|
|
113
|
+
const wordMatch = ctx.lineContent.substring(0, ctx.position.column).match(/\w+$/);
|
|
114
|
+
if (wordMatch) {
|
|
115
|
+
actions.push({
|
|
116
|
+
id: 'rename-symbol',
|
|
117
|
+
title: `Rename '${wordMatch[0]}'`,
|
|
118
|
+
kind: 'refactor.rename',
|
|
119
|
+
shortcut: 'F2',
|
|
120
|
+
command: {
|
|
121
|
+
command: 'refactor.rename',
|
|
122
|
+
title: 'Rename Symbol',
|
|
123
|
+
arguments: [ctx.position, wordMatch[0]]
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
// Convert to arrow function
|
|
128
|
+
if (ctx.lineContent.includes('function ')) {
|
|
129
|
+
actions.push({
|
|
130
|
+
id: 'convert-to-arrow',
|
|
131
|
+
title: 'Convert to arrow function',
|
|
132
|
+
kind: 'refactor',
|
|
133
|
+
description: 'Convert function declaration to arrow function expression'
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Convert to template literal
|
|
137
|
+
if (ctx.lineContent.includes(' + ') && (ctx.lineContent.includes('"') || ctx.lineContent.includes("'"))) {
|
|
138
|
+
actions.push({
|
|
139
|
+
id: 'convert-to-template',
|
|
140
|
+
title: 'Convert to template literal',
|
|
141
|
+
kind: 'refactor',
|
|
142
|
+
description: 'Convert string concatenation to template literal'
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return actions;
|
|
146
|
+
});
|
|
147
|
+
// Source actions provider
|
|
148
|
+
this.registerProvider('source', (ctx) => {
|
|
149
|
+
const actions = [];
|
|
150
|
+
// Organize imports
|
|
151
|
+
if (ctx.lineContent.includes('import ') || ctx.position.line < 20) {
|
|
152
|
+
actions.push({
|
|
153
|
+
id: 'organize-imports',
|
|
154
|
+
title: 'Organize imports',
|
|
155
|
+
kind: 'source.organizeImports',
|
|
156
|
+
shortcut: 'Shift+Alt+O',
|
|
157
|
+
command: {
|
|
158
|
+
command: 'source.organizeImports',
|
|
159
|
+
title: 'Organize Imports'
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
// Fix all auto-fixable issues
|
|
164
|
+
actions.push({
|
|
165
|
+
id: 'fix-all',
|
|
166
|
+
title: 'Fix all auto-fixable problems',
|
|
167
|
+
kind: 'source.fixAll',
|
|
168
|
+
command: {
|
|
169
|
+
command: 'source.fixAll',
|
|
170
|
+
title: 'Fix All'
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
return actions;
|
|
174
|
+
});
|
|
175
|
+
// Generate actions provider
|
|
176
|
+
this.registerProvider('generate', (ctx) => {
|
|
177
|
+
const actions = [];
|
|
178
|
+
// Generate JSDoc
|
|
179
|
+
if (ctx.lineContent.includes('function ') ||
|
|
180
|
+
ctx.lineContent.includes('const ') ||
|
|
181
|
+
ctx.lineContent.includes('class ')) {
|
|
182
|
+
actions.push({
|
|
183
|
+
id: 'generate-jsdoc',
|
|
184
|
+
title: 'Generate JSDoc comment',
|
|
185
|
+
kind: 'generate',
|
|
186
|
+
description: 'Add documentation comment above declaration'
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
// Generate getter/setter (for class properties)
|
|
190
|
+
if (ctx.lineContent.includes('private ') || ctx.lineContent.includes('protected ')) {
|
|
191
|
+
const propMatch = ctx.lineContent.match(/(?:private|protected)\s+(\w+)/);
|
|
192
|
+
if (propMatch) {
|
|
193
|
+
actions.push({
|
|
194
|
+
id: 'generate-getter',
|
|
195
|
+
title: `Generate getter for '${propMatch[1]}'`,
|
|
196
|
+
kind: 'generate'
|
|
197
|
+
});
|
|
198
|
+
actions.push({
|
|
199
|
+
id: 'generate-setter',
|
|
200
|
+
title: `Generate setter for '${propMatch[1]}'`,
|
|
201
|
+
kind: 'generate'
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Generate constructor
|
|
206
|
+
if (ctx.lineContent.includes('class ')) {
|
|
207
|
+
actions.push({
|
|
208
|
+
id: 'generate-constructor',
|
|
209
|
+
title: 'Generate constructor',
|
|
210
|
+
kind: 'generate'
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return actions;
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Register a code action provider
|
|
218
|
+
*/
|
|
219
|
+
registerProvider(id, provider) {
|
|
220
|
+
this._providers.set(id, provider);
|
|
221
|
+
return () => this._providers.delete(id);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get available actions for context
|
|
225
|
+
*/
|
|
226
|
+
getActions(context) {
|
|
227
|
+
if (!this._config.enabled)
|
|
228
|
+
return [];
|
|
229
|
+
const actions = [];
|
|
230
|
+
for (const provider of this._providers.values()) {
|
|
231
|
+
try {
|
|
232
|
+
const providerActions = provider(context);
|
|
233
|
+
actions.push(...providerActions);
|
|
234
|
+
}
|
|
235
|
+
catch (e) {
|
|
236
|
+
console.error('Code action provider error:', e);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Sort by kind and preferred status
|
|
240
|
+
return actions.sort((a, b) => {
|
|
241
|
+
// Preferred actions first
|
|
242
|
+
if (a.isPreferred && !b.isPreferred)
|
|
243
|
+
return -1;
|
|
244
|
+
if (!a.isPreferred && b.isPreferred)
|
|
245
|
+
return 1;
|
|
246
|
+
// Then by kind priority
|
|
247
|
+
const kindPriority = {
|
|
248
|
+
'quickfix': 0,
|
|
249
|
+
'refactor.extract': 1,
|
|
250
|
+
'refactor.inline': 2,
|
|
251
|
+
'refactor.rename': 3,
|
|
252
|
+
'refactor': 4,
|
|
253
|
+
'source.organizeImports': 5,
|
|
254
|
+
'source.fixAll': 6,
|
|
255
|
+
'source': 7,
|
|
256
|
+
'generate': 8
|
|
257
|
+
};
|
|
258
|
+
return (kindPriority[a.kind] ?? 99) - (kindPriority[b.kind] ?? 99);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Update context and refresh actions
|
|
263
|
+
*/
|
|
264
|
+
updateContext(context) {
|
|
265
|
+
if (this._showTimeout) {
|
|
266
|
+
clearTimeout(this._showTimeout);
|
|
267
|
+
}
|
|
268
|
+
if (!this._config.autoShow) {
|
|
269
|
+
this._currentContext = context;
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
this._showTimeout = setTimeout(() => {
|
|
273
|
+
this._currentContext = context;
|
|
274
|
+
this._currentActions = this.getActions(context);
|
|
275
|
+
this.notify();
|
|
276
|
+
}, this._config.showDelay);
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Force refresh actions
|
|
280
|
+
*/
|
|
281
|
+
refresh() {
|
|
282
|
+
if (this._currentContext) {
|
|
283
|
+
this._currentActions = this.getActions(this._currentContext);
|
|
284
|
+
this.notify();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Execute a code action
|
|
289
|
+
*/
|
|
290
|
+
async executeAction(action) {
|
|
291
|
+
if (action.disabled) {
|
|
292
|
+
console.warn('Cannot execute disabled action:', action.disabledReason);
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
// If action has an edit, apply it
|
|
296
|
+
if (action.edit) {
|
|
297
|
+
// The edit would be applied by the editor
|
|
298
|
+
// Return the edit for the caller to handle
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
// If action has a command, execute it
|
|
302
|
+
if (action.command) {
|
|
303
|
+
// The command would be executed by the editor
|
|
304
|
+
// Return true to indicate the action was triggered
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Get current actions
|
|
311
|
+
*/
|
|
312
|
+
get currentActions() {
|
|
313
|
+
return this._currentActions;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Check if actions are available
|
|
317
|
+
*/
|
|
318
|
+
get hasActions() {
|
|
319
|
+
return this._currentActions.length > 0;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Get config
|
|
323
|
+
*/
|
|
324
|
+
get config() {
|
|
325
|
+
return { ...this._config };
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Update config
|
|
329
|
+
*/
|
|
330
|
+
setConfig(config) {
|
|
331
|
+
this._config = { ...this._config, ...config };
|
|
332
|
+
this.notify();
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Enable/disable quick actions
|
|
336
|
+
*/
|
|
337
|
+
setEnabled(enabled) {
|
|
338
|
+
this._config.enabled = enabled;
|
|
339
|
+
if (!enabled) {
|
|
340
|
+
this._currentActions = [];
|
|
341
|
+
}
|
|
342
|
+
this.notify();
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Check if enabled
|
|
346
|
+
*/
|
|
347
|
+
isEnabled() {
|
|
348
|
+
return this._config.enabled;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Subscribe to changes
|
|
352
|
+
*/
|
|
353
|
+
subscribe(listener) {
|
|
354
|
+
this._listeners.add(listener);
|
|
355
|
+
return () => this._listeners.delete(listener);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Notify listeners
|
|
359
|
+
*/
|
|
360
|
+
notify() {
|
|
361
|
+
for (const listener of this._listeners) {
|
|
362
|
+
listener();
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Clean up
|
|
367
|
+
*/
|
|
368
|
+
destroy() {
|
|
369
|
+
if (this._showTimeout) {
|
|
370
|
+
clearTimeout(this._showTimeout);
|
|
371
|
+
}
|
|
372
|
+
this._listeners.clear();
|
|
373
|
+
this._providers.clear();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Create a new QuickActionsManager instance
|
|
378
|
+
*/
|
|
379
|
+
export function createQuickActionsManager() {
|
|
380
|
+
return new QuickActionsManager();
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Group actions by kind for display
|
|
384
|
+
*/
|
|
385
|
+
export function groupActionsByKind(actions) {
|
|
386
|
+
const groups = new Map();
|
|
387
|
+
for (const action of actions) {
|
|
388
|
+
// Get the base kind (e.g., "refactor" from "refactor.extract")
|
|
389
|
+
const baseKind = action.kind.split('.')[0];
|
|
390
|
+
const kindLabel = getKindLabel(baseKind);
|
|
391
|
+
if (!groups.has(kindLabel)) {
|
|
392
|
+
groups.set(kindLabel, []);
|
|
393
|
+
}
|
|
394
|
+
groups.get(kindLabel).push(action);
|
|
395
|
+
}
|
|
396
|
+
return groups;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Get display label for action kind
|
|
400
|
+
*/
|
|
401
|
+
export function getKindLabel(kind) {
|
|
402
|
+
const labels = {
|
|
403
|
+
'quickfix': 'Quick Fix',
|
|
404
|
+
'refactor': 'Refactor',
|
|
405
|
+
'source': 'Source Action',
|
|
406
|
+
'generate': 'Generate'
|
|
407
|
+
};
|
|
408
|
+
const baseKind = kind.split('.')[0];
|
|
409
|
+
return labels[baseKind] || kind;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Get icon for action kind
|
|
413
|
+
*/
|
|
414
|
+
export function getKindIcon(kind) {
|
|
415
|
+
const icons = {
|
|
416
|
+
'quickfix': '🔧',
|
|
417
|
+
'refactor': '✨',
|
|
418
|
+
'refactor.extract': '📤',
|
|
419
|
+
'refactor.inline': '📥',
|
|
420
|
+
'refactor.rename': '✏️',
|
|
421
|
+
'source': '📋',
|
|
422
|
+
'source.organizeImports': '📦',
|
|
423
|
+
'source.fixAll': '✅',
|
|
424
|
+
'generate': '⚡'
|
|
425
|
+
};
|
|
426
|
+
return icons[kind] || icons[kind.split('.')[0]] || '💡';
|
|
427
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search utilities for find and replace functionality
|
|
3
|
+
*/
|
|
4
|
+
import type { Position } from './state';
|
|
5
|
+
export interface SearchMatch {
|
|
6
|
+
/** Start position of match */
|
|
7
|
+
start: Position;
|
|
8
|
+
/** End position of match */
|
|
9
|
+
end: Position;
|
|
10
|
+
/** The matched text */
|
|
11
|
+
text: string;
|
|
12
|
+
/** Line index (0-based) */
|
|
13
|
+
line: number;
|
|
14
|
+
/** Start column in line */
|
|
15
|
+
startColumn: number;
|
|
16
|
+
/** End column in line */
|
|
17
|
+
endColumn: number;
|
|
18
|
+
}
|
|
19
|
+
export interface SearchOptions {
|
|
20
|
+
/** Case sensitive search */
|
|
21
|
+
caseSensitive?: boolean;
|
|
22
|
+
/** Use regular expression */
|
|
23
|
+
useRegex?: boolean;
|
|
24
|
+
/** Wrap around when reaching end of document */
|
|
25
|
+
wrapAround?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface SearchState {
|
|
28
|
+
/** Current search query */
|
|
29
|
+
query: string;
|
|
30
|
+
/** Search options */
|
|
31
|
+
options: SearchOptions;
|
|
32
|
+
/** All matches in document */
|
|
33
|
+
matches: SearchMatch[];
|
|
34
|
+
/** Current match index (0-based) */
|
|
35
|
+
currentIndex: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create initial search state
|
|
39
|
+
*/
|
|
40
|
+
export declare function createSearchState(): SearchState;
|
|
41
|
+
/**
|
|
42
|
+
* Find all matches in content
|
|
43
|
+
*/
|
|
44
|
+
export declare function findAllMatches(lines: readonly {
|
|
45
|
+
text: string;
|
|
46
|
+
}[], query: string, options?: SearchOptions): SearchMatch[];
|
|
47
|
+
/**
|
|
48
|
+
* Find the match index closest to a position (at or after)
|
|
49
|
+
*/
|
|
50
|
+
export declare function findMatchIndexAtOrAfter(matches: SearchMatch[], position: Position): number;
|
|
51
|
+
/**
|
|
52
|
+
* Find the match index closest to a position (at or before)
|
|
53
|
+
*/
|
|
54
|
+
export declare function findMatchIndexAtOrBefore(matches: SearchMatch[], position: Position): number;
|
|
55
|
+
/**
|
|
56
|
+
* Get next match index (with wrap-around)
|
|
57
|
+
*/
|
|
58
|
+
export declare function getNextMatchIndex(matches: SearchMatch[], currentIndex: number, wrapAround?: boolean): number;
|
|
59
|
+
/**
|
|
60
|
+
* Get previous match index (with wrap-around)
|
|
61
|
+
*/
|
|
62
|
+
export declare function getPrevMatchIndex(matches: SearchMatch[], currentIndex: number, wrapAround?: boolean): number;
|
|
63
|
+
/**
|
|
64
|
+
* Replace text at a match position
|
|
65
|
+
* Returns the new content and adjusted cursor position
|
|
66
|
+
*/
|
|
67
|
+
export declare function replaceMatch(lines: readonly {
|
|
68
|
+
text: string;
|
|
69
|
+
}[], match: SearchMatch, replacement: string): {
|
|
70
|
+
newLines: string[];
|
|
71
|
+
cursorPosition: Position;
|
|
72
|
+
lengthDiff: number;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Replace all matches
|
|
76
|
+
* Returns the new content
|
|
77
|
+
*/
|
|
78
|
+
export declare function replaceAllMatches(lines: readonly {
|
|
79
|
+
text: string;
|
|
80
|
+
}[], matches: SearchMatch[], replacement: string): string[];
|
|
81
|
+
/**
|
|
82
|
+
* Check if a position is within a match
|
|
83
|
+
*/
|
|
84
|
+
export declare function isPositionInMatch(position: Position, match: SearchMatch): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Find match at exact position (if cursor is inside a match)
|
|
87
|
+
*/
|
|
88
|
+
export declare function findMatchAtPosition(matches: SearchMatch[], position: Position): number;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search utilities for find and replace functionality
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Create initial search state
|
|
6
|
+
*/
|
|
7
|
+
export function createSearchState() {
|
|
8
|
+
return {
|
|
9
|
+
query: '',
|
|
10
|
+
options: {
|
|
11
|
+
caseSensitive: false,
|
|
12
|
+
useRegex: false,
|
|
13
|
+
wrapAround: true
|
|
14
|
+
},
|
|
15
|
+
matches: [],
|
|
16
|
+
currentIndex: -1
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Find all matches in content
|
|
21
|
+
*/
|
|
22
|
+
export function findAllMatches(lines, query, options = {}) {
|
|
23
|
+
if (!query)
|
|
24
|
+
return [];
|
|
25
|
+
const matches = [];
|
|
26
|
+
const { caseSensitive = false, useRegex = false } = options;
|
|
27
|
+
let searchPattern;
|
|
28
|
+
try {
|
|
29
|
+
if (useRegex) {
|
|
30
|
+
searchPattern = new RegExp(query, caseSensitive ? 'g' : 'gi');
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// Escape regex special characters for literal search
|
|
34
|
+
const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
35
|
+
searchPattern = new RegExp(escaped, caseSensitive ? 'g' : 'gi');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Invalid regex - return empty matches
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
43
|
+
const line = lines[lineIndex];
|
|
44
|
+
const text = line.text;
|
|
45
|
+
let match;
|
|
46
|
+
// Reset lastIndex for each line
|
|
47
|
+
searchPattern.lastIndex = 0;
|
|
48
|
+
while ((match = searchPattern.exec(text)) !== null) {
|
|
49
|
+
const startColumn = match.index;
|
|
50
|
+
const endColumn = match.index + match[0].length;
|
|
51
|
+
matches.push({
|
|
52
|
+
start: { line: lineIndex, column: startColumn },
|
|
53
|
+
end: { line: lineIndex, column: endColumn },
|
|
54
|
+
text: match[0],
|
|
55
|
+
line: lineIndex,
|
|
56
|
+
startColumn,
|
|
57
|
+
endColumn
|
|
58
|
+
});
|
|
59
|
+
// Prevent infinite loop on zero-width matches
|
|
60
|
+
if (match[0].length === 0) {
|
|
61
|
+
searchPattern.lastIndex++;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return matches;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Find the match index closest to a position (at or after)
|
|
69
|
+
*/
|
|
70
|
+
export function findMatchIndexAtOrAfter(matches, position) {
|
|
71
|
+
if (matches.length === 0)
|
|
72
|
+
return -1;
|
|
73
|
+
for (let i = 0; i < matches.length; i++) {
|
|
74
|
+
const match = matches[i];
|
|
75
|
+
// Match is at or after position
|
|
76
|
+
if (match.line > position.line ||
|
|
77
|
+
(match.line === position.line && match.startColumn >= position.column)) {
|
|
78
|
+
return i;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// No match at or after position - wrap to first match
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Find the match index closest to a position (at or before)
|
|
86
|
+
*/
|
|
87
|
+
export function findMatchIndexAtOrBefore(matches, position) {
|
|
88
|
+
if (matches.length === 0)
|
|
89
|
+
return -1;
|
|
90
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
91
|
+
const match = matches[i];
|
|
92
|
+
// Match is at or before position
|
|
93
|
+
if (match.line < position.line ||
|
|
94
|
+
(match.line === position.line && match.endColumn <= position.column)) {
|
|
95
|
+
return i;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// No match at or before position - wrap to last match
|
|
99
|
+
return matches.length - 1;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get next match index (with wrap-around)
|
|
103
|
+
*/
|
|
104
|
+
export function getNextMatchIndex(matches, currentIndex, wrapAround = true) {
|
|
105
|
+
if (matches.length === 0)
|
|
106
|
+
return -1;
|
|
107
|
+
if (currentIndex < 0)
|
|
108
|
+
return 0;
|
|
109
|
+
const next = currentIndex + 1;
|
|
110
|
+
if (next >= matches.length) {
|
|
111
|
+
return wrapAround ? 0 : currentIndex;
|
|
112
|
+
}
|
|
113
|
+
return next;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get previous match index (with wrap-around)
|
|
117
|
+
*/
|
|
118
|
+
export function getPrevMatchIndex(matches, currentIndex, wrapAround = true) {
|
|
119
|
+
if (matches.length === 0)
|
|
120
|
+
return -1;
|
|
121
|
+
if (currentIndex < 0)
|
|
122
|
+
return matches.length - 1;
|
|
123
|
+
const prev = currentIndex - 1;
|
|
124
|
+
if (prev < 0) {
|
|
125
|
+
return wrapAround ? matches.length - 1 : currentIndex;
|
|
126
|
+
}
|
|
127
|
+
return prev;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Replace text at a match position
|
|
131
|
+
* Returns the new content and adjusted cursor position
|
|
132
|
+
*/
|
|
133
|
+
export function replaceMatch(lines, match, replacement) {
|
|
134
|
+
const newLines = lines.map((l) => l.text);
|
|
135
|
+
const line = newLines[match.line];
|
|
136
|
+
// Replace the match
|
|
137
|
+
newLines[match.line] =
|
|
138
|
+
line.substring(0, match.startColumn) +
|
|
139
|
+
replacement +
|
|
140
|
+
line.substring(match.endColumn);
|
|
141
|
+
const lengthDiff = replacement.length - match.text.length;
|
|
142
|
+
return {
|
|
143
|
+
newLines,
|
|
144
|
+
cursorPosition: {
|
|
145
|
+
line: match.line,
|
|
146
|
+
column: match.startColumn + replacement.length
|
|
147
|
+
},
|
|
148
|
+
lengthDiff
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Replace all matches
|
|
153
|
+
* Returns the new content
|
|
154
|
+
*/
|
|
155
|
+
export function replaceAllMatches(lines, matches, replacement) {
|
|
156
|
+
if (matches.length === 0)
|
|
157
|
+
return lines.map((l) => l.text);
|
|
158
|
+
const newLines = lines.map((l) => l.text);
|
|
159
|
+
// Process matches in reverse order to maintain correct positions
|
|
160
|
+
const sortedMatches = [...matches].sort((a, b) => {
|
|
161
|
+
if (a.line !== b.line)
|
|
162
|
+
return b.line - a.line;
|
|
163
|
+
return b.startColumn - a.startColumn;
|
|
164
|
+
});
|
|
165
|
+
for (const match of sortedMatches) {
|
|
166
|
+
const line = newLines[match.line];
|
|
167
|
+
newLines[match.line] =
|
|
168
|
+
line.substring(0, match.startColumn) +
|
|
169
|
+
replacement +
|
|
170
|
+
line.substring(match.endColumn);
|
|
171
|
+
}
|
|
172
|
+
return newLines;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Check if a position is within a match
|
|
176
|
+
*/
|
|
177
|
+
export function isPositionInMatch(position, match) {
|
|
178
|
+
if (position.line !== match.line)
|
|
179
|
+
return false;
|
|
180
|
+
return position.column >= match.startColumn && position.column < match.endColumn;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Find match at exact position (if cursor is inside a match)
|
|
184
|
+
*/
|
|
185
|
+
export function findMatchAtPosition(matches, position) {
|
|
186
|
+
for (let i = 0; i < matches.length; i++) {
|
|
187
|
+
if (isPositionInMatch(position, matches[i])) {
|
|
188
|
+
return i;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return -1;
|
|
192
|
+
}
|