@vui-rs/core 0.1.0
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 +29 -0
- package/dist/char-width.d.ts +7 -0
- package/dist/char-width.js +20 -0
- package/dist/color-names.js +46 -0
- package/dist/color.d.ts +5 -0
- package/dist/color.js +57 -0
- package/dist/image-decode.d.ts +21 -0
- package/dist/image-decode.js +42 -0
- package/dist/index.d.ts +402 -0
- package/dist/index.js +27 -0
- package/dist/keys.d.ts +76 -0
- package/dist/keys.js +373 -0
- package/dist/named-colors.d.ts +7 -0
- package/dist/named-colors.js +20 -0
- package/dist/native/darwin-arm64/libvui_core.dylib +0 -0
- package/dist/native/darwin-x64/libvui_core.dylib +0 -0
- package/dist/native/ffi-symbols.d.ts +453 -0
- package/dist/native/ffi-symbols.js +680 -0
- package/dist/native/linux-arm64/libvui_core.so +0 -0
- package/dist/native/linux-x64/libvui_core.so +0 -0
- package/dist/native/load-native-lib.d.ts +384 -0
- package/dist/native/load-native-lib.js +63 -0
- package/dist/native/win32-x64/vui_core.dll +0 -0
- package/dist/node.d.ts +61 -0
- package/dist/node.js +157 -0
- package/dist/offscreen-buffer.d.ts +28 -0
- package/dist/offscreen-buffer.js +73 -0
- package/dist/renderer.d.ts +106 -0
- package/dist/renderer.js +186 -0
- package/dist/style.d.ts +48 -0
- package/dist/style.js +134 -0
- package/dist/terminal-session.d.ts +43 -0
- package/dist/terminal-session.js +82 -0
- package/dist/text/edit-buffer.d.ts +31 -0
- package/dist/text/edit-buffer.js +96 -0
- package/dist/text/editor-view.d.ts +22 -0
- package/dist/text/editor-view.js +48 -0
- package/dist/text/index.d.ts +5 -0
- package/dist/text/index.js +5 -0
- package/dist/text/text-buffer-view.d.ts +22 -0
- package/dist/text/text-buffer-view.js +49 -0
- package/dist/text/text-buffer.d.ts +16 -0
- package/dist/text/text-buffer.js +43 -0
- package/package.json +46 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//#region src/terminal-session.ts
|
|
2
|
+
const decoder = new TextDecoder();
|
|
3
|
+
const ENTER_ALT = "\x1B[?1049h";
|
|
4
|
+
const LEAVE_ALT = "\x1B[?1049l";
|
|
5
|
+
const KITTY_KBD_ON = "\x1B[>1u";
|
|
6
|
+
const KITTY_KBD_OFF = "\x1B[<u";
|
|
7
|
+
function toText(chunk) {
|
|
8
|
+
if (typeof chunk === "string") return chunk;
|
|
9
|
+
if (chunk instanceof Uint8Array) return decoder.decode(chunk);
|
|
10
|
+
return String(chunk);
|
|
11
|
+
}
|
|
12
|
+
function createTerminalSession(options = {}) {
|
|
13
|
+
const input = options.input ?? process.stdin;
|
|
14
|
+
const output = options.output ?? process.stdout;
|
|
15
|
+
const altScreen = options.altScreen ?? true;
|
|
16
|
+
const installSignals = options.installSignalHandlers ?? true;
|
|
17
|
+
const kittyKeyboard = options.kittyKeyboard ?? true;
|
|
18
|
+
let started = false;
|
|
19
|
+
let restored = false;
|
|
20
|
+
let dataCb = null;
|
|
21
|
+
let resizeCb = null;
|
|
22
|
+
const onDataRaw = (chunk) => dataCb?.(toText(chunk));
|
|
23
|
+
const onResizeRaw = () => resizeCb?.(output.columns ?? 0, output.rows ?? 0);
|
|
24
|
+
const onSignal = () => {
|
|
25
|
+
stop();
|
|
26
|
+
process.exit(0);
|
|
27
|
+
};
|
|
28
|
+
const onUncaught = (err) => {
|
|
29
|
+
stop();
|
|
30
|
+
process.nextTick(() => {
|
|
31
|
+
throw err;
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
function start() {
|
|
35
|
+
if (started) return;
|
|
36
|
+
started = true;
|
|
37
|
+
input.setRawMode?.(true);
|
|
38
|
+
output.write((altScreen ? ENTER_ALT : "") + "\x1B[?25l\x1B[?2004h\x1B[?1006h\x1B[?1000h\x1B[?1002h" + (kittyKeyboard ? KITTY_KBD_ON : ""));
|
|
39
|
+
input.resume?.();
|
|
40
|
+
input.on("data", onDataRaw);
|
|
41
|
+
output.on("resize", onResizeRaw);
|
|
42
|
+
if (installSignals) {
|
|
43
|
+
process.once("exit", stop);
|
|
44
|
+
process.once("SIGINT", onSignal);
|
|
45
|
+
process.once("SIGTERM", onSignal);
|
|
46
|
+
process.once("uncaughtException", onUncaught);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function stop() {
|
|
50
|
+
if (restored) return;
|
|
51
|
+
restored = true;
|
|
52
|
+
input.off("data", onDataRaw);
|
|
53
|
+
output.off("resize", onResizeRaw);
|
|
54
|
+
input.setRawMode?.(false);
|
|
55
|
+
input.pause?.();
|
|
56
|
+
output.write((kittyKeyboard ? KITTY_KBD_OFF : "") + "\x1B[?1002l\x1B[?1000l\x1B[?1006l\x1B[?2004l\x1B[?25h" + (altScreen ? LEAVE_ALT : ""));
|
|
57
|
+
if (installSignals) {
|
|
58
|
+
process.off("exit", stop);
|
|
59
|
+
process.off("SIGINT", onSignal);
|
|
60
|
+
process.off("SIGTERM", onSignal);
|
|
61
|
+
process.off("uncaughtException", onUncaught);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
start,
|
|
66
|
+
stop,
|
|
67
|
+
onData: (cb) => {
|
|
68
|
+
dataCb = cb;
|
|
69
|
+
},
|
|
70
|
+
onResize: (cb) => {
|
|
71
|
+
resizeCb = cb;
|
|
72
|
+
},
|
|
73
|
+
get size() {
|
|
74
|
+
return {
|
|
75
|
+
cols: output.columns ?? 0,
|
|
76
|
+
rows: output.rows ?? 0
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
export { createTerminalSession };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EditMotion, EditMotionCode } from "../native/ffi-symbols.js";
|
|
2
|
+
import { Pointer } from "bun:ffi";
|
|
3
|
+
|
|
4
|
+
//#region src/text/edit-buffer.d.ts
|
|
5
|
+
declare class EditBuffer {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(value?: string);
|
|
8
|
+
get nativePtr(): Pointer;
|
|
9
|
+
getValue(): string;
|
|
10
|
+
setValue(value: string): void;
|
|
11
|
+
insert(text: string): void;
|
|
12
|
+
newline(): void;
|
|
13
|
+
backspace(): void;
|
|
14
|
+
delete(): void;
|
|
15
|
+
move(motion: EditMotionCode, selecting?: boolean): void;
|
|
16
|
+
selectAll(): void;
|
|
17
|
+
hasSelection(): boolean;
|
|
18
|
+
selectedText(): string;
|
|
19
|
+
deleteSelection(): boolean;
|
|
20
|
+
undo(): boolean;
|
|
21
|
+
redo(): boolean;
|
|
22
|
+
canUndo(): boolean;
|
|
23
|
+
canRedo(): boolean;
|
|
24
|
+
cursor(): {
|
|
25
|
+
row: number;
|
|
26
|
+
col: number;
|
|
27
|
+
};
|
|
28
|
+
free(): void;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { EditBuffer };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Status } from "../native/ffi-symbols.js";
|
|
2
|
+
import { loadNativeLib } from "../native/load-native-lib.js";
|
|
3
|
+
//#region src/text/edit-buffer.ts
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
const decoder = new TextDecoder();
|
|
6
|
+
function check(status, op) {
|
|
7
|
+
if (status !== Status.OK) throw new Error(`vui-core ${op} failed with status ${status}`);
|
|
8
|
+
}
|
|
9
|
+
var EditBuffer = class {
|
|
10
|
+
#lib = loadNativeLib();
|
|
11
|
+
#ptr;
|
|
12
|
+
#cursor = new Uint32Array(2);
|
|
13
|
+
#changed = new Uint32Array(1);
|
|
14
|
+
constructor(value = "") {
|
|
15
|
+
const ptr = this.#lib.symbols.vui_editbuf_new();
|
|
16
|
+
if (ptr === null) throw new Error("vui-core: failed to allocate EditBuffer");
|
|
17
|
+
this.#ptr = ptr;
|
|
18
|
+
if (value) this.setValue(value);
|
|
19
|
+
}
|
|
20
|
+
get nativePtr() {
|
|
21
|
+
return this.#ptr;
|
|
22
|
+
}
|
|
23
|
+
getValue() {
|
|
24
|
+
const len = Number(this.#lib.symbols.vui_editbuf_value_len(this.#ptr));
|
|
25
|
+
if (len === 0) return "";
|
|
26
|
+
const out = new Uint8Array(len);
|
|
27
|
+
const copied = Number(this.#lib.symbols.vui_editbuf_copy_value(this.#ptr, out, out.byteLength));
|
|
28
|
+
return decoder.decode(out.subarray(0, copied));
|
|
29
|
+
}
|
|
30
|
+
setValue(value) {
|
|
31
|
+
const bytes = encoder.encode(value);
|
|
32
|
+
check(this.#lib.symbols.vui_editbuf_set_value(this.#ptr, bytes, bytes.byteLength), "editbuf_set_value");
|
|
33
|
+
}
|
|
34
|
+
insert(text) {
|
|
35
|
+
const bytes = encoder.encode(text);
|
|
36
|
+
check(this.#lib.symbols.vui_editbuf_insert(this.#ptr, bytes, bytes.byteLength), "editbuf_insert");
|
|
37
|
+
}
|
|
38
|
+
newline() {
|
|
39
|
+
check(this.#lib.symbols.vui_editbuf_newline(this.#ptr), "editbuf_newline");
|
|
40
|
+
}
|
|
41
|
+
backspace() {
|
|
42
|
+
check(this.#lib.symbols.vui_editbuf_backspace(this.#ptr), "editbuf_backspace");
|
|
43
|
+
}
|
|
44
|
+
delete() {
|
|
45
|
+
check(this.#lib.symbols.vui_editbuf_delete(this.#ptr), "editbuf_delete");
|
|
46
|
+
}
|
|
47
|
+
move(motion, selecting = false) {
|
|
48
|
+
check(this.#lib.symbols.vui_editbuf_move(this.#ptr, motion, selecting ? 1 : 0), "editbuf_move");
|
|
49
|
+
}
|
|
50
|
+
selectAll() {
|
|
51
|
+
check(this.#lib.symbols.vui_editbuf_select_all(this.#ptr), "editbuf_select_all");
|
|
52
|
+
}
|
|
53
|
+
hasSelection() {
|
|
54
|
+
return this.#lib.symbols.vui_editbuf_has_selection(this.#ptr) !== 0;
|
|
55
|
+
}
|
|
56
|
+
selectedText() {
|
|
57
|
+
const len = Number(this.#lib.symbols.vui_editbuf_selected_len(this.#ptr));
|
|
58
|
+
if (len === 0) return "";
|
|
59
|
+
const out = new Uint8Array(len);
|
|
60
|
+
const copied = Number(this.#lib.symbols.vui_editbuf_copy_selected(this.#ptr, out, out.byteLength));
|
|
61
|
+
return decoder.decode(out.subarray(0, copied));
|
|
62
|
+
}
|
|
63
|
+
deleteSelection() {
|
|
64
|
+
check(this.#lib.symbols.vui_editbuf_delete_selection(this.#ptr, this.#changed), "editbuf_delete_selection");
|
|
65
|
+
return this.#changed[0] === 1;
|
|
66
|
+
}
|
|
67
|
+
undo() {
|
|
68
|
+
check(this.#lib.symbols.vui_editbuf_undo(this.#ptr, this.#changed), "editbuf_undo");
|
|
69
|
+
return this.#changed[0] === 1;
|
|
70
|
+
}
|
|
71
|
+
redo() {
|
|
72
|
+
check(this.#lib.symbols.vui_editbuf_redo(this.#ptr, this.#changed), "editbuf_redo");
|
|
73
|
+
return this.#changed[0] === 1;
|
|
74
|
+
}
|
|
75
|
+
canUndo() {
|
|
76
|
+
return this.#lib.symbols.vui_editbuf_can_undo(this.#ptr) !== 0;
|
|
77
|
+
}
|
|
78
|
+
canRedo() {
|
|
79
|
+
return this.#lib.symbols.vui_editbuf_can_redo(this.#ptr) !== 0;
|
|
80
|
+
}
|
|
81
|
+
cursor() {
|
|
82
|
+
check(this.#lib.symbols.vui_editbuf_cursor(this.#ptr, this.#cursor, this.#cursor.subarray(1)), "editbuf_cursor");
|
|
83
|
+
return {
|
|
84
|
+
row: this.#cursor[0],
|
|
85
|
+
col: this.#cursor[1]
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
free() {
|
|
89
|
+
if (this.#ptr !== null) {
|
|
90
|
+
this.#lib.symbols.vui_editbuf_free(this.#ptr);
|
|
91
|
+
this.#ptr = null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
//#endregion
|
|
96
|
+
export { EditBuffer };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { EditMotionCode } from "../native/ffi-symbols.js";
|
|
2
|
+
import { TextWrapMode } from "./text-buffer-view.js";
|
|
3
|
+
import { EditBuffer } from "./edit-buffer.js";
|
|
4
|
+
import { Pointer } from "bun:ffi";
|
|
5
|
+
|
|
6
|
+
//#region src/text/editor-view.d.ts
|
|
7
|
+
declare class EditorView {
|
|
8
|
+
#private;
|
|
9
|
+
constructor(edit: EditBuffer, width?: number, height?: number, mode?: TextWrapMode);
|
|
10
|
+
get nativePtr(): Pointer;
|
|
11
|
+
setWrap(mode: TextWrapMode): void;
|
|
12
|
+
setViewport(width: number, height: number): void;
|
|
13
|
+
setFocused(focused: boolean): void;
|
|
14
|
+
move(motion: EditMotionCode, selecting?: boolean): void;
|
|
15
|
+
measure(width: number, mode?: TextWrapMode): {
|
|
16
|
+
lineCount: number;
|
|
17
|
+
maxWidth: number;
|
|
18
|
+
};
|
|
19
|
+
free(): void;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { EditorView };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Status } from "../native/ffi-symbols.js";
|
|
2
|
+
import { loadNativeLib } from "../native/load-native-lib.js";
|
|
3
|
+
import { wrapCode } from "./text-buffer-view.js";
|
|
4
|
+
//#region src/text/editor-view.ts
|
|
5
|
+
function check(status, op) {
|
|
6
|
+
if (status !== Status.OK) throw new Error(`vui-core ${op} failed with status ${status}`);
|
|
7
|
+
}
|
|
8
|
+
var EditorView = class {
|
|
9
|
+
#lib = loadNativeLib();
|
|
10
|
+
#ptr;
|
|
11
|
+
#measure = new Uint32Array(2);
|
|
12
|
+
constructor(edit, width = 1, height = 1, mode = "word") {
|
|
13
|
+
const ptr = this.#lib.symbols.vui_editor_new(edit.nativePtr, Math.max(1, width), Math.max(1, height));
|
|
14
|
+
if (ptr === null) throw new Error("vui-core: failed to allocate EditorView");
|
|
15
|
+
this.#ptr = ptr;
|
|
16
|
+
this.setWrap(mode);
|
|
17
|
+
}
|
|
18
|
+
get nativePtr() {
|
|
19
|
+
return this.#ptr;
|
|
20
|
+
}
|
|
21
|
+
setWrap(mode) {
|
|
22
|
+
check(this.#lib.symbols.vui_editor_set_wrap(this.#ptr, wrapCode(mode)), "editor_set_wrap");
|
|
23
|
+
}
|
|
24
|
+
setViewport(width, height) {
|
|
25
|
+
check(this.#lib.symbols.vui_editor_set_viewport(this.#ptr, Math.max(1, Math.floor(width)), Math.max(1, Math.floor(height))), "editor_set_viewport");
|
|
26
|
+
}
|
|
27
|
+
setFocused(focused) {
|
|
28
|
+
check(this.#lib.symbols.vui_editor_set_focused(this.#ptr, focused ? 1 : 0), "editor_set_focused");
|
|
29
|
+
}
|
|
30
|
+
move(motion, selecting = false) {
|
|
31
|
+
check(this.#lib.symbols.vui_editor_move(this.#ptr, motion, selecting ? 1 : 0), "editor_move");
|
|
32
|
+
}
|
|
33
|
+
measure(width, mode = "word") {
|
|
34
|
+
check(this.#lib.symbols.vui_editor_measure(this.#ptr, Math.max(1, Math.floor(width)), wrapCode(mode), this.#measure), "editor_measure");
|
|
35
|
+
return {
|
|
36
|
+
lineCount: this.#measure[0],
|
|
37
|
+
maxWidth: this.#measure[1]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
free() {
|
|
41
|
+
if (this.#ptr !== null) {
|
|
42
|
+
this.#lib.symbols.vui_editor_free(this.#ptr);
|
|
43
|
+
this.#ptr = null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
//#endregion
|
|
48
|
+
export { EditorView };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { EditMotion, EditMotionCode } from "../native/ffi-symbols.js";
|
|
2
|
+
import { TextBuffer } from "./text-buffer.js";
|
|
3
|
+
import { TextBufferView, TextMeasure, TextWrapMode, wrapCode } from "./text-buffer-view.js";
|
|
4
|
+
import { EditBuffer } from "./edit-buffer.js";
|
|
5
|
+
import { EditorView } from "./editor-view.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { NativeTextWrapCode } from "../native/ffi-symbols.js";
|
|
2
|
+
import { TextBuffer } from "./text-buffer.js";
|
|
3
|
+
import { Pointer } from "bun:ffi";
|
|
4
|
+
|
|
5
|
+
//#region src/text/text-buffer-view.d.ts
|
|
6
|
+
type TextWrapMode = 'nowrap' | 'char' | 'word';
|
|
7
|
+
interface TextMeasure {
|
|
8
|
+
lineCount: number;
|
|
9
|
+
maxWidth: number;
|
|
10
|
+
}
|
|
11
|
+
declare function wrapCode(mode: TextWrapMode): NativeTextWrapCode;
|
|
12
|
+
declare class TextBufferView {
|
|
13
|
+
#private;
|
|
14
|
+
constructor(buffer: TextBuffer, width?: number, mode?: TextWrapMode);
|
|
15
|
+
get nativePtr(): Pointer;
|
|
16
|
+
setWidth(width: number): void;
|
|
17
|
+
setWrap(mode: TextWrapMode): void;
|
|
18
|
+
measure(width: number, mode?: TextWrapMode): TextMeasure;
|
|
19
|
+
free(): void;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { TextBufferView, TextMeasure, TextWrapMode, wrapCode };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { NativeTextWrap, Status } from "../native/ffi-symbols.js";
|
|
2
|
+
import { loadNativeLib } from "../native/load-native-lib.js";
|
|
3
|
+
//#region src/text/text-buffer-view.ts
|
|
4
|
+
function check(status, op) {
|
|
5
|
+
if (status !== Status.OK) throw new Error(`vui-core ${op} failed with status ${status}`);
|
|
6
|
+
}
|
|
7
|
+
function wrapCode(mode) {
|
|
8
|
+
switch (mode) {
|
|
9
|
+
case "nowrap": return NativeTextWrap.None;
|
|
10
|
+
case "char": return NativeTextWrap.Char;
|
|
11
|
+
case "word": return NativeTextWrap.Word;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
var TextBufferView = class {
|
|
15
|
+
#lib = loadNativeLib();
|
|
16
|
+
#ptr;
|
|
17
|
+
#measure = new Uint32Array(2);
|
|
18
|
+
constructor(buffer, width = 1, mode = "word") {
|
|
19
|
+
const ptr = this.#lib.symbols.vui_textview_new(buffer.nativePtr);
|
|
20
|
+
if (ptr === null) throw new Error("vui-core: failed to allocate TextBufferView");
|
|
21
|
+
this.#ptr = ptr;
|
|
22
|
+
this.setWidth(width);
|
|
23
|
+
this.setWrap(mode);
|
|
24
|
+
}
|
|
25
|
+
get nativePtr() {
|
|
26
|
+
return this.#ptr;
|
|
27
|
+
}
|
|
28
|
+
setWidth(width) {
|
|
29
|
+
check(this.#lib.symbols.vui_textview_set_width(this.#ptr, Math.max(1, Math.floor(width))), "textview_set_width");
|
|
30
|
+
}
|
|
31
|
+
setWrap(mode) {
|
|
32
|
+
check(this.#lib.symbols.vui_textview_set_wrap(this.#ptr, wrapCode(mode)), "textview_set_wrap");
|
|
33
|
+
}
|
|
34
|
+
measure(width, mode = "word") {
|
|
35
|
+
check(this.#lib.symbols.vui_textview_measure(this.#ptr, Math.max(1, Math.floor(width)), wrapCode(mode), this.#measure), "textview_measure");
|
|
36
|
+
return {
|
|
37
|
+
lineCount: this.#measure[0],
|
|
38
|
+
maxWidth: this.#measure[1]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
free() {
|
|
42
|
+
if (this.#ptr !== null) {
|
|
43
|
+
this.#lib.symbols.vui_textview_free(this.#ptr);
|
|
44
|
+
this.#ptr = null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
export { TextBufferView, wrapCode };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TextRun } from "../node.js";
|
|
2
|
+
import { Pointer } from "bun:ffi";
|
|
3
|
+
|
|
4
|
+
//#region src/text/text-buffer.d.ts
|
|
5
|
+
declare class TextBuffer {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(text?: string);
|
|
8
|
+
get nativePtr(): Pointer;
|
|
9
|
+
setText(text: string): void;
|
|
10
|
+
setRuns(runs: TextRun[]): void;
|
|
11
|
+
lineCount(): number;
|
|
12
|
+
length(): number;
|
|
13
|
+
free(): void;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { TextBuffer };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Status } from "../native/ffi-symbols.js";
|
|
2
|
+
import { loadNativeLib } from "../native/load-native-lib.js";
|
|
3
|
+
import { packTextRuns } from "../node.js";
|
|
4
|
+
//#region src/text/text-buffer.ts
|
|
5
|
+
const encoder = new TextEncoder();
|
|
6
|
+
function check(status, op) {
|
|
7
|
+
if (status !== Status.OK) throw new Error(`vui-core ${op} failed with status ${status}`);
|
|
8
|
+
}
|
|
9
|
+
var TextBuffer = class {
|
|
10
|
+
#lib = loadNativeLib();
|
|
11
|
+
#ptr;
|
|
12
|
+
constructor(text = "") {
|
|
13
|
+
const ptr = this.#lib.symbols.vui_textbuf_new();
|
|
14
|
+
if (ptr === null) throw new Error("vui-core: failed to allocate TextBuffer");
|
|
15
|
+
this.#ptr = ptr;
|
|
16
|
+
if (text) this.setText(text);
|
|
17
|
+
}
|
|
18
|
+
get nativePtr() {
|
|
19
|
+
return this.#ptr;
|
|
20
|
+
}
|
|
21
|
+
setText(text) {
|
|
22
|
+
const bytes = encoder.encode(text);
|
|
23
|
+
check(this.#lib.symbols.vui_textbuf_set_text(this.#ptr, bytes, bytes.byteLength), "textbuf_set_text");
|
|
24
|
+
}
|
|
25
|
+
setRuns(runs) {
|
|
26
|
+
const { bytes, runBytes } = packTextRuns(runs);
|
|
27
|
+
check(this.#lib.symbols.vui_textbuf_set_runs(this.#ptr, runBytes, runs.length, bytes, bytes.byteLength), "textbuf_set_runs");
|
|
28
|
+
}
|
|
29
|
+
lineCount() {
|
|
30
|
+
return this.#lib.symbols.vui_textbuf_line_count(this.#ptr);
|
|
31
|
+
}
|
|
32
|
+
length() {
|
|
33
|
+
return this.#lib.symbols.vui_textbuf_length(this.#ptr);
|
|
34
|
+
}
|
|
35
|
+
free() {
|
|
36
|
+
if (this.#ptr !== null) {
|
|
37
|
+
this.#lib.symbols.vui_textbuf_free(this.#ptr);
|
|
38
|
+
this.#ptr = null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
export { TextBuffer };
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vui-rs/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Native terminal rendering engine for vui-rs — a Rust cell buffer (truecolor, unicode, borders, taffy layout, images) driven from Bun via FFI.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"bun",
|
|
7
|
+
"ffi",
|
|
8
|
+
"renderer",
|
|
9
|
+
"rust",
|
|
10
|
+
"terminal",
|
|
11
|
+
"tui",
|
|
12
|
+
"vui-rs"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/open-ai-sdk/vui-rs#readme",
|
|
15
|
+
"bugs": "https://github.com/open-ai-sdk/vui-rs/issues",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "evann <dacsang97@gmail.com>",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/open-ai-sdk/vui-rs.git",
|
|
21
|
+
"directory": "packages/core"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"module": "src/index.ts",
|
|
28
|
+
"types": "src/index.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": "./src/index.ts"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"module": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"import": "./dist/index.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsdown"
|
|
45
|
+
}
|
|
46
|
+
}
|