indusagi 0.12.16 → 0.12.18
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 +0 -1
- package/dist/agent/agent.d.ts +2 -108
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +17 -210
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/event-bus.js +3 -1
- package/dist/agent/event-bus.js.map +1 -1
- package/dist/agent/index.d.ts +5 -11
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +8 -19
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/messages.d.ts +48 -2
- package/dist/agent/messages.d.ts.map +1 -1
- package/dist/agent/messages.js.map +1 -1
- package/dist/agent/proxy.js.map +1 -1
- package/dist/agent/session-manager.d.ts +3 -2
- package/dist/agent/session-manager.d.ts.map +1 -1
- package/dist/agent/session-manager.js +6 -10
- package/dist/agent/session-manager.js.map +1 -1
- package/dist/agent/state-manager.js +0 -1
- package/dist/agent/state-manager.js.map +1 -1
- package/dist/agent/telemetry.js +3 -1
- package/dist/agent/telemetry.js.map +1 -1
- package/dist/agent/tools/bash.js +0 -1
- package/dist/agent/tools/bash.js.map +1 -1
- package/dist/agent/tools/index.d.ts +26 -26
- package/dist/agent/tools/registry.js +4 -2
- package/dist/agent/tools/registry.js.map +1 -1
- package/dist/agent/tools/todo-store.js +1 -2
- package/dist/agent/tools/todo-store.js.map +1 -1
- package/dist/agent/tools/utils/hook-runner.js +3 -1
- package/dist/agent/tools/utils/hook-runner.js.map +1 -1
- package/dist/agent/types.d.ts +1 -138
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/ai/api-registry.js +3 -1
- package/dist/ai/api-registry.js.map +1 -1
- package/dist/ai/models.generated.d.ts +34 -0
- package/dist/ai/models.generated.d.ts.map +1 -1
- package/dist/ai/models.generated.js +34 -0
- package/dist/ai/models.generated.js.map +1 -1
- package/dist/ai/models.js +0 -1
- package/dist/ai/models.js.map +1 -1
- package/dist/ai/providers/amazon-bedrock.d.ts +0 -6
- package/dist/ai/providers/amazon-bedrock.d.ts.map +1 -1
- package/dist/ai/providers/amazon-bedrock.js +9 -47
- package/dist/ai/providers/amazon-bedrock.js.map +1 -1
- package/dist/ai/providers/anthropic.d.ts +0 -8
- package/dist/ai/providers/anthropic.d.ts.map +1 -1
- package/dist/ai/providers/anthropic.js +12 -28
- package/dist/ai/providers/anthropic.js.map +1 -1
- package/dist/ai/providers/azure-openai-responses.js +0 -1
- package/dist/ai/providers/azure-openai-responses.js.map +1 -1
- package/dist/ai/providers/google-shared.d.ts.map +1 -1
- package/dist/ai/providers/google-shared.js +22 -16
- package/dist/ai/providers/google-shared.js.map +1 -1
- package/dist/ai/providers/google-vertex.d.ts.map +1 -1
- package/dist/ai/providers/google-vertex.js +5 -28
- package/dist/ai/providers/google-vertex.js.map +1 -1
- package/dist/ai/providers/google.js +0 -1
- package/dist/ai/providers/google.js.map +1 -1
- package/dist/ai/providers/kimi.js +0 -1
- package/dist/ai/providers/kimi.js.map +1 -1
- package/dist/ai/providers/openai-codex-responses.js +0 -1
- package/dist/ai/providers/openai-codex-responses.js.map +1 -1
- package/dist/ai/providers/openai-completions.js +0 -2
- package/dist/ai/providers/openai-completions.js.map +1 -1
- package/dist/ai/providers/openai-responses.d.ts.map +1 -1
- package/dist/ai/providers/openai-responses.js +0 -30
- package/dist/ai/providers/openai-responses.js.map +1 -1
- package/dist/ai/providers/register-builtins.d.ts.map +1 -1
- package/dist/ai/providers/register-builtins.js +0 -6
- package/dist/ai/providers/register-builtins.js.map +1 -1
- package/dist/ai/providers/simple-options.js +0 -2
- package/dist/ai/providers/simple-options.js.map +1 -1
- package/dist/ai/providers/transform-messages.js +9 -3
- package/dist/ai/providers/transform-messages.js.map +1 -1
- package/dist/ai/stream.js +3 -1
- package/dist/ai/stream.js.map +1 -1
- package/dist/ai/types.d.ts +0 -34
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/types.js.map +1 -1
- package/dist/ai/utils/base-stream-handler.js +0 -1
- package/dist/ai/utils/base-stream-handler.js.map +1 -1
- package/dist/ai/utils/event-stream.js +4 -9
- package/dist/ai/utils/event-stream.js.map +1 -1
- package/dist/ai/utils/index.d.ts +0 -1
- package/dist/ai/utils/index.d.ts.map +1 -1
- package/dist/ai/utils/index.js +0 -1
- package/dist/ai/utils/index.js.map +1 -1
- package/dist/ai/utils/oauth/github-copilot.d.ts.map +1 -1
- package/dist/ai/utils/oauth/github-copilot.js +8 -19
- package/dist/ai/utils/oauth/github-copilot.js.map +1 -1
- package/dist/ai/utils/overflow.d.ts.map +1 -1
- package/dist/ai/utils/overflow.js +0 -4
- package/dist/ai/utils/overflow.js.map +1 -1
- package/dist/ai/utils/provider-adapter.js +0 -9
- package/dist/ai/utils/provider-adapter.js.map +1 -1
- package/dist/ai/utils/provider-client-builder.js +1 -1
- package/dist/ai/utils/provider-client-builder.js.map +1 -1
- package/dist/ai/utils/provider-errors.js +0 -2
- package/dist/ai/utils/provider-errors.js.map +1 -1
- package/dist/ai/utils/stream-event-helper.js +0 -3
- package/dist/ai/utils/stream-event-helper.js.map +1 -1
- package/dist/ai/utils/stream-handler-types.js +0 -5
- package/dist/ai/utils/stream-handler-types.js.map +1 -1
- package/dist/ai/utils/streaming-state-manager.js +2 -4
- package/dist/ai/utils/streaming-state-manager.js.map +1 -1
- package/dist/mcp/client-pool.js +2 -3
- package/dist/mcp/client-pool.js.map +1 -1
- package/dist/mcp/client.js +5 -18
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/errors.js +0 -8
- package/dist/mcp/errors.js.map +1 -1
- package/dist/mcp/server.js +3 -8
- package/dist/mcp/server.js.map +1 -1
- package/dist/memory/embedder/openai.js +1 -7
- package/dist/memory/embedder/openai.js.map +1 -1
- package/dist/memory/memory.js +1 -6
- package/dist/memory/memory.js.map +1 -1
- package/dist/memory/processors/message-history.js +2 -4
- package/dist/memory/processors/message-history.js.map +1 -1
- package/dist/memory/processors/observational-memory/index.js +2 -7
- package/dist/memory/processors/observational-memory/index.js.map +1 -1
- package/dist/memory/processors/observational-memory/token-counter.js +3 -3
- package/dist/memory/processors/observational-memory/token-counter.js.map +1 -1
- package/dist/memory/processors/semantic-recall.js +2 -11
- package/dist/memory/processors/semantic-recall.js.map +1 -1
- package/dist/memory/processors/working-memory.js +2 -7
- package/dist/memory/processors/working-memory.js.map +1 -1
- package/dist/memory/storage/base.js +6 -4
- package/dist/memory/storage/base.js.map +1 -1
- package/dist/memory/storage/inmemory.js +2 -3
- package/dist/memory/storage/inmemory.js.map +1 -1
- package/dist/memory/vector/base.js +6 -4
- package/dist/memory/vector/base.js.map +1 -1
- package/dist/memory/vector/inmemory.js +5 -2
- package/dist/memory/vector/inmemory.js.map +1 -1
- package/dist/tui/autocomplete.js +1 -5
- package/dist/tui/autocomplete.js.map +1 -1
- package/dist/tui/components/box.js +1 -9
- package/dist/tui/components/box.js.map +1 -1
- package/dist/tui/components/cancellable-loader.js +4 -3
- package/dist/tui/components/cancellable-loader.js.map +1 -1
- package/dist/tui/components/editor.d.ts +3 -39
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +133 -162
- package/dist/tui/components/editor.js.map +1 -1
- package/dist/tui/components/image.js +0 -8
- package/dist/tui/components/image.js.map +1 -1
- package/dist/tui/components/input.js +11 -10
- package/dist/tui/components/input.js.map +1 -1
- package/dist/tui/components/loader.js +4 -7
- package/dist/tui/components/loader.js.map +1 -1
- package/dist/tui/components/markdown.js +0 -10
- package/dist/tui/components/markdown.js.map +1 -1
- package/dist/tui/components/select-list.js +4 -8
- package/dist/tui/components/select-list.js.map +1 -1
- package/dist/tui/components/settings-list.js +4 -12
- package/dist/tui/components/settings-list.js.map +1 -1
- package/dist/tui/components/spacer.js +0 -1
- package/dist/tui/components/spacer.js.map +1 -1
- package/dist/tui/components/text.js +0 -5
- package/dist/tui/components/text.js.map +1 -1
- package/dist/tui/components/truncated-text.js +0 -3
- package/dist/tui/components/truncated-text.js.map +1 -1
- package/dist/tui/fuzzy.js +1 -4
- package/dist/tui/fuzzy.js.map +1 -1
- package/dist/tui/keybindings.js +2 -3
- package/dist/tui/keybindings.js.map +1 -1
- package/dist/tui/keys.d.ts +1 -17
- package/dist/tui/keys.d.ts.map +1 -1
- package/dist/tui/keys.js +0 -56
- package/dist/tui/keys.js.map +1 -1
- package/dist/tui/stdin-buffer.js +5 -6
- package/dist/tui/stdin-buffer.js.map +1 -1
- package/dist/tui/terminal-image.js +3 -1
- package/dist/tui/terminal-image.js.map +1 -1
- package/dist/tui/terminal.d.ts +0 -13
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +7 -70
- package/dist/tui/terminal.js.map +1 -1
- package/dist/tui/tui.d.ts +0 -36
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +29 -101
- package/dist/tui/tui.js.map +1 -1
- package/dist/tui/utils.js +16 -12
- package/dist/tui/utils.js.map +1 -1
- package/package.json +1 -1
- package/dist/agent/agent-session.d.ts +0 -352
- package/dist/agent/agent-session.d.ts.map +0 -1
- package/dist/agent/agent-session.js +0 -870
- package/dist/agent/agent-session.js.map +0 -1
- package/dist/agent/agent-session.test.d.ts +0 -5
- package/dist/agent/agent-session.test.d.ts.map +0 -1
- package/dist/agent/agent-session.test.js +0 -129
- package/dist/agent/agent-session.test.js.map +0 -1
- package/dist/agent/bash-executor.d.ts +0 -33
- package/dist/agent/bash-executor.d.ts.map +0 -1
- package/dist/agent/bash-executor.js +0 -197
- package/dist/agent/bash-executor.js.map +0 -1
- package/dist/agent/compaction/compaction.d.ts +0 -87
- package/dist/agent/compaction/compaction.d.ts.map +0 -1
- package/dist/agent/compaction/compaction.js +0 -598
- package/dist/agent/compaction/compaction.js.map +0 -1
- package/dist/agent/compaction/index.d.ts +0 -6
- package/dist/agent/compaction/index.d.ts.map +0 -1
- package/dist/agent/compaction/index.js +0 -6
- package/dist/agent/compaction/index.js.map +0 -1
- package/dist/agent/compaction/utils.d.ts +0 -41
- package/dist/agent/compaction/utils.d.ts.map +0 -1
- package/dist/agent/compaction/utils.js +0 -240
- package/dist/agent/compaction/utils.js.map +0 -1
- package/dist/agent/settings-manager.d.ts +0 -204
- package/dist/agent/settings-manager.d.ts.map +0 -1
- package/dist/agent/settings-manager.js +0 -594
- package/dist/agent/settings-manager.js.map +0 -1
- package/dist/agent/tools/edit.test.d.ts +0 -6
- package/dist/agent/tools/edit.test.d.ts.map +0 -1
- package/dist/agent/tools/edit.test.js +0 -196
- package/dist/agent/tools/edit.test.js.map +0 -1
- package/dist/ai/providers/github-copilot-headers.d.ts +0 -33
- package/dist/ai/providers/github-copilot-headers.d.ts.map +0 -1
- package/dist/ai/providers/github-copilot-headers.js +0 -51
- package/dist/ai/providers/github-copilot-headers.js.map +0 -1
- package/dist/ai/providers/mistral.d.ts +0 -22
- package/dist/ai/providers/mistral.d.ts.map +0 -1
- package/dist/ai/providers/mistral.js +0 -497
- package/dist/ai/providers/mistral.js.map +0 -1
- package/dist/ai/types.test.d.ts +0 -8
- package/dist/ai/types.test.d.ts.map +0 -1
- package/dist/ai/types.test.js +0 -389
- package/dist/ai/types.test.js.map +0 -1
- package/dist/ai/utils/hash.d.ts +0 -6
- package/dist/ai/utils/hash.d.ts.map +0 -1
- package/dist/ai/utils/hash.js +0 -17
- package/dist/ai/utils/hash.js.map +0 -1
- package/dist/tui/kill-ring.d.ts +0 -28
- package/dist/tui/kill-ring.d.ts.map +0 -1
- package/dist/tui/kill-ring.js +0 -44
- package/dist/tui/kill-ring.js.map +0 -1
- package/dist/tui/undo-stack.d.ts +0 -17
- package/dist/tui/undo-stack.d.ts.map +0 -1
- package/dist/tui/undo-stack.js +0 -25
- package/dist/tui/undo-stack.js.map +0 -1
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { getEditorKeybindings } from "../keybindings.js";
|
|
2
|
-
import {
|
|
3
|
-
import { KillRing } from "../kill-ring.js";
|
|
2
|
+
import { matchesKey } from "../keys.js";
|
|
4
3
|
import { ComponentBase, CURSOR_MARKER } from "../tui.js";
|
|
5
|
-
import { UndoStack } from "../undo-stack.js";
|
|
6
4
|
import { getSegmenter, isPunctuationChar, isWhitespaceChar, visibleWidth } from "../utils.js";
|
|
7
5
|
import { SelectList } from "./select-list.js";
|
|
8
6
|
const segmenter = getSegmenter();
|
|
@@ -68,60 +66,81 @@ export function wordWrapLine(line, maxWidth) {
|
|
|
68
66
|
chunks.push({ text: line.slice(chunkStart), startIndex: chunkStart, endIndex: line.length });
|
|
69
67
|
return chunks;
|
|
70
68
|
}
|
|
69
|
+
// Kitty CSI-u sequences for printable keys, including optional shifted/base codepoints.
|
|
70
|
+
const KITTY_CSI_U_REGEX = /^\x1b\[(\d+)(?::(\d*))?(?::(\d+))?(?:;(\d+))?(?::(\d+))?u$/;
|
|
71
|
+
const KITTY_MOD_SHIFT = 1;
|
|
72
|
+
const KITTY_MOD_ALT = 2;
|
|
73
|
+
const KITTY_MOD_CTRL = 4;
|
|
74
|
+
// Decode a printable CSI-u sequence, preferring the shifted key when present.
|
|
75
|
+
function decodeKittyPrintable(data) {
|
|
76
|
+
const match = data.match(KITTY_CSI_U_REGEX);
|
|
77
|
+
if (!match)
|
|
78
|
+
return undefined;
|
|
79
|
+
// CSI-u groups: <codepoint>[:<shifted>[:<base>]];<mod>u
|
|
80
|
+
const codepoint = Number.parseInt(match[1] ?? "", 10);
|
|
81
|
+
if (!Number.isFinite(codepoint))
|
|
82
|
+
return undefined;
|
|
83
|
+
const shiftedKey = match[2] && match[2].length > 0 ? Number.parseInt(match[2], 10) : undefined;
|
|
84
|
+
const modValue = match[4] ? Number.parseInt(match[4], 10) : 1;
|
|
85
|
+
// Modifiers are 1-indexed in CSI-u; normalize to our bitmask.
|
|
86
|
+
const modifier = Number.isFinite(modValue) ? modValue - 1 : 0;
|
|
87
|
+
// Ignore CSI-u sequences used for Alt/Ctrl shortcuts.
|
|
88
|
+
if (modifier & (KITTY_MOD_ALT | KITTY_MOD_CTRL))
|
|
89
|
+
return undefined;
|
|
90
|
+
// Prefer the shifted keycode when Shift is held.
|
|
91
|
+
let effectiveCodepoint = codepoint;
|
|
92
|
+
if (modifier & KITTY_MOD_SHIFT && typeof shiftedKey === "number") {
|
|
93
|
+
effectiveCodepoint = shiftedKey;
|
|
94
|
+
}
|
|
95
|
+
// Drop control characters or invalid codepoints.
|
|
96
|
+
if (!Number.isFinite(effectiveCodepoint) || effectiveCodepoint < 32)
|
|
97
|
+
return undefined;
|
|
98
|
+
try {
|
|
99
|
+
return String.fromCodePoint(effectiveCodepoint);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
71
105
|
export class Editor extends ComponentBase {
|
|
72
|
-
state = {
|
|
73
|
-
lines: [""],
|
|
74
|
-
cursorLine: 0,
|
|
75
|
-
cursorCol: 0,
|
|
76
|
-
};
|
|
77
|
-
/** Focusable interface - set by TUI when focus changes */
|
|
78
|
-
focused = false;
|
|
79
|
-
tui;
|
|
80
|
-
theme;
|
|
81
|
-
paddingX = 0;
|
|
82
|
-
// Store last render width for cursor navigation
|
|
83
|
-
lastWidth = 80;
|
|
84
|
-
// Vertical scrolling support
|
|
85
|
-
scrollOffset = 0;
|
|
86
|
-
// Border color (can be changed dynamically)
|
|
87
|
-
borderColor;
|
|
88
|
-
// Autocomplete support
|
|
89
|
-
autocompleteProvider;
|
|
90
|
-
autocompleteList;
|
|
91
|
-
isAutocompleting = false;
|
|
92
|
-
autocompletePrefix = "";
|
|
93
|
-
autocompleteMaxVisible = 5;
|
|
94
|
-
// Paste tracking for large pastes
|
|
95
|
-
pastes = new Map();
|
|
96
|
-
pasteCounter = 0;
|
|
97
|
-
// Bracketed paste mode buffering
|
|
98
|
-
pasteBuffer = "";
|
|
99
|
-
isInPaste = false;
|
|
100
|
-
pendingShiftEnter = false;
|
|
101
|
-
// Prompt history for up/down navigation
|
|
102
|
-
history = [];
|
|
103
|
-
historyIndex = -1; // -1 = not browsing, 0 = most recent, 1 = older, etc.
|
|
104
|
-
// Kill ring for Emacs-style kill/yank operations
|
|
105
|
-
// Also tracks undo coalescing: "type-word" means we're mid-word (coalescing)
|
|
106
|
-
killRing = new KillRing();
|
|
107
|
-
lastAction = null;
|
|
108
|
-
// Undo support
|
|
109
|
-
undoStack = new UndoStack();
|
|
110
|
-
// Sticky column navigation for wrapped lines
|
|
111
|
-
// Maintains cursor column when moving up/down through lines of different lengths
|
|
112
|
-
preferredVisualCol = null;
|
|
113
|
-
onSubmit;
|
|
114
|
-
onChange;
|
|
115
|
-
disableSubmit = false;
|
|
116
106
|
constructor(tui, theme, options = {}) {
|
|
117
107
|
super();
|
|
108
|
+
this.state = {
|
|
109
|
+
lines: [""],
|
|
110
|
+
cursorLine: 0,
|
|
111
|
+
cursorCol: 0,
|
|
112
|
+
};
|
|
113
|
+
/** Focusable interface - set by TUI when focus changes */
|
|
114
|
+
this.focused = false;
|
|
115
|
+
this.paddingX = 0;
|
|
116
|
+
// Store last render width for cursor navigation
|
|
117
|
+
this.lastWidth = 80;
|
|
118
|
+
// Vertical scrolling support
|
|
119
|
+
this.scrollOffset = 0;
|
|
120
|
+
this.isAutocompleting = false;
|
|
121
|
+
this.autocompletePrefix = "";
|
|
122
|
+
// Paste tracking for large pastes
|
|
123
|
+
this.pastes = new Map();
|
|
124
|
+
this.pasteCounter = 0;
|
|
125
|
+
// Bracketed paste mode buffering
|
|
126
|
+
this.pasteBuffer = "";
|
|
127
|
+
this.isInPaste = false;
|
|
128
|
+
this.pendingShiftEnter = false;
|
|
129
|
+
// Prompt history for up/down navigation
|
|
130
|
+
this.history = [];
|
|
131
|
+
this.historyIndex = -1; // -1 = not browsing, 0 = most recent, 1 = older, etc.
|
|
132
|
+
// Kill ring for Emacs-style kill/yank operations
|
|
133
|
+
// Also tracks undo coalescing: "type-word" means we're mid-word (coalescing)
|
|
134
|
+
this.killRing = [];
|
|
135
|
+
this.lastAction = null;
|
|
136
|
+
// Undo support
|
|
137
|
+
this.undoStack = [];
|
|
138
|
+
this.disableSubmit = false;
|
|
118
139
|
this.tui = tui;
|
|
119
140
|
this.theme = theme;
|
|
120
141
|
this.borderColor = theme.borderColor;
|
|
121
142
|
const paddingX = options.paddingX ?? 0;
|
|
122
143
|
this.paddingX = Number.isFinite(paddingX) ? Math.max(0, Math.floor(paddingX)) : 0;
|
|
123
|
-
const maxVisible = options.autocompleteMaxVisible ?? 5;
|
|
124
|
-
this.autocompleteMaxVisible = Number.isFinite(maxVisible) ? Math.max(3, Math.min(20, Math.floor(maxVisible))) : 5;
|
|
125
144
|
}
|
|
126
145
|
getPaddingX() {
|
|
127
146
|
return this.paddingX;
|
|
@@ -133,16 +152,6 @@ export class Editor extends ComponentBase {
|
|
|
133
152
|
this.tui.requestRender();
|
|
134
153
|
}
|
|
135
154
|
}
|
|
136
|
-
getAutocompleteMaxVisible() {
|
|
137
|
-
return this.autocompleteMaxVisible;
|
|
138
|
-
}
|
|
139
|
-
setAutocompleteMaxVisible(maxVisible) {
|
|
140
|
-
const newMaxVisible = Number.isFinite(maxVisible) ? Math.max(3, Math.min(20, Math.floor(maxVisible))) : 5;
|
|
141
|
-
if (this.autocompleteMaxVisible !== newMaxVisible) {
|
|
142
|
-
this.autocompleteMaxVisible = newMaxVisible;
|
|
143
|
-
this.tui.requestRender();
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
155
|
setAutocompleteProvider(provider) {
|
|
147
156
|
this.autocompleteProvider = provider;
|
|
148
157
|
this.invalidate();
|
|
@@ -493,7 +502,7 @@ export class Editor extends ComponentBase {
|
|
|
493
502
|
this.pasteCounter = 0;
|
|
494
503
|
this.historyIndex = -1;
|
|
495
504
|
this.scrollOffset = 0;
|
|
496
|
-
this.undoStack.
|
|
505
|
+
this.undoStack.length = 0;
|
|
497
506
|
this.lastAction = null;
|
|
498
507
|
if (this.onChange)
|
|
499
508
|
this.onChange("");
|
|
@@ -890,93 +899,14 @@ export class Editor extends ComponentBase {
|
|
|
890
899
|
}
|
|
891
900
|
}
|
|
892
901
|
}
|
|
893
|
-
/**
|
|
894
|
-
* Set cursor column and clear sticky column preference.
|
|
895
|
-
* Call this for any direct column positioning or horizontal movement.
|
|
896
|
-
*/
|
|
897
|
-
setCursorCol(col) {
|
|
898
|
-
this.state.cursorCol = col;
|
|
899
|
-
this.preferredVisualCol = null;
|
|
900
|
-
}
|
|
901
|
-
/**
|
|
902
|
-
* Move cursor to a target visual line, applying sticky column logic.
|
|
903
|
-
* Preserves the cursor column when moving between wrapped lines of different widths.
|
|
904
|
-
*/
|
|
905
|
-
moveToVisualLine(visualLines, currentVisualLine, targetVisualLine) {
|
|
906
|
-
const currentVL = visualLines[currentVisualLine];
|
|
907
|
-
const targetVL = visualLines[targetVisualLine];
|
|
908
|
-
if (currentVL && targetVL) {
|
|
909
|
-
const currentVisualCol = this.state.cursorCol - currentVL.startCol;
|
|
910
|
-
// For non-last segments, clamp to length-1 to stay within the segment
|
|
911
|
-
const isLastSourceSegment = currentVisualLine === visualLines.length - 1 ||
|
|
912
|
-
visualLines[currentVisualLine + 1]?.logicalLine !== currentVL.logicalLine;
|
|
913
|
-
const sourceMaxVisualCol = isLastSourceSegment ? currentVL.length : Math.max(0, currentVL.length - 1);
|
|
914
|
-
const isLastTargetSegment = targetVisualLine === visualLines.length - 1 ||
|
|
915
|
-
visualLines[targetVisualLine + 1]?.logicalLine !== targetVL.logicalLine;
|
|
916
|
-
const targetMaxVisualCol = isLastTargetSegment ? targetVL.length : Math.max(0, targetVL.length - 1);
|
|
917
|
-
const moveToVisualCol = this.computeVerticalMoveColumn(currentVisualCol, sourceMaxVisualCol, targetMaxVisualCol);
|
|
918
|
-
// Set cursor position
|
|
919
|
-
this.state.cursorLine = targetVL.logicalLine;
|
|
920
|
-
const targetCol = targetVL.startCol + moveToVisualCol;
|
|
921
|
-
const logicalLine = this.state.lines[targetVL.logicalLine] || "";
|
|
922
|
-
this.state.cursorCol = Math.min(targetCol, logicalLine.length);
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
/**
|
|
926
|
-
* Compute the target visual column for vertical cursor movement.
|
|
927
|
-
* Implements sticky column logic: maintains the cursor column when moving between
|
|
928
|
-
* wrapped lines of different lengths.
|
|
929
|
-
*
|
|
930
|
-
* Decision table:
|
|
931
|
-
* | P | S | T | U | Scenario | Set Preferred | Move To |
|
|
932
|
-
* |---|---|---|---| ---------------------------------------------------- |---------------|-------------|
|
|
933
|
-
* | 0 | * | 0 | - | Start nav, target fits | null | current |
|
|
934
|
-
* | 0 | * | 1 | - | Start nav, target shorter | current | target end |
|
|
935
|
-
* | 1 | 0 | 0 | 0 | Clamped, target fits preferred | null | preferred |
|
|
936
|
-
* | 1 | 0 | 0 | 1 | Clamped, target longer but still can't fit preferred | keep | target end |
|
|
937
|
-
* | 1 | 0 | 1 | - | Clamped, target even shorter | keep | target end |
|
|
938
|
-
* | 1 | 1 | 0 | - | Rewrapped, target fits current | null | current |
|
|
939
|
-
* | 1 | 1 | 1 | - | Rewrapped, target shorter than current | current | target end |
|
|
940
|
-
*
|
|
941
|
-
* Where:
|
|
942
|
-
* - P = preferred col is set
|
|
943
|
-
* - S = cursor in middle of source line (not clamped to end)
|
|
944
|
-
* - T = target line shorter than current visual col
|
|
945
|
-
* - U = target line shorter than preferred col
|
|
946
|
-
*/
|
|
947
|
-
computeVerticalMoveColumn(currentVisualCol, sourceMaxVisualCol, targetMaxVisualCol) {
|
|
948
|
-
const hasPreferred = this.preferredVisualCol !== null; // P
|
|
949
|
-
const cursorInMiddle = currentVisualCol < sourceMaxVisualCol; // S
|
|
950
|
-
const targetTooShort = targetMaxVisualCol < currentVisualCol; // T
|
|
951
|
-
if (!hasPreferred || cursorInMiddle) {
|
|
952
|
-
if (targetTooShort) {
|
|
953
|
-
// Cases 2 and 7: Start of navigation with target shorter than current
|
|
954
|
-
// Save current column as preferred for later restoration
|
|
955
|
-
this.preferredVisualCol = currentVisualCol;
|
|
956
|
-
return targetMaxVisualCol;
|
|
957
|
-
}
|
|
958
|
-
// Cases 1 and 6: Target fits current column
|
|
959
|
-
this.preferredVisualCol = null;
|
|
960
|
-
return currentVisualCol;
|
|
961
|
-
}
|
|
962
|
-
const targetCantFitPreferred = targetMaxVisualCol < this.preferredVisualCol; // U
|
|
963
|
-
if (targetTooShort || targetCantFitPreferred) {
|
|
964
|
-
// Cases 4 and 5: Target can't fit preferred, clamp to target end
|
|
965
|
-
return targetMaxVisualCol;
|
|
966
|
-
}
|
|
967
|
-
// Case 3: Target can fit preferred, restore it and clear preference
|
|
968
|
-
const result = this.preferredVisualCol;
|
|
969
|
-
this.preferredVisualCol = null;
|
|
970
|
-
return result;
|
|
971
|
-
}
|
|
972
902
|
moveToLineStart() {
|
|
973
903
|
this.lastAction = null;
|
|
974
|
-
this.
|
|
904
|
+
this.state.cursorCol = 0;
|
|
975
905
|
}
|
|
976
906
|
moveToLineEnd() {
|
|
977
907
|
this.lastAction = null;
|
|
978
908
|
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
979
|
-
this.
|
|
909
|
+
this.state.cursorCol = currentLine.length;
|
|
980
910
|
}
|
|
981
911
|
deleteToStartOfLine() {
|
|
982
912
|
this.historyIndex = -1; // Exit history browsing mode
|
|
@@ -1208,10 +1138,20 @@ export class Editor extends ComponentBase {
|
|
|
1208
1138
|
// Build visual line map for navigation
|
|
1209
1139
|
const visualLines = this.buildVisualLineMap(width);
|
|
1210
1140
|
const currentVisualLine = this.findCurrentVisualLine(visualLines);
|
|
1211
|
-
//
|
|
1141
|
+
// Calculate column position within current visual line
|
|
1142
|
+
const currentVL = visualLines[currentVisualLine];
|
|
1143
|
+
const visualCol = currentVL ? this.state.cursorCol - currentVL.startCol : 0;
|
|
1144
|
+
// Move to target visual line
|
|
1212
1145
|
const targetVisualLine = currentVisualLine + deltaLine;
|
|
1213
1146
|
if (targetVisualLine >= 0 && targetVisualLine < visualLines.length) {
|
|
1214
|
-
|
|
1147
|
+
const targetVL = visualLines[targetVisualLine];
|
|
1148
|
+
if (targetVL) {
|
|
1149
|
+
this.state.cursorLine = targetVL.logicalLine;
|
|
1150
|
+
// Try to maintain visual column position, clamped to line length
|
|
1151
|
+
const targetCol = targetVL.startCol + Math.min(visualCol, targetVL.length);
|
|
1152
|
+
const logicalLine = this.state.lines[targetVL.logicalLine] || "";
|
|
1153
|
+
this.state.cursorCol = Math.min(targetCol, logicalLine.length);
|
|
1154
|
+
}
|
|
1215
1155
|
}
|
|
1216
1156
|
}
|
|
1217
1157
|
if (deltaCol !== 0) {
|
|
@@ -1222,12 +1162,12 @@ export class Editor extends ComponentBase {
|
|
|
1222
1162
|
const afterCursor = currentLine.slice(this.state.cursorCol);
|
|
1223
1163
|
const graphemes = [...segmenter.segment(afterCursor)];
|
|
1224
1164
|
const firstGrapheme = graphemes[0];
|
|
1225
|
-
this.
|
|
1165
|
+
this.state.cursorCol += firstGrapheme ? firstGrapheme.segment.length : 1;
|
|
1226
1166
|
}
|
|
1227
1167
|
else if (this.state.cursorLine < this.state.lines.length - 1) {
|
|
1228
1168
|
// Wrap to start of next logical line
|
|
1229
1169
|
this.state.cursorLine++;
|
|
1230
|
-
this.
|
|
1170
|
+
this.state.cursorCol = 0;
|
|
1231
1171
|
}
|
|
1232
1172
|
}
|
|
1233
1173
|
else {
|
|
@@ -1236,13 +1176,13 @@ export class Editor extends ComponentBase {
|
|
|
1236
1176
|
const beforeCursor = currentLine.slice(0, this.state.cursorCol);
|
|
1237
1177
|
const graphemes = [...segmenter.segment(beforeCursor)];
|
|
1238
1178
|
const lastGrapheme = graphemes[graphemes.length - 1];
|
|
1239
|
-
this.
|
|
1179
|
+
this.state.cursorCol -= lastGrapheme ? lastGrapheme.segment.length : 1;
|
|
1240
1180
|
}
|
|
1241
1181
|
else if (this.state.cursorLine > 0) {
|
|
1242
1182
|
// Wrap to end of previous logical line
|
|
1243
1183
|
this.state.cursorLine--;
|
|
1244
1184
|
const prevLine = this.state.lines[this.state.cursorLine] || "";
|
|
1245
|
-
this.
|
|
1185
|
+
this.state.cursorCol = prevLine.length;
|
|
1246
1186
|
}
|
|
1247
1187
|
}
|
|
1248
1188
|
}
|
|
@@ -1261,8 +1201,17 @@ export class Editor extends ComponentBase {
|
|
|
1261
1201
|
const currentVisualLine = this.findCurrentVisualLine(visualLines);
|
|
1262
1202
|
// Calculate target visual line
|
|
1263
1203
|
const targetVisualLine = Math.max(0, Math.min(visualLines.length - 1, currentVisualLine + direction * pageSize));
|
|
1264
|
-
// Move cursor to target visual line
|
|
1265
|
-
|
|
1204
|
+
// Move cursor to target visual line
|
|
1205
|
+
const targetVL = visualLines[targetVisualLine];
|
|
1206
|
+
if (targetVL) {
|
|
1207
|
+
// Preserve column position within the line
|
|
1208
|
+
const currentVL = visualLines[currentVisualLine];
|
|
1209
|
+
const visualCol = currentVL ? this.state.cursorCol - currentVL.startCol : 0;
|
|
1210
|
+
this.state.cursorLine = targetVL.logicalLine;
|
|
1211
|
+
const targetCol = targetVL.startCol + Math.min(visualCol, targetVL.length);
|
|
1212
|
+
const logicalLine = this.state.lines[targetVL.logicalLine] || "";
|
|
1213
|
+
this.state.cursorCol = Math.min(targetCol, logicalLine.length);
|
|
1214
|
+
}
|
|
1266
1215
|
}
|
|
1267
1216
|
moveWordBackwards() {
|
|
1268
1217
|
this.lastAction = null;
|
|
@@ -1309,7 +1258,7 @@ export class Editor extends ComponentBase {
|
|
|
1309
1258
|
if (this.killRing.length === 0)
|
|
1310
1259
|
return;
|
|
1311
1260
|
this.pushUndoSnapshot();
|
|
1312
|
-
const text = this.killRing.
|
|
1261
|
+
const text = this.killRing[this.killRing.length - 1] || "";
|
|
1313
1262
|
this.insertYankedText(text);
|
|
1314
1263
|
this.lastAction = "yank";
|
|
1315
1264
|
}
|
|
@@ -1325,9 +1274,10 @@ export class Editor extends ComponentBase {
|
|
|
1325
1274
|
// Delete the previously yanked text (still at end of ring before rotation)
|
|
1326
1275
|
this.deleteYankedText();
|
|
1327
1276
|
// Rotate the ring: move end to front
|
|
1328
|
-
this.killRing.
|
|
1277
|
+
const lastEntry = this.killRing.pop();
|
|
1278
|
+
this.killRing.unshift(lastEntry);
|
|
1329
1279
|
// Insert the new most recent entry (now at end after rotation)
|
|
1330
|
-
const text = this.killRing.
|
|
1280
|
+
const text = this.killRing[this.killRing.length - 1];
|
|
1331
1281
|
this.insertYankedText(text);
|
|
1332
1282
|
this.lastAction = "yank";
|
|
1333
1283
|
}
|
|
@@ -1369,10 +1319,10 @@ export class Editor extends ComponentBase {
|
|
|
1369
1319
|
}
|
|
1370
1320
|
/**
|
|
1371
1321
|
* Delete the previously yanked text (used by yank-pop).
|
|
1372
|
-
* The yanked text is derived from killRing
|
|
1322
|
+
* The yanked text is derived from killRing[end] since it hasn't been rotated yet.
|
|
1373
1323
|
*/
|
|
1374
1324
|
deleteYankedText() {
|
|
1375
|
-
const yankedText = this.killRing.
|
|
1325
|
+
const yankedText = this.killRing[this.killRing.length - 1] || "";
|
|
1376
1326
|
if (!yankedText)
|
|
1377
1327
|
return;
|
|
1378
1328
|
const yankLines = yankedText.split("\n");
|
|
@@ -1410,17 +1360,38 @@ export class Editor extends ComponentBase {
|
|
|
1410
1360
|
* @param prepend - If accumulating, prepend (true) or append (false) to existing entry
|
|
1411
1361
|
*/
|
|
1412
1362
|
addToKillRing(text, prepend) {
|
|
1413
|
-
|
|
1363
|
+
if (!text)
|
|
1364
|
+
return;
|
|
1365
|
+
if (this.lastAction === "kill" && this.killRing.length > 0) {
|
|
1366
|
+
// Accumulate with the most recent entry (at end of array)
|
|
1367
|
+
const lastEntry = this.killRing.pop();
|
|
1368
|
+
if (prepend) {
|
|
1369
|
+
this.killRing.push(text + lastEntry);
|
|
1370
|
+
}
|
|
1371
|
+
else {
|
|
1372
|
+
this.killRing.push(lastEntry + text);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
else {
|
|
1376
|
+
// Add new entry to end of ring
|
|
1377
|
+
this.killRing.push(text);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
captureUndoSnapshot() {
|
|
1381
|
+
return structuredClone(this.state);
|
|
1382
|
+
}
|
|
1383
|
+
restoreUndoSnapshot(snapshot) {
|
|
1384
|
+
Object.assign(this.state, structuredClone(snapshot));
|
|
1414
1385
|
}
|
|
1415
1386
|
pushUndoSnapshot() {
|
|
1416
|
-
this.undoStack.push(this.
|
|
1387
|
+
this.undoStack.push(this.captureUndoSnapshot());
|
|
1417
1388
|
}
|
|
1418
1389
|
undo() {
|
|
1419
1390
|
this.historyIndex = -1; // Exit history browsing mode
|
|
1420
|
-
|
|
1421
|
-
if (!snapshot)
|
|
1391
|
+
if (this.undoStack.length === 0)
|
|
1422
1392
|
return;
|
|
1423
|
-
|
|
1393
|
+
const snapshot = this.undoStack.pop();
|
|
1394
|
+
this.restoreUndoSnapshot(snapshot);
|
|
1424
1395
|
this.lastAction = null;
|
|
1425
1396
|
if (this.onChange) {
|
|
1426
1397
|
this.onChange(this.getText());
|
|
@@ -1501,7 +1472,7 @@ export class Editor extends ComponentBase {
|
|
|
1501
1472
|
const suggestions = this.autocompleteProvider.getSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol);
|
|
1502
1473
|
if (suggestions && suggestions.items.length > 0) {
|
|
1503
1474
|
this.autocompletePrefix = suggestions.prefix;
|
|
1504
|
-
this.autocompleteList = new SelectList(suggestions.items,
|
|
1475
|
+
this.autocompleteList = new SelectList(suggestions.items, 5, this.theme.selectList);
|
|
1505
1476
|
this.isAutocompleting = true;
|
|
1506
1477
|
}
|
|
1507
1478
|
else {
|
|
@@ -1541,7 +1512,7 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
|
|
|
1541
1512
|
const suggestions = provider.getForceFileSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol);
|
|
1542
1513
|
if (suggestions && suggestions.items.length > 0) {
|
|
1543
1514
|
this.autocompletePrefix = suggestions.prefix;
|
|
1544
|
-
this.autocompleteList = new SelectList(suggestions.items,
|
|
1515
|
+
this.autocompleteList = new SelectList(suggestions.items, 5, this.theme.selectList);
|
|
1545
1516
|
this.isAutocompleting = true;
|
|
1546
1517
|
}
|
|
1547
1518
|
else {
|
|
@@ -1563,7 +1534,7 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
|
|
|
1563
1534
|
if (suggestions && suggestions.items.length > 0) {
|
|
1564
1535
|
this.autocompletePrefix = suggestions.prefix;
|
|
1565
1536
|
// Always create new SelectList to ensure update
|
|
1566
|
-
this.autocompleteList = new SelectList(suggestions.items,
|
|
1537
|
+
this.autocompleteList = new SelectList(suggestions.items, 5, this.theme.selectList);
|
|
1567
1538
|
}
|
|
1568
1539
|
else {
|
|
1569
1540
|
this.cancelAutocomplete();
|