@timurproko/a1 0.1.8-dev.269 → 0.1.8-dev.271
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/dist/integrations/pi/components/owned-editor-ux.js +61 -8
- package/dist/integrations/pi/components/path-word-ranges.d.ts +2 -0
- package/dist/integrations/pi/components/path-word-ranges.js +37 -0
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CURSOR_MARKER, decodeKittyPrintable, visibleWidth, } from "#pi-tui";
|
|
2
|
+
import { promptPathWordRanges } from "./path-word-ranges.js";
|
|
2
3
|
export class OwnedEditorUxInterception {
|
|
3
4
|
interceptors;
|
|
4
5
|
fallback;
|
|
@@ -59,12 +60,13 @@ class PromptSelectionInterceptor {
|
|
|
59
60
|
#lastClick;
|
|
60
61
|
#redoStack = [];
|
|
61
62
|
#selectionRevision = 0;
|
|
63
|
+
#wordDirection;
|
|
62
64
|
#geometry;
|
|
63
65
|
constructor(editor, keybindings, options) {
|
|
64
66
|
this.editor = editor;
|
|
65
67
|
this.keybindings = keybindings;
|
|
66
68
|
this.options = options;
|
|
67
|
-
installAtomicSegmentation(editor, options.atomicRanges);
|
|
69
|
+
installAtomicSegmentation(editor, options.atomicRanges, () => this.#wordDirection);
|
|
68
70
|
}
|
|
69
71
|
handleInput(data, next) {
|
|
70
72
|
if (this.keybindings.matches(data, "owned.editor.selectAll")) {
|
|
@@ -167,24 +169,30 @@ class PromptSelectionInterceptor {
|
|
|
167
169
|
if (this.keybindings.matches(data, "tui.editor.cursorWordLeft")) {
|
|
168
170
|
const before = this.#cursor();
|
|
169
171
|
const startedWithAtomicFocus = this.#atomicFocus() !== undefined;
|
|
170
|
-
next
|
|
172
|
+
this.#delegateWord(-1, next);
|
|
171
173
|
let after = this.#cursor();
|
|
172
174
|
const landedAtomic = this.#atomicRangeAt(after);
|
|
173
175
|
if (!startedWithAtomicFocus && landedAtomic?.start === after.col && after.col > 0) {
|
|
174
176
|
const line = editorState(this.editor).lines[after.line] ?? "";
|
|
175
177
|
const previous = [...GRAPHEMES.segment(line.slice(0, after.col))].at(-1);
|
|
176
178
|
if (previous !== undefined && !/^\s+$/u.test(previous.segment)) {
|
|
177
|
-
next
|
|
179
|
+
this.#delegateWord(-1, next);
|
|
178
180
|
after = this.#cursor();
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
|
-
|
|
183
|
+
const line = editorState(this.editor).lines[after.line] ?? "";
|
|
184
|
+
const landedPath = promptPathWordRanges(line).some(range => range.start === after.col);
|
|
185
|
+
if (!samePosition(before, after) && !landedPath)
|
|
182
186
|
this.#moveOntoPreviousSeparator();
|
|
183
187
|
this.#requestRender();
|
|
184
188
|
return;
|
|
185
189
|
}
|
|
186
190
|
const beforeText = this.editor.getText();
|
|
187
|
-
|
|
191
|
+
const wordDirection = this.#wordDirectionFor(data);
|
|
192
|
+
if (wordDirection === undefined)
|
|
193
|
+
next();
|
|
194
|
+
else
|
|
195
|
+
this.#delegateWord(wordDirection, next);
|
|
188
196
|
if (this.editor.getText() !== beforeText)
|
|
189
197
|
this.#redoStack = [];
|
|
190
198
|
}
|
|
@@ -584,11 +592,28 @@ class PromptSelectionInterceptor {
|
|
|
584
592
|
#snapshot() {
|
|
585
593
|
return { text: this.editor.getText(), cursor: this.#cursor() };
|
|
586
594
|
}
|
|
595
|
+
#wordDirectionFor(data) {
|
|
596
|
+
if (this.keybindings.matches(data, "tui.editor.deleteWordBackward"))
|
|
597
|
+
return -1;
|
|
598
|
+
if (this.keybindings.matches(data, "tui.editor.deleteWordForward")
|
|
599
|
+
|| this.keybindings.matches(data, "tui.editor.cursorWordRight"))
|
|
600
|
+
return 1;
|
|
601
|
+
return undefined;
|
|
602
|
+
}
|
|
603
|
+
#delegateWord(direction, next) {
|
|
604
|
+
this.#wordDirection = direction;
|
|
605
|
+
try {
|
|
606
|
+
next();
|
|
607
|
+
}
|
|
608
|
+
finally {
|
|
609
|
+
this.#wordDirection = undefined;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
587
612
|
#requestRender() {
|
|
588
613
|
this.options.requestRender();
|
|
589
614
|
}
|
|
590
615
|
}
|
|
591
|
-
function installAtomicSegmentation(editor, rangesForText) {
|
|
616
|
+
function installAtomicSegmentation(editor, rangesForText, wordDirection) {
|
|
592
617
|
if (Reflect.get(editor, ATOMIC_SEGMENTATION) === true)
|
|
593
618
|
return;
|
|
594
619
|
const originalValue = Reflect.get(editor, "segment");
|
|
@@ -597,7 +622,14 @@ function installAtomicSegmentation(editor, rangesForText) {
|
|
|
597
622
|
const original = originalValue.bind(editor);
|
|
598
623
|
Reflect.set(editor, "segment", (text, mode) => {
|
|
599
624
|
const segments = [...original(text, mode)].filter(isEditorSegment);
|
|
600
|
-
const ranges = rangesForText(text);
|
|
625
|
+
const ranges = rangesForText(text).map(range => ({ ...range, wordLike: false }));
|
|
626
|
+
if (mode === "word") {
|
|
627
|
+
for (const range of contextualPathRanges(editor, text, wordDirection())) {
|
|
628
|
+
if (!ranges.some(existing => rangesOverlap(existing, range)))
|
|
629
|
+
ranges.push({ ...range, wordLike: true });
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
ranges.sort((left, right) => left.start - right.start);
|
|
601
633
|
if (ranges.length === 0)
|
|
602
634
|
return segments;
|
|
603
635
|
const merged = [];
|
|
@@ -608,10 +640,12 @@ function installAtomicSegmentation(editor, rangesForText) {
|
|
|
608
640
|
const range = ranges[rangeIndex];
|
|
609
641
|
if (range !== undefined && segment.index >= range.start && segment.index < range.end) {
|
|
610
642
|
if (segment.index === range.start) {
|
|
643
|
+
const source = text.slice(range.start, range.end);
|
|
611
644
|
merged.push({
|
|
612
|
-
segment:
|
|
645
|
+
segment: range.wordLike ? "w".repeat(source.length) : source.replaceAll(" ", ATOMIC_SPACE_SENTINEL),
|
|
613
646
|
index: range.start,
|
|
614
647
|
input: text,
|
|
648
|
+
...(range.wordLike ? { isWordLike: true } : {}),
|
|
615
649
|
});
|
|
616
650
|
}
|
|
617
651
|
continue;
|
|
@@ -622,6 +656,25 @@ function installAtomicSegmentation(editor, rangesForText) {
|
|
|
622
656
|
});
|
|
623
657
|
Reflect.set(editor, ATOMIC_SEGMENTATION, true);
|
|
624
658
|
}
|
|
659
|
+
function contextualPathRanges(editor, text, direction) {
|
|
660
|
+
if (direction === undefined)
|
|
661
|
+
return promptPathWordRanges(text);
|
|
662
|
+
const state = editorState(editor);
|
|
663
|
+
const line = state.lines[state.cursorLine] ?? "";
|
|
664
|
+
const offset = direction < 0 ? 0 : state.cursorCol;
|
|
665
|
+
if (text !== (direction < 0 ? line.slice(0, state.cursorCol) : line.slice(state.cursorCol))) {
|
|
666
|
+
return promptPathWordRanges(text);
|
|
667
|
+
}
|
|
668
|
+
const end = offset + text.length;
|
|
669
|
+
return promptPathWordRanges(line).flatMap(range => {
|
|
670
|
+
const start = Math.max(range.start, offset);
|
|
671
|
+
const finish = Math.min(range.end, end);
|
|
672
|
+
return finish <= start ? [] : [{ start: start - offset, end: finish - offset }];
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
function rangesOverlap(left, right) {
|
|
676
|
+
return left.start < right.end && right.start < left.end;
|
|
677
|
+
}
|
|
625
678
|
function isEditorSegment(value) {
|
|
626
679
|
if (typeof value !== "object" || value === null)
|
|
627
680
|
return false;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const WHITESPACE = /\s/u;
|
|
2
|
+
const DRIVE_ROOT = /^[A-Za-z]:[\\/]/u;
|
|
3
|
+
const UNC_ROOT = /^(?:\\\\|\/\/)[^\\/\s]+[\\/][^\\/\s]+/u;
|
|
4
|
+
const POSIX_ROOT = /^\//u;
|
|
5
|
+
const EXPLICIT_RELATIVE_ROOT = /^(?:\.{1,2}|~)[\\/]/u;
|
|
6
|
+
export function promptPathWordRanges(line) {
|
|
7
|
+
const ranges = [];
|
|
8
|
+
let index = 0;
|
|
9
|
+
while (index < line.length) {
|
|
10
|
+
while (index < line.length && WHITESPACE.test(line[index] ?? ""))
|
|
11
|
+
index += 1;
|
|
12
|
+
if (index >= line.length)
|
|
13
|
+
break;
|
|
14
|
+
const start = index;
|
|
15
|
+
const quote = line[index] === '"' || line[index] === "'" ? line[index] : undefined;
|
|
16
|
+
if (quote !== undefined) {
|
|
17
|
+
const closing = line.indexOf(quote, index + 1);
|
|
18
|
+
if (closing >= 0 && (closing + 1 === line.length || WHITESPACE.test(line[closing + 1] ?? ""))) {
|
|
19
|
+
if (isExplicitPath(line.slice(index + 1, closing)))
|
|
20
|
+
ranges.push({ start, end: closing + 1 });
|
|
21
|
+
index = closing + 1;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
while (index < line.length && !WHITESPACE.test(line[index] ?? ""))
|
|
26
|
+
index += 1;
|
|
27
|
+
if (isExplicitPath(line.slice(start, index)))
|
|
28
|
+
ranges.push({ start, end: index });
|
|
29
|
+
}
|
|
30
|
+
return ranges;
|
|
31
|
+
}
|
|
32
|
+
function isExplicitPath(value) {
|
|
33
|
+
return DRIVE_ROOT.test(value)
|
|
34
|
+
|| UNC_ROOT.test(value)
|
|
35
|
+
|| POSIX_ROOT.test(value)
|
|
36
|
+
|| EXPLICIT_RELATIVE_ROOT.test(value);
|
|
37
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "darwin",
|
|
6
6
|
"architecture": "arm64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-09-
|
|
8
|
+
"builtAt": "2026-09-06T15:05:45.656Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "dc03605e5780e2aeebb4ecafd62868dc673e22ddd38b024a369aff704ff136dc",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "linux",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-09-
|
|
8
|
+
"builtAt": "2026-09-06T15:05:42.977Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "ee8a00eaaf79c707459bbbfb52518e9739314967049fbe5fa625f36ce33db9ee",
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
"platform": "win32",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-09-
|
|
8
|
+
"builtAt": "2026-09-06T15:06:12.448Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian.exe",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "7cca17597d89ae0dad9cd14114acc0795f688d54f6580b897463fba11af479ca",
|
|
12
12
|
"size": 177664
|
|
13
13
|
},
|
|
14
14
|
"provenance": {
|
|
Binary file
|